diff options
author | Ingo Molnar <mingo@elte.hu> | 2012-02-17 03:02:28 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2012-02-17 03:02:28 -0500 |
commit | d1e169da9e20efc0762da6ec160dd7740d0103f5 (patch) | |
tree | ea1ec5ae77b11dc180724a51c61ad5695b2dbaa7 | |
parent | f8d98f1095210da708a59f3a0b6fd267ad8f3f03 (diff) | |
parent | 808e122630d45a7f036d25582474d70548a87e2c (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Includes smaller fixes and improvements plus the exclude_{host,guest} feature
test and fallback to handle older kernels.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
33 files changed, 616 insertions, 416 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index ff9a66e0d4e4..a5766b4b0125 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -52,11 +52,11 @@ OPTIONS | |||
52 | 52 | ||
53 | -p:: | 53 | -p:: |
54 | --pid=:: | 54 | --pid=:: |
55 | Record events on existing process ID. | 55 | Record events on existing process ID (comma separated list). |
56 | 56 | ||
57 | -t:: | 57 | -t:: |
58 | --tid=:: | 58 | --tid=:: |
59 | Record events on existing thread ID. | 59 | Record events on existing thread ID (comma separated list). |
60 | 60 | ||
61 | -u:: | 61 | -u:: |
62 | --uid=:: | 62 | --uid=:: |
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 8966b9ab2014..2fa173b51970 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
@@ -35,11 +35,11 @@ OPTIONS | |||
35 | child tasks do not inherit counters | 35 | child tasks do not inherit counters |
36 | -p:: | 36 | -p:: |
37 | --pid=<pid>:: | 37 | --pid=<pid>:: |
38 | stat events on existing process id | 38 | stat events on existing process id (comma separated list) |
39 | 39 | ||
40 | -t:: | 40 | -t:: |
41 | --tid=<tid>:: | 41 | --tid=<tid>:: |
42 | stat events on existing thread id | 42 | stat events on existing thread id (comma separated list) |
43 | 43 | ||
44 | 44 | ||
45 | -a:: | 45 | -a:: |
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index ab1454ed450f..4a5680cb242e 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -72,11 +72,11 @@ Default is to monitor all CPUS. | |||
72 | 72 | ||
73 | -p <pid>:: | 73 | -p <pid>:: |
74 | --pid=<pid>:: | 74 | --pid=<pid>:: |
75 | Profile events on existing Process ID. | 75 | Profile events on existing Process ID (comma separated list). |
76 | 76 | ||
77 | -t <tid>:: | 77 | -t <tid>:: |
78 | --tid=<tid>:: | 78 | --tid=<tid>:: |
79 | Profile events on existing thread ID. | 79 | Profile events on existing thread ID (comma separated list). |
80 | 80 | ||
81 | -u:: | 81 | -u:: |
82 | --uid=:: | 82 | --uid=:: |
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 1078c5fadd5b..5476bc0a1eac 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST | |||
@@ -9,6 +9,7 @@ lib/rbtree.c | |||
9 | include/linux/swab.h | 9 | include/linux/swab.h |
10 | arch/*/include/asm/unistd*.h | 10 | arch/*/include/asm/unistd*.h |
11 | arch/*/lib/memcpy*.S | 11 | arch/*/lib/memcpy*.S |
12 | arch/*/lib/memset*.S | ||
12 | include/linux/poison.h | 13 | include/linux/poison.h |
13 | include/linux/magic.h | 14 | include/linux/magic.h |
14 | include/linux/hw_breakpoint.h | 15 | include/linux/hw_breakpoint.h |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 64df5de12ca8..e011b5060f92 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -183,7 +183,10 @@ SCRIPT_SH += perf-archive.sh | |||
183 | grep-libs = $(filter -l%,$(1)) | 183 | grep-libs = $(filter -l%,$(1)) |
184 | strip-libs = $(filter-out -l%,$(1)) | 184 | strip-libs = $(filter-out -l%,$(1)) |
185 | 185 | ||
186 | $(OUTPUT)python/perf.so: $(PYRF_OBJS) | 186 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) |
187 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py | ||
188 | |||
189 | $(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) | ||
187 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ | 190 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ |
188 | --quiet build_ext; \ | 191 | --quiet build_ext; \ |
189 | mkdir -p $(OUTPUT)python && \ | 192 | mkdir -p $(OUTPUT)python && \ |
@@ -256,6 +259,7 @@ LIB_H += util/callchain.h | |||
256 | LIB_H += util/build-id.h | 259 | LIB_H += util/build-id.h |
257 | LIB_H += util/debug.h | 260 | LIB_H += util/debug.h |
258 | LIB_H += util/debugfs.h | 261 | LIB_H += util/debugfs.h |
262 | LIB_H += util/sysfs.h | ||
259 | LIB_H += util/event.h | 263 | LIB_H += util/event.h |
260 | LIB_H += util/evsel.h | 264 | LIB_H += util/evsel.h |
261 | LIB_H += util/evlist.h | 265 | LIB_H += util/evlist.h |
@@ -302,6 +306,7 @@ LIB_OBJS += $(OUTPUT)util/build-id.o | |||
302 | LIB_OBJS += $(OUTPUT)util/config.o | 306 | LIB_OBJS += $(OUTPUT)util/config.o |
303 | LIB_OBJS += $(OUTPUT)util/ctype.o | 307 | LIB_OBJS += $(OUTPUT)util/ctype.o |
304 | LIB_OBJS += $(OUTPUT)util/debugfs.o | 308 | LIB_OBJS += $(OUTPUT)util/debugfs.o |
309 | LIB_OBJS += $(OUTPUT)util/sysfs.o | ||
305 | LIB_OBJS += $(OUTPUT)util/environment.o | 310 | LIB_OBJS += $(OUTPUT)util/environment.o |
306 | LIB_OBJS += $(OUTPUT)util/event.o | 311 | LIB_OBJS += $(OUTPUT)util/event.o |
307 | LIB_OBJS += $(OUTPUT)util/evlist.o | 312 | LIB_OBJS += $(OUTPUT)util/evlist.o |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f8d9a545dd6e..75d230fef202 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -205,8 +205,11 @@ static void perf_record__open(struct perf_record *rec) | |||
205 | 205 | ||
206 | if (opts->group && pos != first) | 206 | if (opts->group && pos != first) |
207 | group_fd = first->fd; | 207 | group_fd = first->fd; |
208 | fallback_missing_features: | ||
209 | if (opts->exclude_guest_missing) | ||
210 | attr->exclude_guest = attr->exclude_host = 0; | ||
208 | retry_sample_id: | 211 | retry_sample_id: |
209 | attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; | 212 | attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; |
210 | try_again: | 213 | try_again: |
211 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads, | 214 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads, |
212 | opts->group, group_fd) < 0) { | 215 | opts->group, group_fd) < 0) { |
@@ -218,15 +221,23 @@ try_again: | |||
218 | } else if (err == ENODEV && opts->cpu_list) { | 221 | } else if (err == ENODEV && opts->cpu_list) { |
219 | die("No such device - did you specify" | 222 | die("No such device - did you specify" |
220 | " an out-of-range profile CPU?\n"); | 223 | " an out-of-range profile CPU?\n"); |
221 | } else if (err == EINVAL && opts->sample_id_all_avail) { | 224 | } else if (err == EINVAL) { |
222 | /* | 225 | if (!opts->exclude_guest_missing && |
223 | * Old kernel, no attr->sample_id_type_all field | 226 | (attr->exclude_guest || attr->exclude_host)) { |
224 | */ | 227 | pr_debug("Old kernel, cannot exclude " |
225 | opts->sample_id_all_avail = false; | 228 | "guest or host samples.\n"); |
226 | if (!opts->sample_time && !opts->raw_samples && !time_needed) | 229 | opts->exclude_guest_missing = true; |
227 | attr->sample_type &= ~PERF_SAMPLE_TIME; | 230 | goto fallback_missing_features; |
228 | 231 | } else if (!opts->sample_id_all_missing) { | |
229 | goto retry_sample_id; | 232 | /* |
233 | * Old kernel, no attr->sample_id_type_all field | ||
234 | */ | ||
235 | opts->sample_id_all_missing = true; | ||
236 | if (!opts->sample_time && !opts->raw_samples && !time_needed) | ||
237 | attr->sample_type &= ~PERF_SAMPLE_TIME; | ||
238 | |||
239 | goto retry_sample_id; | ||
240 | } | ||
230 | } | 241 | } |
231 | 242 | ||
232 | /* | 243 | /* |
@@ -494,9 +505,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
494 | return err; | 505 | return err; |
495 | } | 506 | } |
496 | 507 | ||
497 | if (!!rec->no_buildid | 508 | if (!rec->no_buildid |
498 | && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { | 509 | && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { |
499 | pr_err("Couldn't generating buildids. " | 510 | pr_err("Couldn't generate buildids. " |
500 | "Use --no-buildid to profile anyway.\n"); | 511 | "Use --no-buildid to profile anyway.\n"); |
501 | return -1; | 512 | return -1; |
502 | } | 513 | } |
@@ -645,13 +656,10 @@ static const char * const record_usage[] = { | |||
645 | */ | 656 | */ |
646 | static struct perf_record record = { | 657 | static struct perf_record record = { |
647 | .opts = { | 658 | .opts = { |
648 | .target_pid = -1, | ||
649 | .target_tid = -1, | ||
650 | .mmap_pages = UINT_MAX, | 659 | .mmap_pages = UINT_MAX, |
651 | .user_freq = UINT_MAX, | 660 | .user_freq = UINT_MAX, |
652 | .user_interval = ULLONG_MAX, | 661 | .user_interval = ULLONG_MAX, |
653 | .freq = 1000, | 662 | .freq = 1000, |
654 | .sample_id_all_avail = true, | ||
655 | }, | 663 | }, |
656 | .write_mode = WRITE_FORCE, | 664 | .write_mode = WRITE_FORCE, |
657 | .file_new = true, | 665 | .file_new = true, |
@@ -670,9 +678,9 @@ const struct option record_options[] = { | |||
670 | parse_events_option), | 678 | parse_events_option), |
671 | OPT_CALLBACK(0, "filter", &record.evlist, "filter", | 679 | OPT_CALLBACK(0, "filter", &record.evlist, "filter", |
672 | "event filter", parse_filter), | 680 | "event filter", parse_filter), |
673 | OPT_INTEGER('p', "pid", &record.opts.target_pid, | 681 | OPT_STRING('p', "pid", &record.opts.target_pid, "pid", |
674 | "record events on existing process id"), | 682 | "record events on existing process id"), |
675 | OPT_INTEGER('t', "tid", &record.opts.target_tid, | 683 | OPT_STRING('t', "tid", &record.opts.target_tid, "tid", |
676 | "record events on existing thread id"), | 684 | "record events on existing thread id"), |
677 | OPT_INTEGER('r', "realtime", &record.realtime_prio, | 685 | OPT_INTEGER('r', "realtime", &record.realtime_prio, |
678 | "collect data with this RT SCHED_FIFO priority"), | 686 | "collect data with this RT SCHED_FIFO priority"), |
@@ -739,7 +747,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
739 | 747 | ||
740 | argc = parse_options(argc, argv, record_options, record_usage, | 748 | argc = parse_options(argc, argv, record_options, record_usage, |
741 | PARSE_OPT_STOP_AT_NON_OPTION); | 749 | PARSE_OPT_STOP_AT_NON_OPTION); |
742 | if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 && | 750 | if (!argc && !rec->opts.target_pid && !rec->opts.target_tid && |
743 | !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str) | 751 | !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str) |
744 | usage_with_options(record_usage, record_options); | 752 | usage_with_options(record_usage, record_options); |
745 | 753 | ||
@@ -785,7 +793,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
785 | if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1) | 793 | if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1) |
786 | goto out_free_fd; | 794 | goto out_free_fd; |
787 | 795 | ||
788 | if (rec->opts.target_pid != -1) | 796 | if (rec->opts.target_pid) |
789 | rec->opts.target_tid = rec->opts.target_pid; | 797 | rec->opts.target_tid = rec->opts.target_pid; |
790 | 798 | ||
791 | if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid, | 799 | if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid, |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index d14b37ad7638..ea40e4e8b227 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -182,8 +182,8 @@ static int run_count = 1; | |||
182 | static bool no_inherit = false; | 182 | static bool no_inherit = false; |
183 | static bool scale = true; | 183 | static bool scale = true; |
184 | static bool no_aggr = false; | 184 | static bool no_aggr = false; |
185 | static pid_t target_pid = -1; | 185 | static const char *target_pid; |
186 | static pid_t target_tid = -1; | 186 | static const char *target_tid; |
187 | static pid_t child_pid = -1; | 187 | static pid_t child_pid = -1; |
188 | static bool null_run = false; | 188 | static bool null_run = false; |
189 | static int detailed_run = 0; | 189 | static int detailed_run = 0; |
@@ -296,7 +296,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel, | |||
296 | if (system_wide) | 296 | if (system_wide) |
297 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, | 297 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, |
298 | group, group_fd); | 298 | group, group_fd); |
299 | if (target_pid == -1 && target_tid == -1) { | 299 | if (!target_pid && !target_tid) { |
300 | attr->disabled = 1; | 300 | attr->disabled = 1; |
301 | attr->enable_on_exec = 1; | 301 | attr->enable_on_exec = 1; |
302 | } | 302 | } |
@@ -446,7 +446,7 @@ static int run_perf_stat(int argc __used, const char **argv) | |||
446 | exit(-1); | 446 | exit(-1); |
447 | } | 447 | } |
448 | 448 | ||
449 | if (target_tid == -1 && target_pid == -1 && !system_wide) | 449 | if (!target_tid && !target_pid && !system_wide) |
450 | evsel_list->threads->map[0] = child_pid; | 450 | evsel_list->threads->map[0] = child_pid; |
451 | 451 | ||
452 | /* | 452 | /* |
@@ -968,14 +968,14 @@ static void print_stat(int argc, const char **argv) | |||
968 | if (!csv_output) { | 968 | if (!csv_output) { |
969 | fprintf(output, "\n"); | 969 | fprintf(output, "\n"); |
970 | fprintf(output, " Performance counter stats for "); | 970 | fprintf(output, " Performance counter stats for "); |
971 | if(target_pid == -1 && target_tid == -1) { | 971 | if (!target_pid && !target_tid) { |
972 | fprintf(output, "\'%s", argv[0]); | 972 | fprintf(output, "\'%s", argv[0]); |
973 | for (i = 1; i < argc; i++) | 973 | for (i = 1; i < argc; i++) |
974 | fprintf(output, " %s", argv[i]); | 974 | fprintf(output, " %s", argv[i]); |
975 | } else if (target_pid != -1) | 975 | } else if (target_pid) |
976 | fprintf(output, "process id \'%d", target_pid); | 976 | fprintf(output, "process id \'%s", target_pid); |
977 | else | 977 | else |
978 | fprintf(output, "thread id \'%d", target_tid); | 978 | fprintf(output, "thread id \'%s", target_tid); |
979 | 979 | ||
980 | fprintf(output, "\'"); | 980 | fprintf(output, "\'"); |
981 | if (run_count > 1) | 981 | if (run_count > 1) |
@@ -1049,10 +1049,10 @@ static const struct option options[] = { | |||
1049 | "event filter", parse_filter), | 1049 | "event filter", parse_filter), |
1050 | OPT_BOOLEAN('i', "no-inherit", &no_inherit, | 1050 | OPT_BOOLEAN('i', "no-inherit", &no_inherit, |
1051 | "child tasks do not inherit counters"), | 1051 | "child tasks do not inherit counters"), |
1052 | OPT_INTEGER('p', "pid", &target_pid, | 1052 | OPT_STRING('p', "pid", &target_pid, "pid", |
1053 | "stat events on existing process id"), | 1053 | "stat events on existing process id"), |
1054 | OPT_INTEGER('t', "tid", &target_tid, | 1054 | OPT_STRING('t', "tid", &target_tid, "tid", |
1055 | "stat events on existing thread id"), | 1055 | "stat events on existing thread id"), |
1056 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 1056 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
1057 | "system-wide collection from all CPUs"), | 1057 | "system-wide collection from all CPUs"), |
1058 | OPT_BOOLEAN('g', "group", &group, | 1058 | OPT_BOOLEAN('g', "group", &group, |
@@ -1190,7 +1190,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
1190 | } else if (big_num_opt == 0) /* User passed --no-big-num */ | 1190 | } else if (big_num_opt == 0) /* User passed --no-big-num */ |
1191 | big_num = false; | 1191 | big_num = false; |
1192 | 1192 | ||
1193 | if (!argc && target_pid == -1 && target_tid == -1) | 1193 | if (!argc && !target_pid && !target_tid) |
1194 | usage_with_options(stat_usage, options); | 1194 | usage_with_options(stat_usage, options); |
1195 | if (run_count <= 0) | 1195 | if (run_count <= 0) |
1196 | usage_with_options(stat_usage, options); | 1196 | usage_with_options(stat_usage, options); |
@@ -1206,10 +1206,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
1206 | if (add_default_attributes()) | 1206 | if (add_default_attributes()) |
1207 | goto out; | 1207 | goto out; |
1208 | 1208 | ||
1209 | if (target_pid != -1) | 1209 | if (target_pid) |
1210 | target_tid = target_pid; | 1210 | target_tid = target_pid; |
1211 | 1211 | ||
1212 | evsel_list->threads = thread_map__new(target_pid, target_tid, UINT_MAX); | 1212 | evsel_list->threads = thread_map__new_str(target_pid, |
1213 | target_tid, UINT_MAX); | ||
1213 | if (evsel_list->threads == NULL) { | 1214 | if (evsel_list->threads == NULL) { |
1214 | pr_err("Problems finding threads of monitor\n"); | 1215 | pr_err("Problems finding threads of monitor\n"); |
1215 | usage_with_options(stat_usage, options); | 1216 | usage_with_options(stat_usage, options); |
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 70c4eb2bdf72..3e087ce8daa6 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
@@ -1010,12 +1010,9 @@ realloc: | |||
1010 | static int test__PERF_RECORD(void) | 1010 | static int test__PERF_RECORD(void) |
1011 | { | 1011 | { |
1012 | struct perf_record_opts opts = { | 1012 | struct perf_record_opts opts = { |
1013 | .target_pid = -1, | ||
1014 | .target_tid = -1, | ||
1015 | .no_delay = true, | 1013 | .no_delay = true, |
1016 | .freq = 10, | 1014 | .freq = 10, |
1017 | .mmap_pages = 256, | 1015 | .mmap_pages = 256, |
1018 | .sample_id_all_avail = true, | ||
1019 | }; | 1016 | }; |
1020 | cpu_set_t *cpu_mask = NULL; | 1017 | cpu_set_t *cpu_mask = NULL; |
1021 | size_t cpu_mask_size = 0; | 1018 | size_t cpu_mask_size = 0; |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index d869b214ada2..e3c63aef8efc 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -677,6 +677,12 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
677 | return; | 677 | return; |
678 | } | 678 | } |
679 | 679 | ||
680 | if (!machine) { | ||
681 | pr_err("%u unprocessable samples recorded.", | ||
682 | top->session->hists.stats.nr_unprocessable_samples++); | ||
683 | return; | ||
684 | } | ||
685 | |||
680 | if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) | 686 | if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) |
681 | top->exact_samples++; | 687 | top->exact_samples++; |
682 | 688 | ||
@@ -866,8 +872,11 @@ static void perf_top__start_counters(struct perf_top *top) | |||
866 | attr->mmap = 1; | 872 | attr->mmap = 1; |
867 | attr->comm = 1; | 873 | attr->comm = 1; |
868 | attr->inherit = top->inherit; | 874 | attr->inherit = top->inherit; |
875 | fallback_missing_features: | ||
876 | if (top->exclude_guest_missing) | ||
877 | attr->exclude_guest = attr->exclude_host = 0; | ||
869 | retry_sample_id: | 878 | retry_sample_id: |
870 | attr->sample_id_all = top->sample_id_all_avail ? 1 : 0; | 879 | attr->sample_id_all = top->sample_id_all_missing ? 0 : 1; |
871 | try_again: | 880 | try_again: |
872 | if (perf_evsel__open(counter, top->evlist->cpus, | 881 | if (perf_evsel__open(counter, top->evlist->cpus, |
873 | top->evlist->threads, top->group, | 882 | top->evlist->threads, top->group, |
@@ -877,12 +886,20 @@ try_again: | |||
877 | if (err == EPERM || err == EACCES) { | 886 | if (err == EPERM || err == EACCES) { |
878 | ui__error_paranoid(); | 887 | ui__error_paranoid(); |
879 | goto out_err; | 888 | goto out_err; |
880 | } else if (err == EINVAL && top->sample_id_all_avail) { | 889 | } else if (err == EINVAL) { |
881 | /* | 890 | if (!top->exclude_guest_missing && |
882 | * Old kernel, no attr->sample_id_type_all field | 891 | (attr->exclude_guest || attr->exclude_host)) { |
883 | */ | 892 | pr_debug("Old kernel, cannot exclude " |
884 | top->sample_id_all_avail = false; | 893 | "guest or host samples.\n"); |
885 | goto retry_sample_id; | 894 | top->exclude_guest_missing = true; |
895 | goto fallback_missing_features; | ||
896 | } else if (!top->sample_id_all_missing) { | ||
897 | /* | ||
898 | * Old kernel, no attr->sample_id_type_all field | ||
899 | */ | ||
900 | top->sample_id_all_missing = true; | ||
901 | goto retry_sample_id; | ||
902 | } | ||
886 | } | 903 | } |
887 | /* | 904 | /* |
888 | * If it's cycles then fall back to hrtimer | 905 | * If it's cycles then fall back to hrtimer |
@@ -965,7 +982,7 @@ static int __cmd_top(struct perf_top *top) | |||
965 | if (ret) | 982 | if (ret) |
966 | goto out_delete; | 983 | goto out_delete; |
967 | 984 | ||
968 | if (top->target_tid != -1 || top->uid != UINT_MAX) | 985 | if (top->target_tid || top->uid != UINT_MAX) |
969 | perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, | 986 | perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, |
970 | perf_event__process, | 987 | perf_event__process, |
971 | &top->session->host_machine); | 988 | &top->session->host_machine); |
@@ -1103,11 +1120,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1103 | struct perf_top top = { | 1120 | struct perf_top top = { |
1104 | .count_filter = 5, | 1121 | .count_filter = 5, |
1105 | .delay_secs = 2, | 1122 | .delay_secs = 2, |
1106 | .target_pid = -1, | ||
1107 | .target_tid = -1, | ||
1108 | .uid = UINT_MAX, | 1123 | .uid = UINT_MAX, |
1109 | .freq = 1000, /* 1 KHz */ | 1124 | .freq = 1000, /* 1 KHz */ |
1110 | .sample_id_all_avail = true, | ||
1111 | .mmap_pages = 128, | 1125 | .mmap_pages = 128, |
1112 | .sym_pcnt_filter = 5, | 1126 | .sym_pcnt_filter = 5, |
1113 | }; | 1127 | }; |
@@ -1118,9 +1132,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1118 | parse_events_option), | 1132 | parse_events_option), |
1119 | OPT_INTEGER('c', "count", &top.default_interval, | 1133 | OPT_INTEGER('c', "count", &top.default_interval, |
1120 | "event period to sample"), | 1134 | "event period to sample"), |
1121 | OPT_INTEGER('p', "pid", &top.target_pid, | 1135 | OPT_STRING('p', "pid", &top.target_pid, "pid", |
1122 | "profile events on existing process id"), | 1136 | "profile events on existing process id"), |
1123 | OPT_INTEGER('t', "tid", &top.target_tid, | 1137 | OPT_STRING('t', "tid", &top.target_tid, "tid", |
1124 | "profile events on existing thread id"), | 1138 | "profile events on existing thread id"), |
1125 | OPT_BOOLEAN('a', "all-cpus", &top.system_wide, | 1139 | OPT_BOOLEAN('a', "all-cpus", &top.system_wide, |
1126 | "system-wide collection from all CPUs"), | 1140 | "system-wide collection from all CPUs"), |
@@ -1210,13 +1224,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1210 | goto out_delete_evlist; | 1224 | goto out_delete_evlist; |
1211 | 1225 | ||
1212 | /* CPU and PID are mutually exclusive */ | 1226 | /* CPU and PID are mutually exclusive */ |
1213 | if (top.target_tid > 0 && top.cpu_list) { | 1227 | if (top.target_tid && top.cpu_list) { |
1214 | printf("WARNING: PID switch overriding CPU\n"); | 1228 | printf("WARNING: PID switch overriding CPU\n"); |
1215 | sleep(1); | 1229 | sleep(1); |
1216 | top.cpu_list = NULL; | 1230 | top.cpu_list = NULL; |
1217 | } | 1231 | } |
1218 | 1232 | ||
1219 | if (top.target_pid != -1) | 1233 | if (top.target_pid) |
1220 | top.target_tid = top.target_pid; | 1234 | top.target_tid = top.target_pid; |
1221 | 1235 | ||
1222 | if (perf_evlist__create_maps(top.evlist, top.target_pid, | 1236 | if (perf_evlist__create_maps(top.evlist, top.target_pid, |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 92af1688bae4..f0227e93665d 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -167,7 +167,6 @@ sys_perf_event_open(struct perf_event_attr *attr, | |||
167 | pid_t pid, int cpu, int group_fd, | 167 | pid_t pid, int cpu, int group_fd, |
168 | unsigned long flags) | 168 | unsigned long flags) |
169 | { | 169 | { |
170 | attr->size = sizeof(*attr); | ||
171 | return syscall(__NR_perf_event_open, attr, pid, cpu, | 170 | return syscall(__NR_perf_event_open, attr, pid, cpu, |
172 | group_fd, flags); | 171 | group_fd, flags); |
173 | } | 172 | } |
@@ -186,8 +185,8 @@ extern const char perf_version_string[]; | |||
186 | void pthread__unblock_sigwinch(void); | 185 | void pthread__unblock_sigwinch(void); |
187 | 186 | ||
188 | struct perf_record_opts { | 187 | struct perf_record_opts { |
189 | pid_t target_pid; | 188 | const char *target_pid; |
190 | pid_t target_tid; | 189 | const char *target_tid; |
191 | uid_t uid; | 190 | uid_t uid; |
192 | bool call_graph; | 191 | bool call_graph; |
193 | bool group; | 192 | bool group; |
@@ -199,7 +198,8 @@ struct perf_record_opts { | |||
199 | bool raw_samples; | 198 | bool raw_samples; |
200 | bool sample_address; | 199 | bool sample_address; |
201 | bool sample_time; | 200 | bool sample_time; |
202 | bool sample_id_all_avail; | 201 | bool sample_id_all_missing; |
202 | bool exclude_guest_missing; | ||
203 | bool system_wide; | 203 | bool system_wide; |
204 | bool period; | 204 | bool period; |
205 | unsigned int freq; | 205 | unsigned int freq; |
diff --git a/tools/perf/util/bitmap.c b/tools/perf/util/bitmap.c index 5e230acae1e9..0a1adc1111fd 100644 --- a/tools/perf/util/bitmap.c +++ b/tools/perf/util/bitmap.c | |||
@@ -19,3 +19,13 @@ int __bitmap_weight(const unsigned long *bitmap, int bits) | |||
19 | 19 | ||
20 | return w; | 20 | return w; |
21 | } | 21 | } |
22 | |||
23 | void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, | ||
24 | const unsigned long *bitmap2, int bits) | ||
25 | { | ||
26 | int k; | ||
27 | int nr = BITS_TO_LONGS(bits); | ||
28 | |||
29 | for (k = 0; k < nr; k++) | ||
30 | dst[k] = bitmap1[k] | bitmap2[k]; | ||
31 | } | ||
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c index 35073621e5de..aada3ac5e891 100644 --- a/tools/perf/util/ctype.c +++ b/tools/perf/util/ctype.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * No surprises, and works with signed and unsigned chars. | 4 | * No surprises, and works with signed and unsigned chars. |
5 | */ | 5 | */ |
6 | #include "cache.h" | 6 | #include "util.h" |
7 | 7 | ||
8 | enum { | 8 | enum { |
9 | S = GIT_SPACE, | 9 | S = GIT_SPACE, |
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c index ffc35e748e89..dd8b19319c03 100644 --- a/tools/perf/util/debugfs.c +++ b/tools/perf/util/debugfs.c | |||
@@ -15,32 +15,6 @@ static const char *debugfs_known_mountpoints[] = { | |||
15 | 0, | 15 | 0, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | /* use this to force a umount */ | ||
19 | void debugfs_force_cleanup(void) | ||
20 | { | ||
21 | debugfs_find_mountpoint(); | ||
22 | debugfs_premounted = 0; | ||
23 | debugfs_umount(); | ||
24 | } | ||
25 | |||
26 | /* construct a full path to a debugfs element */ | ||
27 | int debugfs_make_path(const char *element, char *buffer, int size) | ||
28 | { | ||
29 | int len; | ||
30 | |||
31 | if (strlen(debugfs_mountpoint) == 0) { | ||
32 | buffer[0] = '\0'; | ||
33 | return -1; | ||
34 | } | ||
35 | |||
36 | len = strlen(debugfs_mountpoint) + strlen(element) + 1; | ||
37 | if (len >= size) | ||
38 | return len+1; | ||
39 | |||
40 | snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element); | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static int debugfs_found; | 18 | static int debugfs_found; |
45 | 19 | ||
46 | /* find the path to the mounted debugfs */ | 20 | /* find the path to the mounted debugfs */ |
@@ -97,17 +71,6 @@ int debugfs_valid_mountpoint(const char *debugfs) | |||
97 | return 0; | 71 | return 0; |
98 | } | 72 | } |
99 | 73 | ||
100 | |||
101 | int debugfs_valid_entry(const char *path) | ||
102 | { | ||
103 | struct stat st; | ||
104 | |||
105 | if (stat(path, &st)) | ||
106 | return -errno; | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static void debugfs_set_tracing_events_path(const char *mountpoint) | 74 | static void debugfs_set_tracing_events_path(const char *mountpoint) |
112 | { | 75 | { |
113 | snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", | 76 | snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", |
@@ -149,107 +112,3 @@ void debugfs_set_path(const char *mountpoint) | |||
149 | snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint); | 112 | snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint); |
150 | debugfs_set_tracing_events_path(mountpoint); | 113 | debugfs_set_tracing_events_path(mountpoint); |
151 | } | 114 | } |
152 | |||
153 | /* umount the debugfs */ | ||
154 | |||
155 | int debugfs_umount(void) | ||
156 | { | ||
157 | char umountcmd[128]; | ||
158 | int ret; | ||
159 | |||
160 | /* if it was already mounted, leave it */ | ||
161 | if (debugfs_premounted) | ||
162 | return 0; | ||
163 | |||
164 | /* make sure it's a valid mount point */ | ||
165 | ret = debugfs_valid_mountpoint(debugfs_mountpoint); | ||
166 | if (ret) | ||
167 | return ret; | ||
168 | |||
169 | snprintf(umountcmd, sizeof(umountcmd), | ||
170 | "/bin/umount %s", debugfs_mountpoint); | ||
171 | return system(umountcmd); | ||
172 | } | ||
173 | |||
174 | int debugfs_write(const char *entry, const char *value) | ||
175 | { | ||
176 | char path[PATH_MAX + 1]; | ||
177 | int ret, count; | ||
178 | int fd; | ||
179 | |||
180 | /* construct the path */ | ||
181 | snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry); | ||
182 | |||
183 | /* verify that it exists */ | ||
184 | ret = debugfs_valid_entry(path); | ||
185 | if (ret) | ||
186 | return ret; | ||
187 | |||
188 | /* get how many chars we're going to write */ | ||
189 | count = strlen(value); | ||
190 | |||
191 | /* open the debugfs entry */ | ||
192 | fd = open(path, O_RDWR); | ||
193 | if (fd < 0) | ||
194 | return -errno; | ||
195 | |||
196 | while (count > 0) { | ||
197 | /* write it */ | ||
198 | ret = write(fd, value, count); | ||
199 | if (ret <= 0) { | ||
200 | if (ret == EAGAIN) | ||
201 | continue; | ||
202 | close(fd); | ||
203 | return -errno; | ||
204 | } | ||
205 | count -= ret; | ||
206 | } | ||
207 | |||
208 | /* close it */ | ||
209 | close(fd); | ||
210 | |||
211 | /* return success */ | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * read a debugfs entry | ||
217 | * returns the number of chars read or a negative errno | ||
218 | */ | ||
219 | int debugfs_read(const char *entry, char *buffer, size_t size) | ||
220 | { | ||
221 | char path[PATH_MAX + 1]; | ||
222 | int ret; | ||
223 | int fd; | ||
224 | |||
225 | /* construct the path */ | ||
226 | snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry); | ||
227 | |||
228 | /* verify that it exists */ | ||
229 | ret = debugfs_valid_entry(path); | ||
230 | if (ret) | ||
231 | return ret; | ||
232 | |||
233 | /* open the debugfs entry */ | ||
234 | fd = open(path, O_RDONLY); | ||
235 | if (fd < 0) | ||
236 | return -errno; | ||
237 | |||
238 | do { | ||
239 | /* read it */ | ||
240 | ret = read(fd, buffer, size); | ||
241 | if (ret == 0) { | ||
242 | close(fd); | ||
243 | return EOF; | ||
244 | } | ||
245 | } while (ret < 0 && errno == EAGAIN); | ||
246 | |||
247 | /* close it */ | ||
248 | close(fd); | ||
249 | |||
250 | /* make *sure* there's a null character at the end */ | ||
251 | buffer[ret] = '\0'; | ||
252 | |||
253 | /* return the number of chars read */ | ||
254 | return ret; | ||
255 | } | ||
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h index 4a878f735eb0..68f3e87ec57f 100644 --- a/tools/perf/util/debugfs.h +++ b/tools/perf/util/debugfs.h | |||
@@ -3,14 +3,8 @@ | |||
3 | 3 | ||
4 | const char *debugfs_find_mountpoint(void); | 4 | const char *debugfs_find_mountpoint(void); |
5 | int debugfs_valid_mountpoint(const char *debugfs); | 5 | int debugfs_valid_mountpoint(const char *debugfs); |
6 | int debugfs_valid_entry(const char *path); | ||
7 | char *debugfs_mount(const char *mountpoint); | 6 | char *debugfs_mount(const char *mountpoint); |
8 | int debugfs_umount(void); | ||
9 | void debugfs_set_path(const char *mountpoint); | 7 | void debugfs_set_path(const char *mountpoint); |
10 | int debugfs_write(const char *entry, const char *value); | ||
11 | int debugfs_read(const char *entry, char *buffer, size_t size); | ||
12 | void debugfs_force_cleanup(void); | ||
13 | int debugfs_make_path(const char *element, char *buffer, int size); | ||
14 | 8 | ||
15 | extern char debugfs_mountpoint[]; | 9 | extern char debugfs_mountpoint[]; |
16 | extern char tracing_events_path[]; | 10 | extern char tracing_events_path[]; |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index a57a8cfc5d90..5c61dc57d7c7 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -593,15 +593,15 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | |||
593 | return perf_evlist__mmap_per_cpu(evlist, prot, mask); | 593 | return perf_evlist__mmap_per_cpu(evlist, prot, mask); |
594 | } | 594 | } |
595 | 595 | ||
596 | int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, | 596 | int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, |
597 | pid_t target_tid, uid_t uid, const char *cpu_list) | 597 | const char *target_tid, uid_t uid, const char *cpu_list) |
598 | { | 598 | { |
599 | evlist->threads = thread_map__new(target_pid, target_tid, uid); | 599 | evlist->threads = thread_map__new_str(target_pid, target_tid, uid); |
600 | 600 | ||
601 | if (evlist->threads == NULL) | 601 | if (evlist->threads == NULL) |
602 | return -1; | 602 | return -1; |
603 | 603 | ||
604 | if (uid != UINT_MAX || (cpu_list == NULL && target_tid != -1)) | 604 | if (uid != UINT_MAX || (cpu_list == NULL && target_tid)) |
605 | evlist->cpus = cpu_map__dummy_new(); | 605 | evlist->cpus = cpu_map__dummy_new(); |
606 | else | 606 | else |
607 | evlist->cpus = cpu_map__new(cpu_list); | 607 | evlist->cpus = cpu_map__new(cpu_list); |
@@ -820,7 +820,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, | |||
820 | exit(-1); | 820 | exit(-1); |
821 | } | 821 | } |
822 | 822 | ||
823 | if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1) | 823 | if (!opts->system_wide && !opts->target_tid && !opts->target_pid) |
824 | evlist->threads->map[0] = evlist->workload.pid; | 824 | evlist->threads->map[0] = evlist->workload.pid; |
825 | 825 | ||
826 | close(child_ready_pipe[1]); | 826 | close(child_ready_pipe[1]); |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 1b4282be8fe7..21f1c9e57f13 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -106,8 +106,8 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist, | |||
106 | evlist->threads = threads; | 106 | evlist->threads = threads; |
107 | } | 107 | } |
108 | 108 | ||
109 | int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, | 109 | int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, |
110 | pid_t tid, uid_t uid, const char *cpu_list); | 110 | const char *tid, uid_t uid, const char *cpu_list); |
111 | void perf_evlist__delete_maps(struct perf_evlist *evlist); | 111 | void perf_evlist__delete_maps(struct perf_evlist *evlist); |
112 | int perf_evlist__set_filters(struct perf_evlist *evlist); | 112 | int perf_evlist__set_filters(struct perf_evlist *evlist); |
113 | 113 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 9a11f9edac12..302d49a9f985 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -68,7 +68,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts) | |||
68 | struct perf_event_attr *attr = &evsel->attr; | 68 | struct perf_event_attr *attr = &evsel->attr; |
69 | int track = !evsel->idx; /* only the first counter needs these */ | 69 | int track = !evsel->idx; /* only the first counter needs these */ |
70 | 70 | ||
71 | attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; | 71 | attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; |
72 | attr->inherit = !opts->no_inherit; | 72 | attr->inherit = !opts->no_inherit; |
73 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 73 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
74 | PERF_FORMAT_TOTAL_TIME_RUNNING | | 74 | PERF_FORMAT_TOTAL_TIME_RUNNING | |
@@ -111,7 +111,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts) | |||
111 | if (opts->period) | 111 | if (opts->period) |
112 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 112 | attr->sample_type |= PERF_SAMPLE_PERIOD; |
113 | 113 | ||
114 | if (opts->sample_id_all_avail && | 114 | if (!opts->sample_id_all_missing && |
115 | (opts->sample_time || opts->system_wide || | 115 | (opts->sample_time || opts->system_wide || |
116 | !opts->no_inherit || opts->cpu_list)) | 116 | !opts->no_inherit || opts->cpu_list)) |
117 | attr->sample_type |= PERF_SAMPLE_TIME; | 117 | attr->sample_type |= PERF_SAMPLE_TIME; |
@@ -130,7 +130,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts) | |||
130 | attr->mmap = track; | 130 | attr->mmap = track; |
131 | attr->comm = track; | 131 | attr->comm = track; |
132 | 132 | ||
133 | if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) { | 133 | if (!opts->target_pid && !opts->target_tid && !opts->system_wide) { |
134 | attr->disabled = 1; | 134 | attr->disabled = 1; |
135 | attr->enable_on_exec = 1; | 135 | attr->enable_on_exec = 1; |
136 | } | 136 | } |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ecd7f4dd7eea..9f867d96c6a5 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -63,9 +63,20 @@ char *perf_header__find_event(u64 id) | |||
63 | return NULL; | 63 | return NULL; |
64 | } | 64 | } |
65 | 65 | ||
66 | static const char *__perf_magic = "PERFFILE"; | 66 | /* |
67 | * magic2 = "PERFILE2" | ||
68 | * must be a numerical value to let the endianness | ||
69 | * determine the memory layout. That way we are able | ||
70 | * to detect endianness when reading the perf.data file | ||
71 | * back. | ||
72 | * | ||
73 | * we check for legacy (PERFFILE) format. | ||
74 | */ | ||
75 | static const char *__perf_magic1 = "PERFFILE"; | ||
76 | static const u64 __perf_magic2 = 0x32454c4946524550ULL; | ||
77 | static const u64 __perf_magic2_sw = 0x50455246494c4532ULL; | ||
67 | 78 | ||
68 | #define PERF_MAGIC (*(u64 *)__perf_magic) | 79 | #define PERF_MAGIC __perf_magic2 |
69 | 80 | ||
70 | struct perf_file_attr { | 81 | struct perf_file_attr { |
71 | struct perf_event_attr attr; | 82 | struct perf_event_attr attr; |
@@ -1305,25 +1316,198 @@ static void print_cpuid(struct perf_header *ph, int fd, FILE *fp) | |||
1305 | free(str); | 1316 | free(str); |
1306 | } | 1317 | } |
1307 | 1318 | ||
1319 | static int __event_process_build_id(struct build_id_event *bev, | ||
1320 | char *filename, | ||
1321 | struct perf_session *session) | ||
1322 | { | ||
1323 | int err = -1; | ||
1324 | struct list_head *head; | ||
1325 | struct machine *machine; | ||
1326 | u16 misc; | ||
1327 | struct dso *dso; | ||
1328 | enum dso_kernel_type dso_type; | ||
1329 | |||
1330 | machine = perf_session__findnew_machine(session, bev->pid); | ||
1331 | if (!machine) | ||
1332 | goto out; | ||
1333 | |||
1334 | misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
1335 | |||
1336 | switch (misc) { | ||
1337 | case PERF_RECORD_MISC_KERNEL: | ||
1338 | dso_type = DSO_TYPE_KERNEL; | ||
1339 | head = &machine->kernel_dsos; | ||
1340 | break; | ||
1341 | case PERF_RECORD_MISC_GUEST_KERNEL: | ||
1342 | dso_type = DSO_TYPE_GUEST_KERNEL; | ||
1343 | head = &machine->kernel_dsos; | ||
1344 | break; | ||
1345 | case PERF_RECORD_MISC_USER: | ||
1346 | case PERF_RECORD_MISC_GUEST_USER: | ||
1347 | dso_type = DSO_TYPE_USER; | ||
1348 | head = &machine->user_dsos; | ||
1349 | break; | ||
1350 | default: | ||
1351 | goto out; | ||
1352 | } | ||
1353 | |||
1354 | dso = __dsos__findnew(head, filename); | ||
1355 | if (dso != NULL) { | ||
1356 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
1357 | |||
1358 | dso__set_build_id(dso, &bev->build_id); | ||
1359 | |||
1360 | if (filename[0] == '[') | ||
1361 | dso->kernel = dso_type; | ||
1362 | |||
1363 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), | ||
1364 | sbuild_id); | ||
1365 | pr_debug("build id event received for %s: %s\n", | ||
1366 | dso->long_name, sbuild_id); | ||
1367 | } | ||
1368 | |||
1369 | err = 0; | ||
1370 | out: | ||
1371 | return err; | ||
1372 | } | ||
1373 | |||
1374 | static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, | ||
1375 | int input, u64 offset, u64 size) | ||
1376 | { | ||
1377 | struct perf_session *session = container_of(header, struct perf_session, header); | ||
1378 | struct { | ||
1379 | struct perf_event_header header; | ||
1380 | u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; | ||
1381 | char filename[0]; | ||
1382 | } old_bev; | ||
1383 | struct build_id_event bev; | ||
1384 | char filename[PATH_MAX]; | ||
1385 | u64 limit = offset + size; | ||
1386 | |||
1387 | while (offset < limit) { | ||
1388 | ssize_t len; | ||
1389 | |||
1390 | if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) | ||
1391 | return -1; | ||
1392 | |||
1393 | if (header->needs_swap) | ||
1394 | perf_event_header__bswap(&old_bev.header); | ||
1395 | |||
1396 | len = old_bev.header.size - sizeof(old_bev); | ||
1397 | if (read(input, filename, len) != len) | ||
1398 | return -1; | ||
1399 | |||
1400 | bev.header = old_bev.header; | ||
1401 | |||
1402 | /* | ||
1403 | * As the pid is the missing value, we need to fill | ||
1404 | * it properly. The header.misc value give us nice hint. | ||
1405 | */ | ||
1406 | bev.pid = HOST_KERNEL_ID; | ||
1407 | if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER || | ||
1408 | bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL) | ||
1409 | bev.pid = DEFAULT_GUEST_KERNEL_ID; | ||
1410 | |||
1411 | memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); | ||
1412 | __event_process_build_id(&bev, filename, session); | ||
1413 | |||
1414 | offset += bev.header.size; | ||
1415 | } | ||
1416 | |||
1417 | return 0; | ||
1418 | } | ||
1419 | |||
1420 | static int perf_header__read_build_ids(struct perf_header *header, | ||
1421 | int input, u64 offset, u64 size) | ||
1422 | { | ||
1423 | struct perf_session *session = container_of(header, struct perf_session, header); | ||
1424 | struct build_id_event bev; | ||
1425 | char filename[PATH_MAX]; | ||
1426 | u64 limit = offset + size, orig_offset = offset; | ||
1427 | int err = -1; | ||
1428 | |||
1429 | while (offset < limit) { | ||
1430 | ssize_t len; | ||
1431 | |||
1432 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | ||
1433 | goto out; | ||
1434 | |||
1435 | if (header->needs_swap) | ||
1436 | perf_event_header__bswap(&bev.header); | ||
1437 | |||
1438 | len = bev.header.size - sizeof(bev); | ||
1439 | if (read(input, filename, len) != len) | ||
1440 | goto out; | ||
1441 | /* | ||
1442 | * The a1645ce1 changeset: | ||
1443 | * | ||
1444 | * "perf: 'perf kvm' tool for monitoring guest performance from host" | ||
1445 | * | ||
1446 | * Added a field to struct build_id_event that broke the file | ||
1447 | * format. | ||
1448 | * | ||
1449 | * Since the kernel build-id is the first entry, process the | ||
1450 | * table using the old format if the well known | ||
1451 | * '[kernel.kallsyms]' string for the kernel build-id has the | ||
1452 | * first 4 characters chopped off (where the pid_t sits). | ||
1453 | */ | ||
1454 | if (memcmp(filename, "nel.kallsyms]", 13) == 0) { | ||
1455 | if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1) | ||
1456 | return -1; | ||
1457 | return perf_header__read_build_ids_abi_quirk(header, input, offset, size); | ||
1458 | } | ||
1459 | |||
1460 | __event_process_build_id(&bev, filename, session); | ||
1461 | |||
1462 | offset += bev.header.size; | ||
1463 | } | ||
1464 | err = 0; | ||
1465 | out: | ||
1466 | return err; | ||
1467 | } | ||
1468 | |||
1469 | static int process_trace_info(struct perf_file_section *section __unused, | ||
1470 | struct perf_header *ph __unused, | ||
1471 | int feat __unused, int fd) | ||
1472 | { | ||
1473 | trace_report(fd, false); | ||
1474 | return 0; | ||
1475 | } | ||
1476 | |||
1477 | static int process_build_id(struct perf_file_section *section, | ||
1478 | struct perf_header *ph, | ||
1479 | int feat __unused, int fd) | ||
1480 | { | ||
1481 | if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) | ||
1482 | pr_debug("Failed to read buildids, continuing...\n"); | ||
1483 | return 0; | ||
1484 | } | ||
1485 | |||
1308 | struct feature_ops { | 1486 | struct feature_ops { |
1309 | int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); | 1487 | int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); |
1310 | void (*print)(struct perf_header *h, int fd, FILE *fp); | 1488 | void (*print)(struct perf_header *h, int fd, FILE *fp); |
1489 | int (*process)(struct perf_file_section *section, | ||
1490 | struct perf_header *h, int feat, int fd); | ||
1311 | const char *name; | 1491 | const char *name; |
1312 | bool full_only; | 1492 | bool full_only; |
1313 | }; | 1493 | }; |
1314 | 1494 | ||
1315 | #define FEAT_OPA(n, func) \ | 1495 | #define FEAT_OPA(n, func) \ |
1316 | [n] = { .name = #n, .write = write_##func, .print = print_##func } | 1496 | [n] = { .name = #n, .write = write_##func, .print = print_##func } |
1497 | #define FEAT_OPP(n, func) \ | ||
1498 | [n] = { .name = #n, .write = write_##func, .print = print_##func, \ | ||
1499 | .process = process_##func } | ||
1317 | #define FEAT_OPF(n, func) \ | 1500 | #define FEAT_OPF(n, func) \ |
1318 | [n] = { .name = #n, .write = write_##func, .print = print_##func, .full_only = true } | 1501 | [n] = { .name = #n, .write = write_##func, .print = print_##func, \ |
1502 | .full_only = true } | ||
1319 | 1503 | ||
1320 | /* feature_ops not implemented: */ | 1504 | /* feature_ops not implemented: */ |
1321 | #define print_trace_info NULL | 1505 | #define print_trace_info NULL |
1322 | #define print_build_id NULL | 1506 | #define print_build_id NULL |
1323 | 1507 | ||
1324 | static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { | 1508 | static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { |
1325 | FEAT_OPA(HEADER_TRACE_INFO, trace_info), | 1509 | FEAT_OPP(HEADER_TRACE_INFO, trace_info), |
1326 | FEAT_OPA(HEADER_BUILD_ID, build_id), | 1510 | FEAT_OPP(HEADER_BUILD_ID, build_id), |
1327 | FEAT_OPA(HEADER_HOSTNAME, hostname), | 1511 | FEAT_OPA(HEADER_HOSTNAME, hostname), |
1328 | FEAT_OPA(HEADER_OSRELEASE, osrelease), | 1512 | FEAT_OPA(HEADER_OSRELEASE, osrelease), |
1329 | FEAT_OPA(HEADER_VERSION, version), | 1513 | FEAT_OPA(HEADER_VERSION, version), |
@@ -1620,24 +1804,59 @@ out_free: | |||
1620 | return err; | 1804 | return err; |
1621 | } | 1805 | } |
1622 | 1806 | ||
1807 | static int check_magic_endian(u64 *magic, struct perf_file_header *header, | ||
1808 | struct perf_header *ph) | ||
1809 | { | ||
1810 | int ret; | ||
1811 | |||
1812 | /* check for legacy format */ | ||
1813 | ret = memcmp(magic, __perf_magic1, sizeof(*magic)); | ||
1814 | if (ret == 0) { | ||
1815 | pr_debug("legacy perf.data format\n"); | ||
1816 | if (!header) | ||
1817 | return -1; | ||
1818 | |||
1819 | if (header->attr_size != sizeof(struct perf_file_attr)) { | ||
1820 | u64 attr_size = bswap_64(header->attr_size); | ||
1821 | |||
1822 | if (attr_size != sizeof(struct perf_file_attr)) | ||
1823 | return -1; | ||
1824 | |||
1825 | ph->needs_swap = true; | ||
1826 | } | ||
1827 | return 0; | ||
1828 | } | ||
1829 | |||
1830 | /* check magic number with same endianness */ | ||
1831 | if (*magic == __perf_magic2) | ||
1832 | return 0; | ||
1833 | |||
1834 | /* check magic number but opposite endianness */ | ||
1835 | if (*magic != __perf_magic2_sw) | ||
1836 | return -1; | ||
1837 | |||
1838 | ph->needs_swap = true; | ||
1839 | |||
1840 | return 0; | ||
1841 | } | ||
1842 | |||
1623 | int perf_file_header__read(struct perf_file_header *header, | 1843 | int perf_file_header__read(struct perf_file_header *header, |
1624 | struct perf_header *ph, int fd) | 1844 | struct perf_header *ph, int fd) |
1625 | { | 1845 | { |
1846 | int ret; | ||
1847 | |||
1626 | lseek(fd, 0, SEEK_SET); | 1848 | lseek(fd, 0, SEEK_SET); |
1627 | 1849 | ||
1628 | if (readn(fd, header, sizeof(*header)) <= 0 || | 1850 | ret = readn(fd, header, sizeof(*header)); |
1629 | memcmp(&header->magic, __perf_magic, sizeof(header->magic))) | 1851 | if (ret <= 0) |
1630 | return -1; | 1852 | return -1; |
1631 | 1853 | ||
1632 | if (header->attr_size != sizeof(struct perf_file_attr)) { | 1854 | if (check_magic_endian(&header->magic, header, ph) < 0) |
1633 | u64 attr_size = bswap_64(header->attr_size); | 1855 | return -1; |
1634 | |||
1635 | if (attr_size != sizeof(struct perf_file_attr)) | ||
1636 | return -1; | ||
1637 | 1856 | ||
1857 | if (ph->needs_swap) { | ||
1638 | mem_bswap_64(header, offsetof(struct perf_file_header, | 1858 | mem_bswap_64(header, offsetof(struct perf_file_header, |
1639 | adds_features)); | 1859 | adds_features)); |
1640 | ph->needs_swap = true; | ||
1641 | } | 1860 | } |
1642 | 1861 | ||
1643 | if (header->size != sizeof(*header)) { | 1862 | if (header->size != sizeof(*header)) { |
@@ -1689,156 +1908,6 @@ int perf_file_header__read(struct perf_file_header *header, | |||
1689 | return 0; | 1908 | return 0; |
1690 | } | 1909 | } |
1691 | 1910 | ||
1692 | static int __event_process_build_id(struct build_id_event *bev, | ||
1693 | char *filename, | ||
1694 | struct perf_session *session) | ||
1695 | { | ||
1696 | int err = -1; | ||
1697 | struct list_head *head; | ||
1698 | struct machine *machine; | ||
1699 | u16 misc; | ||
1700 | struct dso *dso; | ||
1701 | enum dso_kernel_type dso_type; | ||
1702 | |||
1703 | machine = perf_session__findnew_machine(session, bev->pid); | ||
1704 | if (!machine) | ||
1705 | goto out; | ||
1706 | |||
1707 | misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
1708 | |||
1709 | switch (misc) { | ||
1710 | case PERF_RECORD_MISC_KERNEL: | ||
1711 | dso_type = DSO_TYPE_KERNEL; | ||
1712 | head = &machine->kernel_dsos; | ||
1713 | break; | ||
1714 | case PERF_RECORD_MISC_GUEST_KERNEL: | ||
1715 | dso_type = DSO_TYPE_GUEST_KERNEL; | ||
1716 | head = &machine->kernel_dsos; | ||
1717 | break; | ||
1718 | case PERF_RECORD_MISC_USER: | ||
1719 | case PERF_RECORD_MISC_GUEST_USER: | ||
1720 | dso_type = DSO_TYPE_USER; | ||
1721 | head = &machine->user_dsos; | ||
1722 | break; | ||
1723 | default: | ||
1724 | goto out; | ||
1725 | } | ||
1726 | |||
1727 | dso = __dsos__findnew(head, filename); | ||
1728 | if (dso != NULL) { | ||
1729 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
1730 | |||
1731 | dso__set_build_id(dso, &bev->build_id); | ||
1732 | |||
1733 | if (filename[0] == '[') | ||
1734 | dso->kernel = dso_type; | ||
1735 | |||
1736 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), | ||
1737 | sbuild_id); | ||
1738 | pr_debug("build id event received for %s: %s\n", | ||
1739 | dso->long_name, sbuild_id); | ||
1740 | } | ||
1741 | |||
1742 | err = 0; | ||
1743 | out: | ||
1744 | return err; | ||
1745 | } | ||
1746 | |||
1747 | static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, | ||
1748 | int input, u64 offset, u64 size) | ||
1749 | { | ||
1750 | struct perf_session *session = container_of(header, struct perf_session, header); | ||
1751 | struct { | ||
1752 | struct perf_event_header header; | ||
1753 | u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; | ||
1754 | char filename[0]; | ||
1755 | } old_bev; | ||
1756 | struct build_id_event bev; | ||
1757 | char filename[PATH_MAX]; | ||
1758 | u64 limit = offset + size; | ||
1759 | |||
1760 | while (offset < limit) { | ||
1761 | ssize_t len; | ||
1762 | |||
1763 | if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) | ||
1764 | return -1; | ||
1765 | |||
1766 | if (header->needs_swap) | ||
1767 | perf_event_header__bswap(&old_bev.header); | ||
1768 | |||
1769 | len = old_bev.header.size - sizeof(old_bev); | ||
1770 | if (read(input, filename, len) != len) | ||
1771 | return -1; | ||
1772 | |||
1773 | bev.header = old_bev.header; | ||
1774 | |||
1775 | /* | ||
1776 | * As the pid is the missing value, we need to fill | ||
1777 | * it properly. The header.misc value give us nice hint. | ||
1778 | */ | ||
1779 | bev.pid = HOST_KERNEL_ID; | ||
1780 | if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER || | ||
1781 | bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL) | ||
1782 | bev.pid = DEFAULT_GUEST_KERNEL_ID; | ||
1783 | |||
1784 | memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); | ||
1785 | __event_process_build_id(&bev, filename, session); | ||
1786 | |||
1787 | offset += bev.header.size; | ||
1788 | } | ||
1789 | |||
1790 | return 0; | ||
1791 | } | ||
1792 | |||
1793 | static int perf_header__read_build_ids(struct perf_header *header, | ||
1794 | int input, u64 offset, u64 size) | ||
1795 | { | ||
1796 | struct perf_session *session = container_of(header, struct perf_session, header); | ||
1797 | struct build_id_event bev; | ||
1798 | char filename[PATH_MAX]; | ||
1799 | u64 limit = offset + size, orig_offset = offset; | ||
1800 | int err = -1; | ||
1801 | |||
1802 | while (offset < limit) { | ||
1803 | ssize_t len; | ||
1804 | |||
1805 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | ||
1806 | goto out; | ||
1807 | |||
1808 | if (header->needs_swap) | ||
1809 | perf_event_header__bswap(&bev.header); | ||
1810 | |||
1811 | len = bev.header.size - sizeof(bev); | ||
1812 | if (read(input, filename, len) != len) | ||
1813 | goto out; | ||
1814 | /* | ||
1815 | * The a1645ce1 changeset: | ||
1816 | * | ||
1817 | * "perf: 'perf kvm' tool for monitoring guest performance from host" | ||
1818 | * | ||
1819 | * Added a field to struct build_id_event that broke the file | ||
1820 | * format. | ||
1821 | * | ||
1822 | * Since the kernel build-id is the first entry, process the | ||
1823 | * table using the old format if the well known | ||
1824 | * '[kernel.kallsyms]' string for the kernel build-id has the | ||
1825 | * first 4 characters chopped off (where the pid_t sits). | ||
1826 | */ | ||
1827 | if (memcmp(filename, "nel.kallsyms]", 13) == 0) { | ||
1828 | if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1) | ||
1829 | return -1; | ||
1830 | return perf_header__read_build_ids_abi_quirk(header, input, offset, size); | ||
1831 | } | ||
1832 | |||
1833 | __event_process_build_id(&bev, filename, session); | ||
1834 | |||
1835 | offset += bev.header.size; | ||
1836 | } | ||
1837 | err = 0; | ||
1838 | out: | ||
1839 | return err; | ||
1840 | } | ||
1841 | |||
1842 | static int perf_file_section__process(struct perf_file_section *section, | 1911 | static int perf_file_section__process(struct perf_file_section *section, |
1843 | struct perf_header *ph, | 1912 | struct perf_header *ph, |
1844 | int feat, int fd, void *data __used) | 1913 | int feat, int fd, void *data __used) |
@@ -1854,27 +1923,23 @@ static int perf_file_section__process(struct perf_file_section *section, | |||
1854 | return 0; | 1923 | return 0; |
1855 | } | 1924 | } |
1856 | 1925 | ||
1857 | switch (feat) { | 1926 | if (!feat_ops[feat].process) |
1858 | case HEADER_TRACE_INFO: | 1927 | return 0; |
1859 | trace_report(fd, false); | ||
1860 | break; | ||
1861 | case HEADER_BUILD_ID: | ||
1862 | if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) | ||
1863 | pr_debug("Failed to read buildids, continuing...\n"); | ||
1864 | break; | ||
1865 | default: | ||
1866 | break; | ||
1867 | } | ||
1868 | 1928 | ||
1869 | return 0; | 1929 | return feat_ops[feat].process(section, ph, feat, fd); |
1870 | } | 1930 | } |
1871 | 1931 | ||
1872 | static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, | 1932 | static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, |
1873 | struct perf_header *ph, int fd, | 1933 | struct perf_header *ph, int fd, |
1874 | bool repipe) | 1934 | bool repipe) |
1875 | { | 1935 | { |
1876 | if (readn(fd, header, sizeof(*header)) <= 0 || | 1936 | int ret; |
1877 | memcmp(&header->magic, __perf_magic, sizeof(header->magic))) | 1937 | |
1938 | ret = readn(fd, header, sizeof(*header)); | ||
1939 | if (ret <= 0) | ||
1940 | return -1; | ||
1941 | |||
1942 | if (check_magic_endian(&header->magic, NULL, ph) < 0) | ||
1878 | return -1; | 1943 | return -1; |
1879 | 1944 | ||
1880 | if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0) | 1945 | if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0) |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 0d486135d10f..48e5acd1e862 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -32,6 +32,7 @@ struct events_stats { | |||
32 | u32 nr_unknown_events; | 32 | u32 nr_unknown_events; |
33 | u32 nr_invalid_chains; | 33 | u32 nr_invalid_chains; |
34 | u32 nr_unknown_id; | 34 | u32 nr_unknown_id; |
35 | u32 nr_unprocessable_samples; | ||
35 | }; | 36 | }; |
36 | 37 | ||
37 | enum hist_column { | 38 | enum hist_column { |
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h index eda4416efa0a..bb162e40c76c 100644 --- a/tools/perf/util/include/linux/bitmap.h +++ b/tools/perf/util/include/linux/bitmap.h | |||
@@ -5,6 +5,8 @@ | |||
5 | #include <linux/bitops.h> | 5 | #include <linux/bitops.h> |
6 | 6 | ||
7 | int __bitmap_weight(const unsigned long *bitmap, int bits); | 7 | int __bitmap_weight(const unsigned long *bitmap, int bits); |
8 | void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, | ||
9 | const unsigned long *bitmap2, int bits); | ||
8 | 10 | ||
9 | #define BITMAP_LAST_WORD_MASK(nbits) \ | 11 | #define BITMAP_LAST_WORD_MASK(nbits) \ |
10 | ( \ | 12 | ( \ |
@@ -32,4 +34,13 @@ static inline int bitmap_weight(const unsigned long *src, int nbits) | |||
32 | return __bitmap_weight(src, nbits); | 34 | return __bitmap_weight(src, nbits); |
33 | } | 35 | } |
34 | 36 | ||
37 | static inline void bitmap_or(unsigned long *dst, const unsigned long *src1, | ||
38 | const unsigned long *src2, int nbits) | ||
39 | { | ||
40 | if (small_const_nbits(nbits)) | ||
41 | *dst = *src1 | *src2; | ||
42 | else | ||
43 | __bitmap_or(dst, src1, src2, nbits); | ||
44 | } | ||
45 | |||
35 | #endif /* _PERF_BITOPS_H */ | 46 | #endif /* _PERF_BITOPS_H */ |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources new file mode 100644 index 000000000000..2884e67ee625 --- /dev/null +++ b/tools/perf/util/python-ext-sources | |||
@@ -0,0 +1,19 @@ | |||
1 | # | ||
2 | # List of files needed by perf python extention | ||
3 | # | ||
4 | # Each source file must be placed on its own line so that it can be | ||
5 | # processed by Makefile and util/setup.py accordingly. | ||
6 | # | ||
7 | |||
8 | util/python.c | ||
9 | util/ctype.c | ||
10 | util/evlist.c | ||
11 | util/evsel.c | ||
12 | util/cpumap.c | ||
13 | util/thread_map.c | ||
14 | util/util.c | ||
15 | util/xyarray.c | ||
16 | util/cgroup.c | ||
17 | util/debugfs.c | ||
18 | util/strlist.c | ||
19 | ../../lib/rbtree.c | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 552c1c50eea1..9f833cf9c6a9 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -796,6 +796,10 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
796 | ++session->hists.stats.nr_unknown_id; | 796 | ++session->hists.stats.nr_unknown_id; |
797 | return -1; | 797 | return -1; |
798 | } | 798 | } |
799 | if (machine == NULL) { | ||
800 | ++session->hists.stats.nr_unprocessable_samples; | ||
801 | return -1; | ||
802 | } | ||
799 | return tool->sample(tool, event, sample, evsel, machine); | 803 | return tool->sample(tool, event, sample, evsel, machine); |
800 | case PERF_RECORD_MMAP: | 804 | case PERF_RECORD_MMAP: |
801 | return tool->mmap(tool, event, sample, machine); | 805 | return tool->mmap(tool, event, sample, machine); |
@@ -964,6 +968,12 @@ static void perf_session__warn_about_errors(const struct perf_session *session, | |||
964 | session->hists.stats.nr_invalid_chains, | 968 | session->hists.stats.nr_invalid_chains, |
965 | session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); | 969 | session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); |
966 | } | 970 | } |
971 | |||
972 | if (session->hists.stats.nr_unprocessable_samples != 0) { | ||
973 | ui__warning("%u unprocessable samples recorded.\n" | ||
974 | "Do you have a KVM guest running and not using 'perf kvm'?\n", | ||
975 | session->hists.stats.nr_unprocessable_samples); | ||
976 | } | ||
967 | } | 977 | } |
968 | 978 | ||
969 | #define session_done() (*(volatile int *)(&session_done)) | 979 | #define session_done() (*(volatile int *)(&session_done)) |
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index 36d4c5619575..d0f9f29cf181 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py | |||
@@ -24,11 +24,11 @@ cflags += getenv('CFLAGS', '').split() | |||
24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') | 24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') |
25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') | 25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') |
26 | 26 | ||
27 | ext_sources = [f.strip() for f in file('util/python-ext-sources') | ||
28 | if len(f.strip()) > 0 and f[0] != '#'] | ||
29 | |||
27 | perf = Extension('perf', | 30 | perf = Extension('perf', |
28 | sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', | 31 | sources = ext_sources, |
29 | 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', | ||
30 | 'util/util.c', 'util/xyarray.c', 'util/cgroup.c', | ||
31 | 'util/debugfs.c'], | ||
32 | include_dirs = ['util/include'], | 32 | include_dirs = ['util/include'], |
33 | extra_compile_args = cflags, | 33 | extra_compile_args = cflags, |
34 | ) | 34 | ) |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index fc6e12fe4b44..5dd83c3e2c0c 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #include <ctype.h> | ||
2 | #include <dirent.h> | 1 | #include <dirent.h> |
3 | #include <errno.h> | 2 | #include <errno.h> |
4 | #include <libgen.h> | 3 | #include <libgen.h> |
@@ -12,6 +11,7 @@ | |||
12 | #include <unistd.h> | 11 | #include <unistd.h> |
13 | #include <inttypes.h> | 12 | #include <inttypes.h> |
14 | #include "build-id.h" | 13 | #include "build-id.h" |
14 | #include "util.h" | ||
15 | #include "debug.h" | 15 | #include "debug.h" |
16 | #include "symbol.h" | 16 | #include "symbol.h" |
17 | #include "strlist.h" | 17 | #include "strlist.h" |
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c new file mode 100644 index 000000000000..48c6902e749f --- /dev/null +++ b/tools/perf/util/sysfs.c | |||
@@ -0,0 +1,60 @@ | |||
1 | |||
2 | #include "util.h" | ||
3 | #include "sysfs.h" | ||
4 | |||
5 | static const char * const sysfs_known_mountpoints[] = { | ||
6 | "/sys", | ||
7 | 0, | ||
8 | }; | ||
9 | |||
10 | static int sysfs_found; | ||
11 | char sysfs_mountpoint[PATH_MAX]; | ||
12 | |||
13 | static int sysfs_valid_mountpoint(const char *sysfs) | ||
14 | { | ||
15 | struct statfs st_fs; | ||
16 | |||
17 | if (statfs(sysfs, &st_fs) < 0) | ||
18 | return -ENOENT; | ||
19 | else if (st_fs.f_type != (long) SYSFS_MAGIC) | ||
20 | return -ENOENT; | ||
21 | |||
22 | return 0; | ||
23 | } | ||
24 | |||
25 | const char *sysfs_find_mountpoint(void) | ||
26 | { | ||
27 | const char * const *ptr; | ||
28 | char type[100]; | ||
29 | FILE *fp; | ||
30 | |||
31 | if (sysfs_found) | ||
32 | return (const char *) sysfs_mountpoint; | ||
33 | |||
34 | ptr = sysfs_known_mountpoints; | ||
35 | while (*ptr) { | ||
36 | if (sysfs_valid_mountpoint(*ptr) == 0) { | ||
37 | sysfs_found = 1; | ||
38 | strcpy(sysfs_mountpoint, *ptr); | ||
39 | return sysfs_mountpoint; | ||
40 | } | ||
41 | ptr++; | ||
42 | } | ||
43 | |||
44 | /* give up and parse /proc/mounts */ | ||
45 | fp = fopen("/proc/mounts", "r"); | ||
46 | if (fp == NULL) | ||
47 | return NULL; | ||
48 | |||
49 | while (!sysfs_found && | ||
50 | fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", | ||
51 | sysfs_mountpoint, type) == 2) { | ||
52 | |||
53 | if (strcmp(type, "sysfs") == 0) | ||
54 | sysfs_found = 1; | ||
55 | } | ||
56 | |||
57 | fclose(fp); | ||
58 | |||
59 | return sysfs_found ? sysfs_mountpoint : NULL; | ||
60 | } | ||
diff --git a/tools/perf/util/sysfs.h b/tools/perf/util/sysfs.h new file mode 100644 index 000000000000..a813b7203938 --- /dev/null +++ b/tools/perf/util/sysfs.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef __SYSFS_H__ | ||
2 | #define __SYSFS_H__ | ||
3 | |||
4 | const char *sysfs_find_mountpoint(void); | ||
5 | |||
6 | #endif /* __DEBUGFS_H__ */ | ||
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 3d4b6c5931b9..e15983cf077d 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c | |||
@@ -6,6 +6,8 @@ | |||
6 | #include <sys/types.h> | 6 | #include <sys/types.h> |
7 | #include <sys/stat.h> | 7 | #include <sys/stat.h> |
8 | #include <unistd.h> | 8 | #include <unistd.h> |
9 | #include "strlist.h" | ||
10 | #include <string.h> | ||
9 | #include "thread_map.h" | 11 | #include "thread_map.h" |
10 | 12 | ||
11 | /* Skip "." and ".." directories */ | 13 | /* Skip "." and ".." directories */ |
@@ -152,6 +154,132 @@ struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid) | |||
152 | return thread_map__new_by_tid(tid); | 154 | return thread_map__new_by_tid(tid); |
153 | } | 155 | } |
154 | 156 | ||
157 | static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) | ||
158 | { | ||
159 | struct thread_map *threads = NULL, *nt; | ||
160 | char name[256]; | ||
161 | int items, total_tasks = 0; | ||
162 | struct dirent **namelist = NULL; | ||
163 | int i, j = 0; | ||
164 | pid_t pid, prev_pid = INT_MAX; | ||
165 | char *end_ptr; | ||
166 | struct str_node *pos; | ||
167 | struct strlist *slist = strlist__new(false, pid_str); | ||
168 | |||
169 | if (!slist) | ||
170 | return NULL; | ||
171 | |||
172 | strlist__for_each(pos, slist) { | ||
173 | pid = strtol(pos->s, &end_ptr, 10); | ||
174 | |||
175 | if (pid == INT_MIN || pid == INT_MAX || | ||
176 | (*end_ptr != '\0' && *end_ptr != ',')) | ||
177 | goto out_free_threads; | ||
178 | |||
179 | if (pid == prev_pid) | ||
180 | continue; | ||
181 | |||
182 | sprintf(name, "/proc/%d/task", pid); | ||
183 | items = scandir(name, &namelist, filter, NULL); | ||
184 | if (items <= 0) | ||
185 | goto out_free_threads; | ||
186 | |||
187 | total_tasks += items; | ||
188 | nt = realloc(threads, (sizeof(*threads) + | ||
189 | sizeof(pid_t) * total_tasks)); | ||
190 | if (nt == NULL) | ||
191 | goto out_free_threads; | ||
192 | |||
193 | threads = nt; | ||
194 | |||
195 | if (threads) { | ||
196 | for (i = 0; i < items; i++) | ||
197 | threads->map[j++] = atoi(namelist[i]->d_name); | ||
198 | threads->nr = total_tasks; | ||
199 | } | ||
200 | |||
201 | for (i = 0; i < items; i++) | ||
202 | free(namelist[i]); | ||
203 | free(namelist); | ||
204 | |||
205 | if (!threads) | ||
206 | break; | ||
207 | } | ||
208 | |||
209 | out: | ||
210 | strlist__delete(slist); | ||
211 | return threads; | ||
212 | |||
213 | out_free_threads: | ||
214 | free(threads); | ||
215 | threads = NULL; | ||
216 | goto out; | ||
217 | } | ||
218 | |||
219 | static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) | ||
220 | { | ||
221 | struct thread_map *threads = NULL, *nt; | ||
222 | int ntasks = 0; | ||
223 | pid_t tid, prev_tid = INT_MAX; | ||
224 | char *end_ptr; | ||
225 | struct str_node *pos; | ||
226 | struct strlist *slist; | ||
227 | |||
228 | /* perf-stat expects threads to be generated even if tid not given */ | ||
229 | if (!tid_str) { | ||
230 | threads = malloc(sizeof(*threads) + sizeof(pid_t)); | ||
231 | if (threads != NULL) { | ||
232 | threads->map[1] = -1; | ||
233 | threads->nr = 1; | ||
234 | } | ||
235 | return threads; | ||
236 | } | ||
237 | |||
238 | slist = strlist__new(false, tid_str); | ||
239 | if (!slist) | ||
240 | return NULL; | ||
241 | |||
242 | strlist__for_each(pos, slist) { | ||
243 | tid = strtol(pos->s, &end_ptr, 10); | ||
244 | |||
245 | if (tid == INT_MIN || tid == INT_MAX || | ||
246 | (*end_ptr != '\0' && *end_ptr != ',')) | ||
247 | goto out_free_threads; | ||
248 | |||
249 | if (tid == prev_tid) | ||
250 | continue; | ||
251 | |||
252 | ntasks++; | ||
253 | nt = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks); | ||
254 | |||
255 | if (nt == NULL) | ||
256 | goto out_free_threads; | ||
257 | |||
258 | threads = nt; | ||
259 | threads->map[ntasks - 1] = tid; | ||
260 | threads->nr = ntasks; | ||
261 | } | ||
262 | out: | ||
263 | return threads; | ||
264 | |||
265 | out_free_threads: | ||
266 | free(threads); | ||
267 | threads = NULL; | ||
268 | goto out; | ||
269 | } | ||
270 | |||
271 | struct thread_map *thread_map__new_str(const char *pid, const char *tid, | ||
272 | uid_t uid) | ||
273 | { | ||
274 | if (pid) | ||
275 | return thread_map__new_by_pid_str(pid); | ||
276 | |||
277 | if (!tid && uid != UINT_MAX) | ||
278 | return thread_map__new_by_uid(uid); | ||
279 | |||
280 | return thread_map__new_by_tid_str(tid); | ||
281 | } | ||
282 | |||
155 | void thread_map__delete(struct thread_map *threads) | 283 | void thread_map__delete(struct thread_map *threads) |
156 | { | 284 | { |
157 | free(threads); | 285 | free(threads); |
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h index c75ddbaba005..7da80f14418b 100644 --- a/tools/perf/util/thread_map.h +++ b/tools/perf/util/thread_map.h | |||
@@ -13,6 +13,10 @@ struct thread_map *thread_map__new_by_pid(pid_t pid); | |||
13 | struct thread_map *thread_map__new_by_tid(pid_t tid); | 13 | struct thread_map *thread_map__new_by_tid(pid_t tid); |
14 | struct thread_map *thread_map__new_by_uid(uid_t uid); | 14 | struct thread_map *thread_map__new_by_uid(uid_t uid); |
15 | struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); | 15 | struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); |
16 | |||
17 | struct thread_map *thread_map__new_str(const char *pid, | ||
18 | const char *tid, uid_t uid); | ||
19 | |||
16 | void thread_map__delete(struct thread_map *threads); | 20 | void thread_map__delete(struct thread_map *threads); |
17 | 21 | ||
18 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); | 22 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); |
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index e4370ca27193..09fe579ccafb 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c | |||
@@ -69,11 +69,11 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
69 | 69 | ||
70 | ret += SNPRINTF(bf + ret, size - ret, "], "); | 70 | ret += SNPRINTF(bf + ret, size - ret, "], "); |
71 | 71 | ||
72 | if (top->target_pid != -1) | 72 | if (top->target_pid) |
73 | ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %d", | 73 | ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", |
74 | top->target_pid); | 74 | top->target_pid); |
75 | else if (top->target_tid != -1) | 75 | else if (top->target_tid) |
76 | ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d", | 76 | ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", |
77 | top->target_tid); | 77 | top->target_tid); |
78 | else if (top->uid_str != NULL) | 78 | else if (top->uid_str != NULL) |
79 | ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", | 79 | ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", |
@@ -85,7 +85,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
85 | ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", | 85 | ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", |
86 | top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); | 86 | top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); |
87 | else { | 87 | else { |
88 | if (top->target_tid != -1) | 88 | if (top->target_tid) |
89 | ret += SNPRINTF(bf + ret, size - ret, ")"); | 89 | ret += SNPRINTF(bf + ret, size - ret, ")"); |
90 | else | 90 | else |
91 | ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", | 91 | ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", |
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index def3e53e0fe0..ce61cb2d1acf 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
@@ -23,7 +23,7 @@ struct perf_top { | |||
23 | u64 guest_us_samples, guest_kernel_samples; | 23 | u64 guest_us_samples, guest_kernel_samples; |
24 | int print_entries, count_filter, delay_secs; | 24 | int print_entries, count_filter, delay_secs; |
25 | int freq; | 25 | int freq; |
26 | pid_t target_pid, target_tid; | 26 | const char *target_pid, *target_tid; |
27 | uid_t uid; | 27 | uid_t uid; |
28 | bool hide_kernel_symbols, hide_user_symbols, zero; | 28 | bool hide_kernel_symbols, hide_user_symbols, zero; |
29 | bool system_wide; | 29 | bool system_wide; |
@@ -34,7 +34,8 @@ struct perf_top { | |||
34 | bool vmlinux_warned; | 34 | bool vmlinux_warned; |
35 | bool inherit; | 35 | bool inherit; |
36 | bool group; | 36 | bool group; |
37 | bool sample_id_all_avail; | 37 | bool sample_id_all_missing; |
38 | bool exclude_guest_missing; | ||
38 | bool dump_symtab; | 39 | bool dump_symtab; |
39 | const char *cpu_list; | 40 | const char *cpu_list; |
40 | struct hist_entry *sym_filter_entry; | 41 | struct hist_entry *sym_filter_entry; |
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c index d0c013934f30..52bb07c6442a 100644 --- a/tools/perf/util/usage.c +++ b/tools/perf/util/usage.c | |||
@@ -83,7 +83,7 @@ void warning(const char *warn, ...) | |||
83 | va_end(params); | 83 | va_end(params); |
84 | } | 84 | } |
85 | 85 | ||
86 | uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid) | 86 | uid_t parse_target_uid(const char *str, const char *tid, const char *pid) |
87 | { | 87 | { |
88 | struct passwd pwd, *result; | 88 | struct passwd pwd, *result; |
89 | char buf[1024]; | 89 | char buf[1024]; |
@@ -91,8 +91,8 @@ uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid) | |||
91 | if (str == NULL) | 91 | if (str == NULL) |
92 | return UINT_MAX; | 92 | return UINT_MAX; |
93 | 93 | ||
94 | /* CPU and PID are mutually exclusive */ | 94 | /* UID and PID are mutually exclusive */ |
95 | if (tid > 0 || pid > 0) { | 95 | if (tid || pid) { |
96 | ui__warning("PID/TID switch overriding UID\n"); | 96 | ui__warning("PID/TID switch overriding UID\n"); |
97 | sleep(1); | 97 | sleep(1); |
98 | return UINT_MAX; | 98 | return UINT_MAX; |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 813141047fc2..8109a907841e 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * XXX We need to find a better place for these things... | 6 | * XXX We need to find a better place for these things... |
7 | */ | 7 | */ |
8 | bool perf_host = true; | 8 | bool perf_host = true; |
9 | bool perf_guest = true; | 9 | bool perf_guest = false; |
10 | 10 | ||
11 | void event_attr_init(struct perf_event_attr *attr) | 11 | void event_attr_init(struct perf_event_attr *attr) |
12 | { | 12 | { |
@@ -14,6 +14,8 @@ void event_attr_init(struct perf_event_attr *attr) | |||
14 | attr->exclude_host = 1; | 14 | attr->exclude_host = 1; |
15 | if (!perf_guest) | 15 | if (!perf_guest) |
16 | attr->exclude_guest = 1; | 16 | attr->exclude_guest = 1; |
17 | /* to capture ABI version */ | ||
18 | attr->size = sizeof(*attr); | ||
17 | } | 19 | } |
18 | 20 | ||
19 | int mkdir_p(char *path, mode_t mode) | 21 | int mkdir_p(char *path, mode_t mode) |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 232d17ef3e60..0f99f394d8e0 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -199,6 +199,8 @@ static inline int has_extension(const char *filename, const char *ext) | |||
199 | #undef isalpha | 199 | #undef isalpha |
200 | #undef isprint | 200 | #undef isprint |
201 | #undef isalnum | 201 | #undef isalnum |
202 | #undef islower | ||
203 | #undef isupper | ||
202 | #undef tolower | 204 | #undef tolower |
203 | #undef toupper | 205 | #undef toupper |
204 | 206 | ||
@@ -219,6 +221,8 @@ extern unsigned char sane_ctype[256]; | |||
219 | #define isalpha(x) sane_istest(x,GIT_ALPHA) | 221 | #define isalpha(x) sane_istest(x,GIT_ALPHA) |
220 | #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) | 222 | #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) |
221 | #define isprint(x) sane_istest(x,GIT_PRINT) | 223 | #define isprint(x) sane_istest(x,GIT_PRINT) |
224 | #define islower(x) (sane_istest(x,GIT_ALPHA) && sane_istest(x,0x20)) | ||
225 | #define isupper(x) (sane_istest(x,GIT_ALPHA) && !sane_istest(x,0x20)) | ||
222 | #define tolower(x) sane_case((unsigned char)(x), 0x20) | 226 | #define tolower(x) sane_case((unsigned char)(x), 0x20) |
223 | #define toupper(x) sane_case((unsigned char)(x), 0) | 227 | #define toupper(x) sane_case((unsigned char)(x), 0) |
224 | 228 | ||
@@ -245,7 +249,7 @@ struct perf_event_attr; | |||
245 | 249 | ||
246 | void event_attr_init(struct perf_event_attr *attr); | 250 | void event_attr_init(struct perf_event_attr *attr); |
247 | 251 | ||
248 | uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid); | 252 | uid_t parse_target_uid(const char *str, const char *tid, const char *pid); |
249 | 253 | ||
250 | #define _STR(x) #x | 254 | #define _STR(x) #x |
251 | #define STR(x) _STR(x) | 255 | #define STR(x) _STR(x) |