diff options
author | Ingo Molnar <mingo@elte.hu> | 2010-12-07 01:51:14 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-12-07 01:51:14 -0500 |
commit | 75b5293a5d176cd9caf6dc590da4f3458c048c3c (patch) | |
tree | 40929d6108c662d6eb4c65f900312a37d0d6d566 /tools/perf | |
parent | 10a18d7dc0d9f12483c95ffc234118e9b80edfeb (diff) | |
parent | ce47dc56a2241dc035160a85bc5e34283cdd622c (diff) |
Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/core
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Documentation/perf-record.txt | 5 | ||||
-rw-r--r-- | tools/perf/builtin-annotate.c | 6 | ||||
-rw-r--r-- | tools/perf/builtin-diff.c | 11 | ||||
-rw-r--r-- | tools/perf/builtin-inject.c | 39 | ||||
-rw-r--r-- | tools/perf/builtin-kmem.c | 24 | ||||
-rw-r--r-- | tools/perf/builtin-lock.c | 15 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 23 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 15 | ||||
-rw-r--r-- | tools/perf/builtin-sched.c | 24 | ||||
-rw-r--r-- | tools/perf/builtin-script.c | 44 | ||||
-rw-r--r-- | tools/perf/builtin-timechart.c | 43 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 12 | ||||
-rw-r--r-- | tools/perf/util/build-id.c | 7 | ||||
-rw-r--r-- | tools/perf/util/event.c | 341 | ||||
-rw-r--r-- | tools/perf/util/event.h | 27 | ||||
-rw-r--r-- | tools/perf/util/header.c | 32 | ||||
-rw-r--r-- | tools/perf/util/header.h | 1 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 2 | ||||
-rw-r--r-- | tools/perf/util/parse-options.h | 4 | ||||
-rw-r--r-- | tools/perf/util/session.c | 226 | ||||
-rw-r--r-- | tools/perf/util/session.h | 12 | ||||
-rw-r--r-- | tools/perf/util/sort.c | 6 |
22 files changed, 608 insertions, 311 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 0ad1bc75ab49..52462ae26455 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -108,6 +108,11 @@ OPTIONS | |||
108 | --data:: | 108 | --data:: |
109 | Sample addresses. | 109 | Sample addresses. |
110 | 110 | ||
111 | -T:: | ||
112 | --timestamp:: | ||
113 | Sample timestamps. Use it with 'perf report -D' to see the timestamps, | ||
114 | for instance. | ||
115 | |||
111 | -n:: | 116 | -n:: |
112 | --no-samples:: | 117 | --no-samples:: |
113 | Don't sample. | 118 | Don't sample. |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 6d5604d8df95..569a2761b90a 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -58,12 +58,12 @@ static int hists__add_entry(struct hists *self, struct addr_location *al) | |||
58 | return hist_entry__inc_addr_samples(he, al->addr); | 58 | return hist_entry__inc_addr_samples(he, al->addr); |
59 | } | 59 | } |
60 | 60 | ||
61 | static int process_sample_event(event_t *event, struct perf_session *session) | 61 | static int process_sample_event(event_t *event, struct sample_data *sample, |
62 | struct perf_session *session) | ||
62 | { | 63 | { |
63 | struct addr_location al; | 64 | struct addr_location al; |
64 | struct sample_data data; | ||
65 | 65 | ||
66 | if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { | 66 | if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { |
67 | pr_warning("problem processing %d event, skipping it.\n", | 67 | pr_warning("problem processing %d event, skipping it.\n", |
68 | event->header.type); | 68 | event->header.type); |
69 | return -1; | 69 | return -1; |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 221b823bc26f..5e1a043aae03 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -30,12 +30,13 @@ static int hists__add_entry(struct hists *self, | |||
30 | return -ENOMEM; | 30 | return -ENOMEM; |
31 | } | 31 | } |
32 | 32 | ||
33 | static int diff__process_sample_event(event_t *event, struct perf_session *session) | 33 | static int diff__process_sample_event(event_t *event, |
34 | struct sample_data *sample, | ||
35 | struct perf_session *session) | ||
34 | { | 36 | { |
35 | struct addr_location al; | 37 | struct addr_location al; |
36 | struct sample_data data = { .period = 1, }; | ||
37 | 38 | ||
38 | if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { | 39 | if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { |
39 | pr_warning("problem processing %d event, skipping it.\n", | 40 | pr_warning("problem processing %d event, skipping it.\n", |
40 | event->header.type); | 41 | event->header.type); |
41 | return -1; | 42 | return -1; |
@@ -44,12 +45,12 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi | |||
44 | if (al.filtered || al.sym == NULL) | 45 | if (al.filtered || al.sym == NULL) |
45 | return 0; | 46 | return 0; |
46 | 47 | ||
47 | if (hists__add_entry(&session->hists, &al, data.period)) { | 48 | if (hists__add_entry(&session->hists, &al, sample->period)) { |
48 | pr_warning("problem incrementing symbol period, skipping event\n"); | 49 | pr_warning("problem incrementing symbol period, skipping event\n"); |
49 | return -1; | 50 | return -1; |
50 | } | 51 | } |
51 | 52 | ||
52 | session->hists.stats.total_period += data.period; | 53 | session->hists.stats.total_period += sample->period; |
53 | return 0; | 54 | return 0; |
54 | } | 55 | } |
55 | 56 | ||
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 8e3e47b064ce..4b66b8579410 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -16,8 +16,8 @@ | |||
16 | static char const *input_name = "-"; | 16 | static char const *input_name = "-"; |
17 | static bool inject_build_ids; | 17 | static bool inject_build_ids; |
18 | 18 | ||
19 | static int event__repipe(event_t *event __used, | 19 | static int event__repipe_synth(event_t *event, |
20 | struct perf_session *session __used) | 20 | struct perf_session *session __used) |
21 | { | 21 | { |
22 | uint32_t size; | 22 | uint32_t size; |
23 | void *buf = event; | 23 | void *buf = event; |
@@ -36,22 +36,30 @@ static int event__repipe(event_t *event __used, | |||
36 | return 0; | 36 | return 0; |
37 | } | 37 | } |
38 | 38 | ||
39 | static int event__repipe_mmap(event_t *self, struct perf_session *session) | 39 | static int event__repipe(event_t *event, struct sample_data *sample __used, |
40 | struct perf_session *session) | ||
41 | { | ||
42 | return event__repipe_synth(event, session); | ||
43 | } | ||
44 | |||
45 | static int event__repipe_mmap(event_t *self, struct sample_data *sample, | ||
46 | struct perf_session *session) | ||
40 | { | 47 | { |
41 | int err; | 48 | int err; |
42 | 49 | ||
43 | err = event__process_mmap(self, session); | 50 | err = event__process_mmap(self, sample, session); |
44 | event__repipe(self, session); | 51 | event__repipe(self, sample, session); |
45 | 52 | ||
46 | return err; | 53 | return err; |
47 | } | 54 | } |
48 | 55 | ||
49 | static int event__repipe_task(event_t *self, struct perf_session *session) | 56 | static int event__repipe_task(event_t *self, struct sample_data *sample, |
57 | struct perf_session *session) | ||
50 | { | 58 | { |
51 | int err; | 59 | int err; |
52 | 60 | ||
53 | err = event__process_task(self, session); | 61 | err = event__process_task(self, sample, session); |
54 | event__repipe(self, session); | 62 | event__repipe(self, sample, session); |
55 | 63 | ||
56 | return err; | 64 | return err; |
57 | } | 65 | } |
@@ -61,7 +69,7 @@ static int event__repipe_tracing_data(event_t *self, | |||
61 | { | 69 | { |
62 | int err; | 70 | int err; |
63 | 71 | ||
64 | event__repipe(self, session); | 72 | event__repipe_synth(self, session); |
65 | err = event__process_tracing_data(self, session); | 73 | err = event__process_tracing_data(self, session); |
66 | 74 | ||
67 | return err; | 75 | return err; |
@@ -111,7 +119,8 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session) | |||
111 | return 0; | 119 | return 0; |
112 | } | 120 | } |
113 | 121 | ||
114 | static int event__inject_buildid(event_t *event, struct perf_session *session) | 122 | static int event__inject_buildid(event_t *event, struct sample_data *sample, |
123 | struct perf_session *session) | ||
115 | { | 124 | { |
116 | struct addr_location al; | 125 | struct addr_location al; |
117 | struct thread *thread; | 126 | struct thread *thread; |
@@ -146,7 +155,7 @@ static int event__inject_buildid(event_t *event, struct perf_session *session) | |||
146 | } | 155 | } |
147 | 156 | ||
148 | repipe: | 157 | repipe: |
149 | event__repipe(event, session); | 158 | event__repipe(event, sample, session); |
150 | return 0; | 159 | return 0; |
151 | } | 160 | } |
152 | 161 | ||
@@ -160,10 +169,10 @@ struct perf_event_ops inject_ops = { | |||
160 | .read = event__repipe, | 169 | .read = event__repipe, |
161 | .throttle = event__repipe, | 170 | .throttle = event__repipe, |
162 | .unthrottle = event__repipe, | 171 | .unthrottle = event__repipe, |
163 | .attr = event__repipe, | 172 | .attr = event__repipe_synth, |
164 | .event_type = event__repipe, | 173 | .event_type = event__repipe_synth, |
165 | .tracing_data = event__repipe, | 174 | .tracing_data = event__repipe_synth, |
166 | .build_id = event__repipe, | 175 | .build_id = event__repipe_synth, |
167 | }; | 176 | }; |
168 | 177 | ||
169 | extern volatile int session_done; | 178 | extern volatile int session_done; |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 31f60a2535e0..c9620ff6496f 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -304,22 +304,11 @@ process_raw_event(event_t *raw_event __used, void *data, | |||
304 | } | 304 | } |
305 | } | 305 | } |
306 | 306 | ||
307 | static int process_sample_event(event_t *event, struct perf_session *session) | 307 | static int process_sample_event(event_t *event, struct sample_data *sample, |
308 | struct perf_session *session) | ||
308 | { | 309 | { |
309 | struct sample_data data; | 310 | struct thread *thread = perf_session__findnew(session, event->ip.pid); |
310 | struct thread *thread; | ||
311 | 311 | ||
312 | memset(&data, 0, sizeof(data)); | ||
313 | data.time = -1; | ||
314 | data.cpu = -1; | ||
315 | data.period = 1; | ||
316 | |||
317 | event__parse_sample(event, session->sample_type, &data); | ||
318 | |||
319 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, | ||
320 | data.pid, data.tid, data.ip, data.period); | ||
321 | |||
322 | thread = perf_session__findnew(session, event->ip.pid); | ||
323 | if (thread == NULL) { | 312 | if (thread == NULL) { |
324 | pr_debug("problem processing %d event, skipping it.\n", | 313 | pr_debug("problem processing %d event, skipping it.\n", |
325 | event->header.type); | 314 | event->header.type); |
@@ -328,8 +317,8 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
328 | 317 | ||
329 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 318 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
330 | 319 | ||
331 | process_raw_event(event, data.raw_data, data.cpu, | 320 | process_raw_event(event, sample->raw_data, sample->cpu, |
332 | data.time, thread); | 321 | sample->time, thread); |
333 | 322 | ||
334 | return 0; | 323 | return 0; |
335 | } | 324 | } |
@@ -747,6 +736,9 @@ static int __cmd_record(int argc, const char **argv) | |||
747 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; | 736 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; |
748 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 737 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
749 | 738 | ||
739 | if (rec_argv == NULL) | ||
740 | return -ENOMEM; | ||
741 | |||
750 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 742 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
751 | rec_argv[i] = strdup(record_args[i]); | 743 | rec_argv[i] = strdup(record_args[i]); |
752 | 744 | ||
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 8452a2ae2191..b41b4492b1cc 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c | |||
@@ -834,22 +834,18 @@ static void dump_info(void) | |||
834 | die("Unknown type of information\n"); | 834 | die("Unknown type of information\n"); |
835 | } | 835 | } |
836 | 836 | ||
837 | static int process_sample_event(event_t *self, struct perf_session *s) | 837 | static int process_sample_event(event_t *self, struct sample_data *sample, |
838 | struct perf_session *s) | ||
838 | { | 839 | { |
839 | struct sample_data data; | 840 | struct thread *thread = perf_session__findnew(s, sample->tid); |
840 | struct thread *thread; | ||
841 | 841 | ||
842 | bzero(&data, sizeof(data)); | ||
843 | event__parse_sample(self, s->sample_type, &data); | ||
844 | |||
845 | thread = perf_session__findnew(s, data.tid); | ||
846 | if (thread == NULL) { | 842 | if (thread == NULL) { |
847 | pr_debug("problem processing %d event, skipping it.\n", | 843 | pr_debug("problem processing %d event, skipping it.\n", |
848 | self->header.type); | 844 | self->header.type); |
849 | return -1; | 845 | return -1; |
850 | } | 846 | } |
851 | 847 | ||
852 | process_raw_event(data.raw_data, data.cpu, data.time, thread); | 848 | process_raw_event(sample->raw_data, sample->cpu, sample->time, thread); |
853 | 849 | ||
854 | return 0; | 850 | return 0; |
855 | } | 851 | } |
@@ -947,6 +943,9 @@ static int __cmd_record(int argc, const char **argv) | |||
947 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; | 943 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; |
948 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 944 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
949 | 945 | ||
946 | if (rec_argv == NULL) | ||
947 | return -ENOMEM; | ||
948 | |||
950 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 949 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
951 | rec_argv[i] = strdup(record_args[i]); | 950 | rec_argv[i] = strdup(record_args[i]); |
952 | 951 | ||
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 024e1441d76b..699dd2149c4b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -36,6 +36,7 @@ static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; | |||
36 | 36 | ||
37 | static u64 user_interval = ULLONG_MAX; | 37 | static u64 user_interval = ULLONG_MAX; |
38 | static u64 default_interval = 0; | 38 | static u64 default_interval = 0; |
39 | static u64 sample_type; | ||
39 | 40 | ||
40 | static int nr_cpus = 0; | 41 | static int nr_cpus = 0; |
41 | static unsigned int page_size; | 42 | static unsigned int page_size; |
@@ -48,6 +49,7 @@ static const char *output_name = "perf.data"; | |||
48 | static int group = 0; | 49 | static int group = 0; |
49 | static int realtime_prio = 0; | 50 | static int realtime_prio = 0; |
50 | static bool raw_samples = false; | 51 | static bool raw_samples = false; |
52 | static bool sample_id_all_avail = true; | ||
51 | static bool system_wide = false; | 53 | static bool system_wide = false; |
52 | static pid_t target_pid = -1; | 54 | static pid_t target_pid = -1; |
53 | static pid_t target_tid = -1; | 55 | static pid_t target_tid = -1; |
@@ -60,6 +62,7 @@ static bool call_graph = false; | |||
60 | static bool inherit_stat = false; | 62 | static bool inherit_stat = false; |
61 | static bool no_samples = false; | 63 | static bool no_samples = false; |
62 | static bool sample_address = false; | 64 | static bool sample_address = false; |
65 | static bool sample_time = false; | ||
63 | static bool no_buildid = false; | 66 | static bool no_buildid = false; |
64 | static bool no_buildid_cache = false; | 67 | static bool no_buildid_cache = false; |
65 | 68 | ||
@@ -129,6 +132,7 @@ static void write_output(void *buf, size_t size) | |||
129 | } | 132 | } |
130 | 133 | ||
131 | static int process_synthesized_event(event_t *event, | 134 | static int process_synthesized_event(event_t *event, |
135 | struct sample_data *sample __used, | ||
132 | struct perf_session *self __used) | 136 | struct perf_session *self __used) |
133 | { | 137 | { |
134 | write_output(event, event->header.size); | 138 | write_output(event, event->header.size); |
@@ -281,12 +285,18 @@ static void create_counter(int counter, int cpu) | |||
281 | if (system_wide) | 285 | if (system_wide) |
282 | attr->sample_type |= PERF_SAMPLE_CPU; | 286 | attr->sample_type |= PERF_SAMPLE_CPU; |
283 | 287 | ||
288 | if (sample_time) | ||
289 | attr->sample_type |= PERF_SAMPLE_TIME; | ||
290 | |||
284 | if (raw_samples) { | 291 | if (raw_samples) { |
285 | attr->sample_type |= PERF_SAMPLE_TIME; | 292 | attr->sample_type |= PERF_SAMPLE_TIME; |
286 | attr->sample_type |= PERF_SAMPLE_RAW; | 293 | attr->sample_type |= PERF_SAMPLE_RAW; |
287 | attr->sample_type |= PERF_SAMPLE_CPU; | 294 | attr->sample_type |= PERF_SAMPLE_CPU; |
288 | } | 295 | } |
289 | 296 | ||
297 | if (!sample_type) | ||
298 | sample_type = attr->sample_type; | ||
299 | |||
290 | attr->mmap = track; | 300 | attr->mmap = track; |
291 | attr->comm = track; | 301 | attr->comm = track; |
292 | attr->inherit = !no_inherit; | 302 | attr->inherit = !no_inherit; |
@@ -294,6 +304,8 @@ static void create_counter(int counter, int cpu) | |||
294 | attr->disabled = 1; | 304 | attr->disabled = 1; |
295 | attr->enable_on_exec = 1; | 305 | attr->enable_on_exec = 1; |
296 | } | 306 | } |
307 | retry_sample_id: | ||
308 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; | ||
297 | 309 | ||
298 | for (thread_index = 0; thread_index < thread_num; thread_index++) { | 310 | for (thread_index = 0; thread_index < thread_num; thread_index++) { |
299 | try_again: | 311 | try_again: |
@@ -310,6 +322,12 @@ try_again: | |||
310 | else if (err == ENODEV && cpu_list) { | 322 | else if (err == ENODEV && cpu_list) { |
311 | die("No such device - did you specify" | 323 | die("No such device - did you specify" |
312 | " an out-of-range profile CPU?\n"); | 324 | " an out-of-range profile CPU?\n"); |
325 | } else if (err == EINVAL && sample_id_all_avail) { | ||
326 | /* | ||
327 | * Old kernel, no attr->sample_id_type_all field | ||
328 | */ | ||
329 | sample_id_all_avail = false; | ||
330 | goto retry_sample_id; | ||
313 | } | 331 | } |
314 | 332 | ||
315 | /* | 333 | /* |
@@ -642,6 +660,8 @@ static int __cmd_record(int argc, const char **argv) | |||
642 | open_counters(cpumap[i]); | 660 | open_counters(cpumap[i]); |
643 | } | 661 | } |
644 | 662 | ||
663 | perf_session__set_sample_type(session, sample_type); | ||
664 | |||
645 | if (pipe_output) { | 665 | if (pipe_output) { |
646 | err = perf_header__write_pipe(output); | 666 | err = perf_header__write_pipe(output); |
647 | if (err < 0) | 667 | if (err < 0) |
@@ -654,6 +674,8 @@ static int __cmd_record(int argc, const char **argv) | |||
654 | 674 | ||
655 | post_processing_offset = lseek(output, 0, SEEK_CUR); | 675 | post_processing_offset = lseek(output, 0, SEEK_CUR); |
656 | 676 | ||
677 | perf_session__set_sample_id_all(session, sample_id_all_avail); | ||
678 | |||
657 | if (pipe_output) { | 679 | if (pipe_output) { |
658 | err = event__synthesize_attrs(&session->header, | 680 | err = event__synthesize_attrs(&session->header, |
659 | process_synthesized_event, | 681 | process_synthesized_event, |
@@ -834,6 +856,7 @@ const struct option record_options[] = { | |||
834 | "per thread counts"), | 856 | "per thread counts"), |
835 | OPT_BOOLEAN('d', "data", &sample_address, | 857 | OPT_BOOLEAN('d', "data", &sample_address, |
836 | "Sample addresses"), | 858 | "Sample addresses"), |
859 | OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"), | ||
837 | OPT_BOOLEAN('n', "no-samples", &no_samples, | 860 | OPT_BOOLEAN('n', "no-samples", &no_samples, |
838 | "don't sample"), | 861 | "don't sample"), |
839 | OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache, | 862 | OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache, |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 5de405d45230..904519fba434 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -150,13 +150,13 @@ static int add_event_total(struct perf_session *session, | |||
150 | return 0; | 150 | return 0; |
151 | } | 151 | } |
152 | 152 | ||
153 | static int process_sample_event(event_t *event, struct perf_session *session) | 153 | static int process_sample_event(event_t *event, struct sample_data *sample, |
154 | struct perf_session *session) | ||
154 | { | 155 | { |
155 | struct sample_data data = { .period = 1, }; | ||
156 | struct addr_location al; | 156 | struct addr_location al; |
157 | struct perf_event_attr *attr; | 157 | struct perf_event_attr *attr; |
158 | 158 | ||
159 | if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { | 159 | if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { |
160 | fprintf(stderr, "problem processing %d event, skipping it.\n", | 160 | fprintf(stderr, "problem processing %d event, skipping it.\n", |
161 | event->header.type); | 161 | event->header.type); |
162 | return -1; | 162 | return -1; |
@@ -165,14 +165,14 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
165 | if (al.filtered || (hide_unresolved && al.sym == NULL)) | 165 | if (al.filtered || (hide_unresolved && al.sym == NULL)) |
166 | return 0; | 166 | return 0; |
167 | 167 | ||
168 | if (perf_session__add_hist_entry(session, &al, &data)) { | 168 | if (perf_session__add_hist_entry(session, &al, sample)) { |
169 | pr_debug("problem incrementing symbol period, skipping event\n"); | 169 | pr_debug("problem incrementing symbol period, skipping event\n"); |
170 | return -1; | 170 | return -1; |
171 | } | 171 | } |
172 | 172 | ||
173 | attr = perf_header__find_attr(data.id, &session->header); | 173 | attr = perf_header__find_attr(sample->id, &session->header); |
174 | 174 | ||
175 | if (add_event_total(session, &data, attr)) { | 175 | if (add_event_total(session, sample, attr)) { |
176 | pr_debug("problem adding event period\n"); | 176 | pr_debug("problem adding event period\n"); |
177 | return -1; | 177 | return -1; |
178 | } | 178 | } |
@@ -180,7 +180,8 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
180 | return 0; | 180 | return 0; |
181 | } | 181 | } |
182 | 182 | ||
183 | static int process_read_event(event_t *event, struct perf_session *session __used) | 183 | static int process_read_event(event_t *event, struct sample_data *sample __used, |
184 | struct perf_session *session __used) | ||
184 | { | 185 | { |
185 | struct perf_event_attr *attr; | 186 | struct perf_event_attr *attr; |
186 | 187 | ||
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 26523c939791..c7753940aea0 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -1606,25 +1606,15 @@ process_raw_event(event_t *raw_event __used, struct perf_session *session, | |||
1606 | process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); | 1606 | process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); |
1607 | } | 1607 | } |
1608 | 1608 | ||
1609 | static int process_sample_event(event_t *event, struct perf_session *session) | 1609 | static int process_sample_event(event_t *event, struct sample_data *sample, |
1610 | struct perf_session *session) | ||
1610 | { | 1611 | { |
1611 | struct sample_data data; | ||
1612 | struct thread *thread; | 1612 | struct thread *thread; |
1613 | 1613 | ||
1614 | if (!(session->sample_type & PERF_SAMPLE_RAW)) | 1614 | if (!(session->sample_type & PERF_SAMPLE_RAW)) |
1615 | return 0; | 1615 | return 0; |
1616 | 1616 | ||
1617 | memset(&data, 0, sizeof(data)); | 1617 | thread = perf_session__findnew(session, sample->pid); |
1618 | data.time = -1; | ||
1619 | data.cpu = -1; | ||
1620 | data.period = -1; | ||
1621 | |||
1622 | event__parse_sample(event, session->sample_type, &data); | ||
1623 | |||
1624 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, | ||
1625 | data.pid, data.tid, data.ip, data.period); | ||
1626 | |||
1627 | thread = perf_session__findnew(session, data.pid); | ||
1628 | if (thread == NULL) { | 1618 | if (thread == NULL) { |
1629 | pr_debug("problem processing %d event, skipping it.\n", | 1619 | pr_debug("problem processing %d event, skipping it.\n", |
1630 | event->header.type); | 1620 | event->header.type); |
@@ -1633,10 +1623,11 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
1633 | 1623 | ||
1634 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 1624 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
1635 | 1625 | ||
1636 | if (profile_cpu != -1 && profile_cpu != (int)data.cpu) | 1626 | if (profile_cpu != -1 && profile_cpu != (int)sample->cpu) |
1637 | return 0; | 1627 | return 0; |
1638 | 1628 | ||
1639 | process_raw_event(event, session, data.raw_data, data.cpu, data.time, thread); | 1629 | process_raw_event(event, session, sample->raw_data, sample->cpu, |
1630 | sample->time, thread); | ||
1640 | 1631 | ||
1641 | return 0; | 1632 | return 0; |
1642 | } | 1633 | } |
@@ -1869,6 +1860,9 @@ static int __cmd_record(int argc, const char **argv) | |||
1869 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; | 1860 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; |
1870 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 1861 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
1871 | 1862 | ||
1863 | if (rec_argv) | ||
1864 | return -ENOMEM; | ||
1865 | |||
1872 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 1866 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
1873 | rec_argv[i] = strdup(record_args[i]); | 1867 | rec_argv[i] = strdup(record_args[i]); |
1874 | 1868 | ||
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 4539551ab40e..54f1ea808db5 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -63,22 +63,11 @@ static int cleanup_scripting(void) | |||
63 | 63 | ||
64 | static char const *input_name = "perf.data"; | 64 | static char const *input_name = "perf.data"; |
65 | 65 | ||
66 | static int process_sample_event(event_t *event, struct perf_session *session) | 66 | static int process_sample_event(event_t *event, struct sample_data *sample, |
67 | struct perf_session *session) | ||
67 | { | 68 | { |
68 | struct sample_data data; | 69 | struct thread *thread = perf_session__findnew(session, event->ip.pid); |
69 | struct thread *thread; | ||
70 | 70 | ||
71 | memset(&data, 0, sizeof(data)); | ||
72 | data.time = -1; | ||
73 | data.cpu = -1; | ||
74 | data.period = 1; | ||
75 | |||
76 | event__parse_sample(event, session->sample_type, &data); | ||
77 | |||
78 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, | ||
79 | data.pid, data.tid, data.ip, data.period); | ||
80 | |||
81 | thread = perf_session__findnew(session, event->ip.pid); | ||
82 | if (thread == NULL) { | 71 | if (thread == NULL) { |
83 | pr_debug("problem processing %d event, skipping it.\n", | 72 | pr_debug("problem processing %d event, skipping it.\n", |
84 | event->header.type); | 73 | event->header.type); |
@@ -87,13 +76,13 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
87 | 76 | ||
88 | if (session->sample_type & PERF_SAMPLE_RAW) { | 77 | if (session->sample_type & PERF_SAMPLE_RAW) { |
89 | if (debug_mode) { | 78 | if (debug_mode) { |
90 | if (data.time < last_timestamp) { | 79 | if (sample->time < last_timestamp) { |
91 | pr_err("Samples misordered, previous: %llu " | 80 | pr_err("Samples misordered, previous: %llu " |
92 | "this: %llu\n", last_timestamp, | 81 | "this: %llu\n", last_timestamp, |
93 | data.time); | 82 | sample->time); |
94 | nr_unordered++; | 83 | nr_unordered++; |
95 | } | 84 | } |
96 | last_timestamp = data.time; | 85 | last_timestamp = sample->time; |
97 | return 0; | 86 | return 0; |
98 | } | 87 | } |
99 | /* | 88 | /* |
@@ -101,18 +90,19 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
101 | * field, although it should be the same than this perf | 90 | * field, although it should be the same than this perf |
102 | * event pid | 91 | * event pid |
103 | */ | 92 | */ |
104 | scripting_ops->process_event(data.cpu, data.raw_data, | 93 | scripting_ops->process_event(sample->cpu, sample->raw_data, |
105 | data.raw_size, | 94 | sample->raw_size, |
106 | data.time, thread->comm); | 95 | sample->time, thread->comm); |
107 | } | 96 | } |
108 | 97 | ||
109 | session->hists.stats.total_period += data.period; | 98 | session->hists.stats.total_period += sample->period; |
110 | return 0; | 99 | return 0; |
111 | } | 100 | } |
112 | 101 | ||
113 | static u64 nr_lost; | 102 | static u64 nr_lost; |
114 | 103 | ||
115 | static int process_lost_event(event_t *event, struct perf_session *session __used) | 104 | static int process_lost_event(event_t *event, struct sample_data *sample __used, |
105 | struct perf_session *session __used) | ||
116 | { | 106 | { |
117 | nr_lost += event->lost.lost; | 107 | nr_lost += event->lost.lost; |
118 | 108 | ||
@@ -397,10 +387,10 @@ out_delete_desc: | |||
397 | return NULL; | 387 | return NULL; |
398 | } | 388 | } |
399 | 389 | ||
400 | static char *ends_with(char *str, const char *suffix) | 390 | static const char *ends_with(const char *str, const char *suffix) |
401 | { | 391 | { |
402 | size_t suffix_len = strlen(suffix); | 392 | size_t suffix_len = strlen(suffix); |
403 | char *p = str; | 393 | const char *p = str; |
404 | 394 | ||
405 | if (strlen(str) > suffix_len) { | 395 | if (strlen(str) > suffix_len) { |
406 | p = str + strlen(str) - suffix_len; | 396 | p = str + strlen(str) - suffix_len; |
@@ -492,7 +482,7 @@ static int list_available_scripts(const struct option *opt __used, | |||
492 | 482 | ||
493 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { | 483 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { |
494 | script_root = strdup(script_dirent.d_name); | 484 | script_root = strdup(script_dirent.d_name); |
495 | str = ends_with(script_root, REPORT_SUFFIX); | 485 | str = (char *)ends_with(script_root, REPORT_SUFFIX); |
496 | if (str) { | 486 | if (str) { |
497 | *str = '\0'; | 487 | *str = '\0'; |
498 | desc = script_desc__findnew(script_root); | 488 | desc = script_desc__findnew(script_root); |
@@ -540,7 +530,7 @@ static char *get_script_path(const char *script_root, const char *suffix) | |||
540 | 530 | ||
541 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { | 531 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { |
542 | __script_root = strdup(script_dirent.d_name); | 532 | __script_root = strdup(script_dirent.d_name); |
543 | str = ends_with(__script_root, suffix); | 533 | str = (char *)ends_with(__script_root, suffix); |
544 | if (str) { | 534 | if (str) { |
545 | *str = '\0'; | 535 | *str = '\0'; |
546 | if (strcmp(__script_root, script_root)) | 536 | if (strcmp(__script_root, script_root)) |
@@ -560,7 +550,7 @@ static char *get_script_path(const char *script_root, const char *suffix) | |||
560 | 550 | ||
561 | static bool is_top_script(const char *script_path) | 551 | static bool is_top_script(const char *script_path) |
562 | { | 552 | { |
563 | return ends_with((char *)script_path, "top") == NULL ? false : true; | 553 | return ends_with(script_path, "top") == NULL ? false : true; |
564 | } | 554 | } |
565 | 555 | ||
566 | static int has_required_arg(char *script_path) | 556 | static int has_required_arg(char *script_path) |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 9bcc38f0b706..d2fc46103f83 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -272,19 +272,22 @@ static int cpus_cstate_state[MAX_CPUS]; | |||
272 | static u64 cpus_pstate_start_times[MAX_CPUS]; | 272 | static u64 cpus_pstate_start_times[MAX_CPUS]; |
273 | static u64 cpus_pstate_state[MAX_CPUS]; | 273 | static u64 cpus_pstate_state[MAX_CPUS]; |
274 | 274 | ||
275 | static int process_comm_event(event_t *event, struct perf_session *session __used) | 275 | static int process_comm_event(event_t *event, struct sample_data *sample __used, |
276 | struct perf_session *session __used) | ||
276 | { | 277 | { |
277 | pid_set_comm(event->comm.tid, event->comm.comm); | 278 | pid_set_comm(event->comm.tid, event->comm.comm); |
278 | return 0; | 279 | return 0; |
279 | } | 280 | } |
280 | 281 | ||
281 | static int process_fork_event(event_t *event, struct perf_session *session __used) | 282 | static int process_fork_event(event_t *event, struct sample_data *sample __used, |
283 | struct perf_session *session __used) | ||
282 | { | 284 | { |
283 | pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); | 285 | pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); |
284 | return 0; | 286 | return 0; |
285 | } | 287 | } |
286 | 288 | ||
287 | static int process_exit_event(event_t *event, struct perf_session *session __used) | 289 | static int process_exit_event(event_t *event, struct sample_data *sample __used, |
290 | struct perf_session *session __used) | ||
288 | { | 291 | { |
289 | pid_exit(event->fork.pid, event->fork.time); | 292 | pid_exit(event->fork.pid, event->fork.time); |
290 | return 0; | 293 | return 0; |
@@ -470,24 +473,21 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) | |||
470 | } | 473 | } |
471 | 474 | ||
472 | 475 | ||
473 | static int process_sample_event(event_t *event, struct perf_session *session) | 476 | static int process_sample_event(event_t *event __used, |
477 | struct sample_data *sample, | ||
478 | struct perf_session *session) | ||
474 | { | 479 | { |
475 | struct sample_data data; | ||
476 | struct trace_entry *te; | 480 | struct trace_entry *te; |
477 | 481 | ||
478 | memset(&data, 0, sizeof(data)); | ||
479 | |||
480 | event__parse_sample(event, session->sample_type, &data); | ||
481 | |||
482 | if (session->sample_type & PERF_SAMPLE_TIME) { | 482 | if (session->sample_type & PERF_SAMPLE_TIME) { |
483 | if (!first_time || first_time > data.time) | 483 | if (!first_time || first_time > sample->time) |
484 | first_time = data.time; | 484 | first_time = sample->time; |
485 | if (last_time < data.time) | 485 | if (last_time < sample->time) |
486 | last_time = data.time; | 486 | last_time = sample->time; |
487 | } | 487 | } |
488 | 488 | ||
489 | te = (void *)data.raw_data; | 489 | te = (void *)sample->raw_data; |
490 | if (session->sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) { | 490 | if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) { |
491 | char *event_str; | 491 | char *event_str; |
492 | struct power_entry *pe; | 492 | struct power_entry *pe; |
493 | 493 | ||
@@ -499,19 +499,19 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
499 | return 0; | 499 | return 0; |
500 | 500 | ||
501 | if (strcmp(event_str, "power:power_start") == 0) | 501 | if (strcmp(event_str, "power:power_start") == 0) |
502 | c_state_start(pe->cpu_id, data.time, pe->value); | 502 | c_state_start(pe->cpu_id, sample->time, pe->value); |
503 | 503 | ||
504 | if (strcmp(event_str, "power:power_end") == 0) | 504 | if (strcmp(event_str, "power:power_end") == 0) |
505 | c_state_end(pe->cpu_id, data.time); | 505 | c_state_end(pe->cpu_id, sample->time); |
506 | 506 | ||
507 | if (strcmp(event_str, "power:power_frequency") == 0) | 507 | if (strcmp(event_str, "power:power_frequency") == 0) |
508 | p_state_change(pe->cpu_id, data.time, pe->value); | 508 | p_state_change(pe->cpu_id, sample->time, pe->value); |
509 | 509 | ||
510 | if (strcmp(event_str, "sched:sched_wakeup") == 0) | 510 | if (strcmp(event_str, "sched:sched_wakeup") == 0) |
511 | sched_wakeup(data.cpu, data.time, data.pid, te); | 511 | sched_wakeup(sample->cpu, sample->time, sample->pid, te); |
512 | 512 | ||
513 | if (strcmp(event_str, "sched:sched_switch") == 0) | 513 | if (strcmp(event_str, "sched:sched_switch") == 0) |
514 | sched_switch(data.cpu, data.time, te); | 514 | sched_switch(sample->cpu, sample->time, te); |
515 | } | 515 | } |
516 | return 0; | 516 | return 0; |
517 | } | 517 | } |
@@ -989,6 +989,9 @@ static int __cmd_record(int argc, const char **argv) | |||
989 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; | 989 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; |
990 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 990 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
991 | 991 | ||
992 | if (rec_argv == NULL) | ||
993 | return -ENOMEM; | ||
994 | |||
992 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 995 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
993 | rec_argv[i] = strdup(record_args[i]); | 996 | rec_argv[i] = strdup(record_args[i]); |
994 | 997 | ||
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 3d2b47d5121a..0515ce9d3d3e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -977,12 +977,12 @@ static int symbol_filter(struct map *map, struct symbol *sym) | |||
977 | } | 977 | } |
978 | 978 | ||
979 | static void event__process_sample(const event_t *self, | 979 | static void event__process_sample(const event_t *self, |
980 | struct perf_session *session, int counter) | 980 | struct sample_data *sample, |
981 | struct perf_session *session, int counter) | ||
981 | { | 982 | { |
982 | u64 ip = self->ip.ip; | 983 | u64 ip = self->ip.ip; |
983 | struct sym_entry *syme; | 984 | struct sym_entry *syme; |
984 | struct addr_location al; | 985 | struct addr_location al; |
985 | struct sample_data data; | ||
986 | struct machine *machine; | 986 | struct machine *machine; |
987 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 987 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
988 | 988 | ||
@@ -1025,7 +1025,7 @@ static void event__process_sample(const event_t *self, | |||
1025 | if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) | 1025 | if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) |
1026 | exact_samples++; | 1026 | exact_samples++; |
1027 | 1027 | ||
1028 | if (event__preprocess_sample(self, session, &al, &data, | 1028 | if (event__preprocess_sample(self, session, &al, sample, |
1029 | symbol_filter) < 0 || | 1029 | symbol_filter) < 0 || |
1030 | al.filtered) | 1030 | al.filtered) |
1031 | return; | 1031 | return; |
@@ -1105,6 +1105,7 @@ static void perf_session__mmap_read_counter(struct perf_session *self, | |||
1105 | unsigned int head = mmap_read_head(md); | 1105 | unsigned int head = mmap_read_head(md); |
1106 | unsigned int old = md->prev; | 1106 | unsigned int old = md->prev; |
1107 | unsigned char *data = md->base + page_size; | 1107 | unsigned char *data = md->base + page_size; |
1108 | struct sample_data sample; | ||
1108 | int diff; | 1109 | int diff; |
1109 | 1110 | ||
1110 | /* | 1111 | /* |
@@ -1152,10 +1153,11 @@ static void perf_session__mmap_read_counter(struct perf_session *self, | |||
1152 | event = &event_copy; | 1153 | event = &event_copy; |
1153 | } | 1154 | } |
1154 | 1155 | ||
1156 | event__parse_sample(event, self, &sample); | ||
1155 | if (event->header.type == PERF_RECORD_SAMPLE) | 1157 | if (event->header.type == PERF_RECORD_SAMPLE) |
1156 | event__process_sample(event, self, md->counter); | 1158 | event__process_sample(event, &sample, self, md->counter); |
1157 | else | 1159 | else |
1158 | event__process(event, self); | 1160 | event__process(event, &sample, self); |
1159 | old += size; | 1161 | old += size; |
1160 | } | 1162 | } |
1161 | 1163 | ||
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index e437edb72417..deffb8c96071 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -14,7 +14,9 @@ | |||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include "debug.h" | 15 | #include "debug.h" |
16 | 16 | ||
17 | static int build_id__mark_dso_hit(event_t *event, struct perf_session *session) | 17 | static int build_id__mark_dso_hit(event_t *event, |
18 | struct sample_data *sample __used, | ||
19 | struct perf_session *session) | ||
18 | { | 20 | { |
19 | struct addr_location al; | 21 | struct addr_location al; |
20 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 22 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
@@ -35,7 +37,8 @@ static int build_id__mark_dso_hit(event_t *event, struct perf_session *session) | |||
35 | return 0; | 37 | return 0; |
36 | } | 38 | } |
37 | 39 | ||
38 | static int event__exit_del_thread(event_t *self, struct perf_session *session) | 40 | static int event__exit_del_thread(event_t *self, struct sample_data *sample __used, |
41 | struct perf_session *session) | ||
39 | { | 42 | { |
40 | struct thread *thread = perf_session__findnew(session, self->fork.tid); | 43 | struct thread *thread = perf_session__findnew(session, self->fork.tid); |
41 | 44 | ||
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 7260db75b93d..e4cdc1ebe0fb 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -24,11 +24,19 @@ const char *event__name[] = { | |||
24 | [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", | 24 | [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", |
25 | }; | 25 | }; |
26 | 26 | ||
27 | static pid_t event__synthesize_comm(pid_t pid, int full, | 27 | static struct sample_data synth_sample = { |
28 | .pid = -1, | ||
29 | .tid = -1, | ||
30 | .time = -1, | ||
31 | .stream_id = -1, | ||
32 | .cpu = -1, | ||
33 | .period = 1, | ||
34 | }; | ||
35 | |||
36 | static pid_t event__synthesize_comm(event_t *event, pid_t pid, int full, | ||
28 | event__handler_t process, | 37 | event__handler_t process, |
29 | struct perf_session *session) | 38 | struct perf_session *session) |
30 | { | 39 | { |
31 | event_t ev; | ||
32 | char filename[PATH_MAX]; | 40 | char filename[PATH_MAX]; |
33 | char bf[BUFSIZ]; | 41 | char bf[BUFSIZ]; |
34 | FILE *fp; | 42 | FILE *fp; |
@@ -49,34 +57,39 @@ out_race: | |||
49 | return 0; | 57 | return 0; |
50 | } | 58 | } |
51 | 59 | ||
52 | memset(&ev.comm, 0, sizeof(ev.comm)); | 60 | memset(&event->comm, 0, sizeof(event->comm)); |
53 | while (!ev.comm.comm[0] || !ev.comm.pid) { | 61 | |
54 | if (fgets(bf, sizeof(bf), fp) == NULL) | 62 | while (!event->comm.comm[0] || !event->comm.pid) { |
55 | goto out_failure; | 63 | if (fgets(bf, sizeof(bf), fp) == NULL) { |
64 | pr_warning("couldn't get COMM and pgid, malformed %s\n", filename); | ||
65 | goto out; | ||
66 | } | ||
56 | 67 | ||
57 | if (memcmp(bf, "Name:", 5) == 0) { | 68 | if (memcmp(bf, "Name:", 5) == 0) { |
58 | char *name = bf + 5; | 69 | char *name = bf + 5; |
59 | while (*name && isspace(*name)) | 70 | while (*name && isspace(*name)) |
60 | ++name; | 71 | ++name; |
61 | size = strlen(name) - 1; | 72 | size = strlen(name) - 1; |
62 | memcpy(ev.comm.comm, name, size++); | 73 | memcpy(event->comm.comm, name, size++); |
63 | } else if (memcmp(bf, "Tgid:", 5) == 0) { | 74 | } else if (memcmp(bf, "Tgid:", 5) == 0) { |
64 | char *tgids = bf + 5; | 75 | char *tgids = bf + 5; |
65 | while (*tgids && isspace(*tgids)) | 76 | while (*tgids && isspace(*tgids)) |
66 | ++tgids; | 77 | ++tgids; |
67 | tgid = ev.comm.pid = atoi(tgids); | 78 | tgid = event->comm.pid = atoi(tgids); |
68 | } | 79 | } |
69 | } | 80 | } |
70 | 81 | ||
71 | ev.comm.header.type = PERF_RECORD_COMM; | 82 | event->comm.header.type = PERF_RECORD_COMM; |
72 | size = ALIGN(size, sizeof(u64)); | 83 | size = ALIGN(size, sizeof(u64)); |
73 | ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size); | 84 | memset(event->comm.comm + size, 0, session->id_hdr_size); |
74 | 85 | event->comm.header.size = (sizeof(event->comm) - | |
86 | (sizeof(event->comm.comm) - size) + | ||
87 | session->id_hdr_size); | ||
75 | if (!full) { | 88 | if (!full) { |
76 | ev.comm.tid = pid; | 89 | event->comm.tid = pid; |
77 | 90 | ||
78 | process(&ev, session); | 91 | process(event, &synth_sample, session); |
79 | goto out_fclose; | 92 | goto out; |
80 | } | 93 | } |
81 | 94 | ||
82 | snprintf(filename, sizeof(filename), "/proc/%d/task", pid); | 95 | snprintf(filename, sizeof(filename), "/proc/%d/task", pid); |
@@ -91,22 +104,19 @@ out_race: | |||
91 | if (*end) | 104 | if (*end) |
92 | continue; | 105 | continue; |
93 | 106 | ||
94 | ev.comm.tid = pid; | 107 | event->comm.tid = pid; |
95 | 108 | ||
96 | process(&ev, session); | 109 | process(event, &synth_sample, session); |
97 | } | 110 | } |
98 | closedir(tasks); | ||
99 | 111 | ||
100 | out_fclose: | 112 | closedir(tasks); |
113 | out: | ||
101 | fclose(fp); | 114 | fclose(fp); |
102 | return tgid; | ||
103 | 115 | ||
104 | out_failure: | 116 | return tgid; |
105 | pr_warning("couldn't get COMM and pgid, malformed %s\n", filename); | ||
106 | return -1; | ||
107 | } | 117 | } |
108 | 118 | ||
109 | static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, | 119 | static int event__synthesize_mmap_events(event_t *event, pid_t pid, pid_t tgid, |
110 | event__handler_t process, | 120 | event__handler_t process, |
111 | struct perf_session *session) | 121 | struct perf_session *session) |
112 | { | 122 | { |
@@ -124,29 +134,25 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, | |||
124 | return -1; | 134 | return -1; |
125 | } | 135 | } |
126 | 136 | ||
137 | event->header.type = PERF_RECORD_MMAP; | ||
138 | /* | ||
139 | * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c | ||
140 | */ | ||
141 | event->header.misc = PERF_RECORD_MISC_USER; | ||
142 | |||
127 | while (1) { | 143 | while (1) { |
128 | char bf[BUFSIZ], *pbf = bf; | 144 | char bf[BUFSIZ], *pbf = bf; |
129 | event_t ev = { | ||
130 | .header = { | ||
131 | .type = PERF_RECORD_MMAP, | ||
132 | /* | ||
133 | * Just like the kernel, see __perf_event_mmap | ||
134 | * in kernel/perf_event.c | ||
135 | */ | ||
136 | .misc = PERF_RECORD_MISC_USER, | ||
137 | }, | ||
138 | }; | ||
139 | int n; | 145 | int n; |
140 | size_t size; | 146 | size_t size; |
141 | if (fgets(bf, sizeof(bf), fp) == NULL) | 147 | if (fgets(bf, sizeof(bf), fp) == NULL) |
142 | break; | 148 | break; |
143 | 149 | ||
144 | /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ | 150 | /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ |
145 | n = hex2u64(pbf, &ev.mmap.start); | 151 | n = hex2u64(pbf, &event->mmap.start); |
146 | if (n < 0) | 152 | if (n < 0) |
147 | continue; | 153 | continue; |
148 | pbf += n + 1; | 154 | pbf += n + 1; |
149 | n = hex2u64(pbf, &ev.mmap.len); | 155 | n = hex2u64(pbf, &event->mmap.len); |
150 | if (n < 0) | 156 | if (n < 0) |
151 | continue; | 157 | continue; |
152 | pbf += n + 3; | 158 | pbf += n + 3; |
@@ -161,19 +167,21 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, | |||
161 | continue; | 167 | continue; |
162 | 168 | ||
163 | pbf += 3; | 169 | pbf += 3; |
164 | n = hex2u64(pbf, &ev.mmap.pgoff); | 170 | n = hex2u64(pbf, &event->mmap.pgoff); |
165 | 171 | ||
166 | size = strlen(execname); | 172 | size = strlen(execname); |
167 | execname[size - 1] = '\0'; /* Remove \n */ | 173 | execname[size - 1] = '\0'; /* Remove \n */ |
168 | memcpy(ev.mmap.filename, execname, size); | 174 | memcpy(event->mmap.filename, execname, size); |
169 | size = ALIGN(size, sizeof(u64)); | 175 | size = ALIGN(size, sizeof(u64)); |
170 | ev.mmap.len -= ev.mmap.start; | 176 | event->mmap.len -= event->mmap.start; |
171 | ev.mmap.header.size = (sizeof(ev.mmap) - | 177 | event->mmap.header.size = (sizeof(event->mmap) - |
172 | (sizeof(ev.mmap.filename) - size)); | 178 | (sizeof(event->mmap.filename) - size)); |
173 | ev.mmap.pid = tgid; | 179 | memset(event->mmap.filename + size, 0, session->id_hdr_size); |
174 | ev.mmap.tid = pid; | 180 | event->mmap.header.size += session->id_hdr_size; |
175 | 181 | event->mmap.pid = tgid; | |
176 | process(&ev, session); | 182 | event->mmap.tid = pid; |
183 | |||
184 | process(event, &synth_sample, session); | ||
177 | } | 185 | } |
178 | } | 186 | } |
179 | 187 | ||
@@ -187,20 +195,27 @@ int event__synthesize_modules(event__handler_t process, | |||
187 | { | 195 | { |
188 | struct rb_node *nd; | 196 | struct rb_node *nd; |
189 | struct map_groups *kmaps = &machine->kmaps; | 197 | struct map_groups *kmaps = &machine->kmaps; |
190 | u16 misc; | 198 | event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size); |
199 | |||
200 | if (event == NULL) { | ||
201 | pr_debug("Not enough memory synthesizing mmap event " | ||
202 | "for kernel modules\n"); | ||
203 | return -1; | ||
204 | } | ||
205 | |||
206 | event->header.type = PERF_RECORD_MMAP; | ||
191 | 207 | ||
192 | /* | 208 | /* |
193 | * kernel uses 0 for user space maps, see kernel/perf_event.c | 209 | * kernel uses 0 for user space maps, see kernel/perf_event.c |
194 | * __perf_event_mmap | 210 | * __perf_event_mmap |
195 | */ | 211 | */ |
196 | if (machine__is_host(machine)) | 212 | if (machine__is_host(machine)) |
197 | misc = PERF_RECORD_MISC_KERNEL; | 213 | event->header.misc = PERF_RECORD_MISC_KERNEL; |
198 | else | 214 | else |
199 | misc = PERF_RECORD_MISC_GUEST_KERNEL; | 215 | event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; |
200 | 216 | ||
201 | for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]); | 217 | for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]); |
202 | nd; nd = rb_next(nd)) { | 218 | nd; nd = rb_next(nd)) { |
203 | event_t ev; | ||
204 | size_t size; | 219 | size_t size; |
205 | struct map *pos = rb_entry(nd, struct map, rb_node); | 220 | struct map *pos = rb_entry(nd, struct map, rb_node); |
206 | 221 | ||
@@ -208,39 +223,78 @@ int event__synthesize_modules(event__handler_t process, | |||
208 | continue; | 223 | continue; |
209 | 224 | ||
210 | size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); | 225 | size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); |
211 | memset(&ev, 0, sizeof(ev)); | 226 | event->mmap.header.type = PERF_RECORD_MMAP; |
212 | ev.mmap.header.misc = misc; | 227 | event->mmap.header.size = (sizeof(event->mmap) - |
213 | ev.mmap.header.type = PERF_RECORD_MMAP; | 228 | (sizeof(event->mmap.filename) - size)); |
214 | ev.mmap.header.size = (sizeof(ev.mmap) - | 229 | memset(event->mmap.filename + size, 0, session->id_hdr_size); |
215 | (sizeof(ev.mmap.filename) - size)); | 230 | event->mmap.header.size += session->id_hdr_size; |
216 | ev.mmap.start = pos->start; | 231 | event->mmap.start = pos->start; |
217 | ev.mmap.len = pos->end - pos->start; | 232 | event->mmap.len = pos->end - pos->start; |
218 | ev.mmap.pid = machine->pid; | 233 | event->mmap.pid = machine->pid; |
219 | 234 | ||
220 | memcpy(ev.mmap.filename, pos->dso->long_name, | 235 | memcpy(event->mmap.filename, pos->dso->long_name, |
221 | pos->dso->long_name_len + 1); | 236 | pos->dso->long_name_len + 1); |
222 | process(&ev, session); | 237 | process(event, &synth_sample, session); |
223 | } | 238 | } |
224 | 239 | ||
240 | free(event); | ||
225 | return 0; | 241 | return 0; |
226 | } | 242 | } |
227 | 243 | ||
228 | int event__synthesize_thread(pid_t pid, event__handler_t process, | 244 | static int __event__synthesize_thread(event_t *comm_event, event_t *mmap_event, |
229 | struct perf_session *session) | 245 | pid_t pid, event__handler_t process, |
246 | struct perf_session *session) | ||
230 | { | 247 | { |
231 | pid_t tgid = event__synthesize_comm(pid, 1, process, session); | 248 | pid_t tgid = event__synthesize_comm(comm_event, pid, 1, process, |
249 | session); | ||
232 | if (tgid == -1) | 250 | if (tgid == -1) |
233 | return -1; | 251 | return -1; |
234 | return event__synthesize_mmap_events(pid, tgid, process, session); | 252 | return event__synthesize_mmap_events(mmap_event, pid, tgid, |
253 | process, session); | ||
254 | } | ||
255 | |||
256 | int event__synthesize_thread(pid_t pid, event__handler_t process, | ||
257 | struct perf_session *session) | ||
258 | { | ||
259 | event_t *comm_event, *mmap_event; | ||
260 | int err = -1; | ||
261 | |||
262 | comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); | ||
263 | if (comm_event == NULL) | ||
264 | goto out; | ||
265 | |||
266 | mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size); | ||
267 | if (mmap_event == NULL) | ||
268 | goto out_free_comm; | ||
269 | |||
270 | err = __event__synthesize_thread(comm_event, mmap_event, pid, | ||
271 | process, session); | ||
272 | free(mmap_event); | ||
273 | out_free_comm: | ||
274 | free(comm_event); | ||
275 | out: | ||
276 | return err; | ||
235 | } | 277 | } |
236 | 278 | ||
237 | void event__synthesize_threads(event__handler_t process, | 279 | int event__synthesize_threads(event__handler_t process, |
238 | struct perf_session *session) | 280 | struct perf_session *session) |
239 | { | 281 | { |
240 | DIR *proc; | 282 | DIR *proc; |
241 | struct dirent dirent, *next; | 283 | struct dirent dirent, *next; |
284 | event_t *comm_event, *mmap_event; | ||
285 | int err = -1; | ||
286 | |||
287 | comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); | ||
288 | if (comm_event == NULL) | ||
289 | goto out; | ||
290 | |||
291 | mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size); | ||
292 | if (mmap_event == NULL) | ||
293 | goto out_free_comm; | ||
242 | 294 | ||
243 | proc = opendir("/proc"); | 295 | proc = opendir("/proc"); |
296 | if (proc == NULL) | ||
297 | goto out_free_mmap; | ||
244 | 298 | ||
245 | while (!readdir_r(proc, &dirent, &next) && next) { | 299 | while (!readdir_r(proc, &dirent, &next) && next) { |
246 | char *end; | 300 | char *end; |
@@ -249,10 +303,18 @@ void event__synthesize_threads(event__handler_t process, | |||
249 | if (*end) /* only interested in proper numerical dirents */ | 303 | if (*end) /* only interested in proper numerical dirents */ |
250 | continue; | 304 | continue; |
251 | 305 | ||
252 | event__synthesize_thread(pid, process, session); | 306 | __event__synthesize_thread(comm_event, mmap_event, pid, |
307 | process, session); | ||
253 | } | 308 | } |
254 | 309 | ||
255 | closedir(proc); | 310 | closedir(proc); |
311 | err = 0; | ||
312 | out_free_mmap: | ||
313 | free(mmap_event); | ||
314 | out_free_comm: | ||
315 | free(comm_event); | ||
316 | out: | ||
317 | return err; | ||
256 | } | 318 | } |
257 | 319 | ||
258 | struct process_symbol_args { | 320 | struct process_symbol_args { |
@@ -286,18 +348,20 @@ int event__synthesize_kernel_mmap(event__handler_t process, | |||
286 | char path[PATH_MAX]; | 348 | char path[PATH_MAX]; |
287 | char name_buff[PATH_MAX]; | 349 | char name_buff[PATH_MAX]; |
288 | struct map *map; | 350 | struct map *map; |
289 | 351 | int err; | |
290 | event_t ev = { | ||
291 | .header = { | ||
292 | .type = PERF_RECORD_MMAP, | ||
293 | }, | ||
294 | }; | ||
295 | /* | 352 | /* |
296 | * We should get this from /sys/kernel/sections/.text, but till that is | 353 | * We should get this from /sys/kernel/sections/.text, but till that is |
297 | * available use this, and after it is use this as a fallback for older | 354 | * available use this, and after it is use this as a fallback for older |
298 | * kernels. | 355 | * kernels. |
299 | */ | 356 | */ |
300 | struct process_symbol_args args = { .name = symbol_name, }; | 357 | struct process_symbol_args args = { .name = symbol_name, }; |
358 | event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size); | ||
359 | |||
360 | if (event == NULL) { | ||
361 | pr_debug("Not enough memory synthesizing mmap event " | ||
362 | "for kernel modules\n"); | ||
363 | return -1; | ||
364 | } | ||
301 | 365 | ||
302 | mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff)); | 366 | mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff)); |
303 | if (machine__is_host(machine)) { | 367 | if (machine__is_host(machine)) { |
@@ -305,10 +369,10 @@ int event__synthesize_kernel_mmap(event__handler_t process, | |||
305 | * kernel uses PERF_RECORD_MISC_USER for user space maps, | 369 | * kernel uses PERF_RECORD_MISC_USER for user space maps, |
306 | * see kernel/perf_event.c __perf_event_mmap | 370 | * see kernel/perf_event.c __perf_event_mmap |
307 | */ | 371 | */ |
308 | ev.header.misc = PERF_RECORD_MISC_KERNEL; | 372 | event->header.misc = PERF_RECORD_MISC_KERNEL; |
309 | filename = "/proc/kallsyms"; | 373 | filename = "/proc/kallsyms"; |
310 | } else { | 374 | } else { |
311 | ev.header.misc = PERF_RECORD_MISC_GUEST_KERNEL; | 375 | event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; |
312 | if (machine__is_default_guest(machine)) | 376 | if (machine__is_default_guest(machine)) |
313 | filename = (char *) symbol_conf.default_guest_kallsyms; | 377 | filename = (char *) symbol_conf.default_guest_kallsyms; |
314 | else { | 378 | else { |
@@ -321,17 +385,21 @@ int event__synthesize_kernel_mmap(event__handler_t process, | |||
321 | return -ENOENT; | 385 | return -ENOENT; |
322 | 386 | ||
323 | map = machine->vmlinux_maps[MAP__FUNCTION]; | 387 | map = machine->vmlinux_maps[MAP__FUNCTION]; |
324 | size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename), | 388 | size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), |
325 | "%s%s", mmap_name, symbol_name) + 1; | 389 | "%s%s", mmap_name, symbol_name) + 1; |
326 | size = ALIGN(size, sizeof(u64)); | 390 | size = ALIGN(size, sizeof(u64)); |
327 | ev.mmap.header.size = (sizeof(ev.mmap) - | 391 | event->mmap.header.type = PERF_RECORD_MMAP; |
328 | (sizeof(ev.mmap.filename) - size)); | 392 | event->mmap.header.size = (sizeof(event->mmap) - |
329 | ev.mmap.pgoff = args.start; | 393 | (sizeof(event->mmap.filename) - size) + session->id_hdr_size); |
330 | ev.mmap.start = map->start; | 394 | event->mmap.pgoff = args.start; |
331 | ev.mmap.len = map->end - ev.mmap.start; | 395 | event->mmap.start = map->start; |
332 | ev.mmap.pid = machine->pid; | 396 | event->mmap.len = map->end - event->mmap.start; |
333 | 397 | event->mmap.pid = machine->pid; | |
334 | return process(&ev, session); | 398 | |
399 | err = process(event, &synth_sample, session); | ||
400 | free(event); | ||
401 | |||
402 | return err; | ||
335 | } | 403 | } |
336 | 404 | ||
337 | static void thread__comm_adjust(struct thread *self, struct hists *hists) | 405 | static void thread__comm_adjust(struct thread *self, struct hists *hists) |
@@ -361,7 +429,8 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm, | |||
361 | return 0; | 429 | return 0; |
362 | } | 430 | } |
363 | 431 | ||
364 | int event__process_comm(event_t *self, struct perf_session *session) | 432 | int event__process_comm(event_t *self, struct sample_data *sample __used, |
433 | struct perf_session *session) | ||
365 | { | 434 | { |
366 | struct thread *thread = perf_session__findnew(session, self->comm.tid); | 435 | struct thread *thread = perf_session__findnew(session, self->comm.tid); |
367 | 436 | ||
@@ -376,7 +445,8 @@ int event__process_comm(event_t *self, struct perf_session *session) | |||
376 | return 0; | 445 | return 0; |
377 | } | 446 | } |
378 | 447 | ||
379 | int event__process_lost(event_t *self, struct perf_session *session) | 448 | int event__process_lost(event_t *self, struct sample_data *sample __used, |
449 | struct perf_session *session) | ||
380 | { | 450 | { |
381 | dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); | 451 | dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); |
382 | session->hists.stats.total_lost += self->lost.lost; | 452 | session->hists.stats.total_lost += self->lost.lost; |
@@ -485,7 +555,8 @@ out_problem: | |||
485 | return -1; | 555 | return -1; |
486 | } | 556 | } |
487 | 557 | ||
488 | int event__process_mmap(event_t *self, struct perf_session *session) | 558 | int event__process_mmap(event_t *self, struct sample_data *sample __used, |
559 | struct perf_session *session) | ||
489 | { | 560 | { |
490 | struct machine *machine; | 561 | struct machine *machine; |
491 | struct thread *thread; | 562 | struct thread *thread; |
@@ -526,7 +597,8 @@ out_problem: | |||
526 | return 0; | 597 | return 0; |
527 | } | 598 | } |
528 | 599 | ||
529 | int event__process_task(event_t *self, struct perf_session *session) | 600 | int event__process_task(event_t *self, struct sample_data *sample __used, |
601 | struct perf_session *session) | ||
530 | { | 602 | { |
531 | struct thread *thread = perf_session__findnew(session, self->fork.tid); | 603 | struct thread *thread = perf_session__findnew(session, self->fork.tid); |
532 | struct thread *parent = perf_session__findnew(session, self->fork.ptid); | 604 | struct thread *parent = perf_session__findnew(session, self->fork.ptid); |
@@ -548,18 +620,19 @@ int event__process_task(event_t *self, struct perf_session *session) | |||
548 | return 0; | 620 | return 0; |
549 | } | 621 | } |
550 | 622 | ||
551 | int event__process(event_t *event, struct perf_session *session) | 623 | int event__process(event_t *event, struct sample_data *sample, |
624 | struct perf_session *session) | ||
552 | { | 625 | { |
553 | switch (event->header.type) { | 626 | switch (event->header.type) { |
554 | case PERF_RECORD_COMM: | 627 | case PERF_RECORD_COMM: |
555 | event__process_comm(event, session); | 628 | event__process_comm(event, sample, session); |
556 | break; | 629 | break; |
557 | case PERF_RECORD_MMAP: | 630 | case PERF_RECORD_MMAP: |
558 | event__process_mmap(event, session); | 631 | event__process_mmap(event, sample, session); |
559 | break; | 632 | break; |
560 | case PERF_RECORD_FORK: | 633 | case PERF_RECORD_FORK: |
561 | case PERF_RECORD_EXIT: | 634 | case PERF_RECORD_EXIT: |
562 | event__process_task(event, session); | 635 | event__process_task(event, sample, session); |
563 | break; | 636 | break; |
564 | default: | 637 | default: |
565 | break; | 638 | break; |
@@ -674,32 +747,8 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session, | |||
674 | symbol_filter_t filter) | 747 | symbol_filter_t filter) |
675 | { | 748 | { |
676 | u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 749 | u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
677 | struct thread *thread; | 750 | struct thread *thread = perf_session__findnew(session, self->ip.pid); |
678 | |||
679 | event__parse_sample(self, session->sample_type, data); | ||
680 | 751 | ||
681 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld cpu:%d\n", | ||
682 | self->header.misc, data->pid, data->tid, data->ip, | ||
683 | data->period, data->cpu); | ||
684 | |||
685 | if (session->sample_type & PERF_SAMPLE_CALLCHAIN) { | ||
686 | unsigned int i; | ||
687 | |||
688 | dump_printf("... chain: nr:%Lu\n", data->callchain->nr); | ||
689 | |||
690 | if (!ip_callchain__valid(data->callchain, self)) { | ||
691 | pr_debug("call-chain problem with event, " | ||
692 | "skipping it.\n"); | ||
693 | goto out_filtered; | ||
694 | } | ||
695 | |||
696 | if (dump_trace) { | ||
697 | for (i = 0; i < data->callchain->nr; i++) | ||
698 | dump_printf("..... %2d: %016Lx\n", | ||
699 | i, data->callchain->ips[i]); | ||
700 | } | ||
701 | } | ||
702 | thread = perf_session__findnew(session, self->ip.pid); | ||
703 | if (thread == NULL) | 752 | if (thread == NULL) |
704 | return -1; | 753 | return -1; |
705 | 754 | ||
@@ -766,9 +815,65 @@ out_filtered: | |||
766 | return 0; | 815 | return 0; |
767 | } | 816 | } |
768 | 817 | ||
769 | int event__parse_sample(const event_t *event, u64 type, struct sample_data *data) | 818 | static int event__parse_id_sample(const event_t *event, |
819 | struct perf_session *session, | ||
820 | struct sample_data *sample) | ||
770 | { | 821 | { |
771 | const u64 *array = event->sample.array; | 822 | const u64 *array; |
823 | u64 type; | ||
824 | |||
825 | sample->cpu = sample->pid = sample->tid = -1; | ||
826 | sample->stream_id = sample->id = sample->time = -1ULL; | ||
827 | |||
828 | if (!session->sample_id_all) | ||
829 | return 0; | ||
830 | |||
831 | array = event->sample.array; | ||
832 | array += ((event->header.size - | ||
833 | sizeof(event->header)) / sizeof(u64)) - 1; | ||
834 | type = session->sample_type; | ||
835 | |||
836 | if (type & PERF_SAMPLE_CPU) { | ||
837 | u32 *p = (u32 *)array; | ||
838 | sample->cpu = *p; | ||
839 | array--; | ||
840 | } | ||
841 | |||
842 | if (type & PERF_SAMPLE_STREAM_ID) { | ||
843 | sample->stream_id = *array; | ||
844 | array--; | ||
845 | } | ||
846 | |||
847 | if (type & PERF_SAMPLE_ID) { | ||
848 | sample->id = *array; | ||
849 | array--; | ||
850 | } | ||
851 | |||
852 | if (type & PERF_SAMPLE_TIME) { | ||
853 | sample->time = *array; | ||
854 | array--; | ||
855 | } | ||
856 | |||
857 | if (type & PERF_SAMPLE_TID) { | ||
858 | u32 *p = (u32 *)array; | ||
859 | sample->pid = p[0]; | ||
860 | sample->tid = p[1]; | ||
861 | } | ||
862 | |||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | int event__parse_sample(const event_t *event, struct perf_session *session, | ||
867 | struct sample_data *data) | ||
868 | { | ||
869 | const u64 *array; | ||
870 | u64 type; | ||
871 | |||
872 | if (event->header.type != PERF_RECORD_SAMPLE) | ||
873 | return event__parse_id_sample(event, session, data); | ||
874 | |||
875 | array = event->sample.array; | ||
876 | type = session->sample_type; | ||
772 | 877 | ||
773 | if (type & PERF_SAMPLE_IP) { | 878 | if (type & PERF_SAMPLE_IP) { |
774 | data->ip = event->ip.ip; | 879 | data->ip = event->ip.ip; |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 8e790dae7026..a95ab18575ce 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -135,12 +135,15 @@ void event__print_totals(void); | |||
135 | 135 | ||
136 | struct perf_session; | 136 | struct perf_session; |
137 | 137 | ||
138 | typedef int (*event__handler_t)(event_t *event, struct perf_session *session); | 138 | typedef int (*event__handler_synth_t)(event_t *event, |
139 | struct perf_session *session); | ||
140 | typedef int (*event__handler_t)(event_t *event, struct sample_data *sample, | ||
141 | struct perf_session *session); | ||
139 | 142 | ||
140 | int event__synthesize_thread(pid_t pid, event__handler_t process, | 143 | int event__synthesize_thread(pid_t pid, event__handler_t process, |
141 | struct perf_session *session); | 144 | struct perf_session *session); |
142 | void event__synthesize_threads(event__handler_t process, | 145 | int event__synthesize_threads(event__handler_t process, |
143 | struct perf_session *session); | 146 | struct perf_session *session); |
144 | int event__synthesize_kernel_mmap(event__handler_t process, | 147 | int event__synthesize_kernel_mmap(event__handler_t process, |
145 | struct perf_session *session, | 148 | struct perf_session *session, |
146 | struct machine *machine, | 149 | struct machine *machine, |
@@ -150,17 +153,23 @@ int event__synthesize_modules(event__handler_t process, | |||
150 | struct perf_session *session, | 153 | struct perf_session *session, |
151 | struct machine *machine); | 154 | struct machine *machine); |
152 | 155 | ||
153 | int event__process_comm(event_t *self, struct perf_session *session); | 156 | int event__process_comm(event_t *self, struct sample_data *sample, |
154 | int event__process_lost(event_t *self, struct perf_session *session); | 157 | struct perf_session *session); |
155 | int event__process_mmap(event_t *self, struct perf_session *session); | 158 | int event__process_lost(event_t *self, struct sample_data *sample, |
156 | int event__process_task(event_t *self, struct perf_session *session); | 159 | struct perf_session *session); |
157 | int event__process(event_t *event, struct perf_session *session); | 160 | int event__process_mmap(event_t *self, struct sample_data *sample, |
161 | struct perf_session *session); | ||
162 | int event__process_task(event_t *self, struct sample_data *sample, | ||
163 | struct perf_session *session); | ||
164 | int event__process(event_t *event, struct sample_data *sample, | ||
165 | struct perf_session *session); | ||
158 | 166 | ||
159 | struct addr_location; | 167 | struct addr_location; |
160 | int event__preprocess_sample(const event_t *self, struct perf_session *session, | 168 | int event__preprocess_sample(const event_t *self, struct perf_session *session, |
161 | struct addr_location *al, struct sample_data *data, | 169 | struct addr_location *al, struct sample_data *data, |
162 | symbol_filter_t filter); | 170 | symbol_filter_t filter); |
163 | int event__parse_sample(const event_t *event, u64 type, struct sample_data *data); | 171 | int event__parse_sample(const event_t *event, struct perf_session *session, |
172 | struct sample_data *sample); | ||
164 | 173 | ||
165 | extern const char *event__name[]; | 174 | extern const char *event__name[]; |
166 | 175 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index f65d7dc127b6..76e949a59ea4 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -946,6 +946,24 @@ u64 perf_header__sample_type(struct perf_header *header) | |||
946 | return type; | 946 | return type; |
947 | } | 947 | } |
948 | 948 | ||
949 | bool perf_header__sample_id_all(const struct perf_header *header) | ||
950 | { | ||
951 | bool value = false, first = true; | ||
952 | int i; | ||
953 | |||
954 | for (i = 0; i < header->attrs; i++) { | ||
955 | struct perf_header_attr *attr = header->attr[i]; | ||
956 | |||
957 | if (first) { | ||
958 | value = attr->attr.sample_id_all; | ||
959 | first = false; | ||
960 | } else if (value != attr->attr.sample_id_all) | ||
961 | die("non matching sample_id_all"); | ||
962 | } | ||
963 | |||
964 | return value; | ||
965 | } | ||
966 | |||
949 | struct perf_event_attr * | 967 | struct perf_event_attr * |
950 | perf_header__find_attr(u64 id, struct perf_header *header) | 968 | perf_header__find_attr(u64 id, struct perf_header *header) |
951 | { | 969 | { |
@@ -987,21 +1005,23 @@ int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | |||
987 | 1005 | ||
988 | ev = malloc(size); | 1006 | ev = malloc(size); |
989 | 1007 | ||
1008 | if (ev == NULL) | ||
1009 | return -ENOMEM; | ||
1010 | |||
990 | ev->attr.attr = *attr; | 1011 | ev->attr.attr = *attr; |
991 | memcpy(ev->attr.id, id, ids * sizeof(u64)); | 1012 | memcpy(ev->attr.id, id, ids * sizeof(u64)); |
992 | 1013 | ||
993 | ev->attr.header.type = PERF_RECORD_HEADER_ATTR; | 1014 | ev->attr.header.type = PERF_RECORD_HEADER_ATTR; |
994 | ev->attr.header.size = size; | 1015 | ev->attr.header.size = size; |
995 | 1016 | ||
996 | err = process(ev, session); | 1017 | err = process(ev, NULL, session); |
997 | 1018 | ||
998 | free(ev); | 1019 | free(ev); |
999 | 1020 | ||
1000 | return err; | 1021 | return err; |
1001 | } | 1022 | } |
1002 | 1023 | ||
1003 | int event__synthesize_attrs(struct perf_header *self, | 1024 | int event__synthesize_attrs(struct perf_header *self, event__handler_t process, |
1004 | event__handler_t process, | ||
1005 | struct perf_session *session) | 1025 | struct perf_session *session) |
1006 | { | 1026 | { |
1007 | struct perf_header_attr *attr; | 1027 | struct perf_header_attr *attr; |
@@ -1071,7 +1091,7 @@ int event__synthesize_event_type(u64 event_id, char *name, | |||
1071 | ev.event_type.header.size = sizeof(ev.event_type) - | 1091 | ev.event_type.header.size = sizeof(ev.event_type) - |
1072 | (sizeof(ev.event_type.event_type.name) - size); | 1092 | (sizeof(ev.event_type.event_type.name) - size); |
1073 | 1093 | ||
1074 | err = process(&ev, session); | 1094 | err = process(&ev, NULL, session); |
1075 | 1095 | ||
1076 | return err; | 1096 | return err; |
1077 | } | 1097 | } |
@@ -1126,7 +1146,7 @@ int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs, | |||
1126 | ev.tracing_data.header.size = sizeof(ev.tracing_data); | 1146 | ev.tracing_data.header.size = sizeof(ev.tracing_data); |
1127 | ev.tracing_data.size = aligned_size; | 1147 | ev.tracing_data.size = aligned_size; |
1128 | 1148 | ||
1129 | process(&ev, session); | 1149 | process(&ev, NULL, session); |
1130 | 1150 | ||
1131 | err = read_tracing_data(fd, pattrs, nb_events); | 1151 | err = read_tracing_data(fd, pattrs, nb_events); |
1132 | write_padded(fd, NULL, 0, padding); | 1152 | write_padded(fd, NULL, 0, padding); |
@@ -1186,7 +1206,7 @@ int event__synthesize_build_id(struct dso *pos, u16 misc, | |||
1186 | ev.build_id.header.size = sizeof(ev.build_id) + len; | 1206 | ev.build_id.header.size = sizeof(ev.build_id) + len; |
1187 | memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); | 1207 | memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); |
1188 | 1208 | ||
1189 | err = process(&ev, session); | 1209 | err = process(&ev, NULL, session); |
1190 | 1210 | ||
1191 | return err; | 1211 | return err; |
1192 | } | 1212 | } |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index ed550bffd655..6335965e1f93 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -81,6 +81,7 @@ void perf_header_attr__delete(struct perf_header_attr *self); | |||
81 | int perf_header_attr__add_id(struct perf_header_attr *self, u64 id); | 81 | int perf_header_attr__add_id(struct perf_header_attr *self, u64 id); |
82 | 82 | ||
83 | u64 perf_header__sample_type(struct perf_header *header); | 83 | u64 perf_header__sample_type(struct perf_header *header); |
84 | bool perf_header__sample_id_all(const struct perf_header *header); | ||
84 | struct perf_event_attr * | 85 | struct perf_event_attr * |
85 | perf_header__find_attr(u64 id, struct perf_header *header); | 86 | perf_header__find_attr(u64 id, struct perf_header *header); |
86 | void perf_header__set_feat(struct perf_header *self, int feat); | 87 | void perf_header__set_feat(struct perf_header *self, int feat); |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 587d375d3430..ee789856a8c9 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -52,8 +52,10 @@ struct sym_priv { | |||
52 | struct events_stats { | 52 | struct events_stats { |
53 | u64 total_period; | 53 | u64 total_period; |
54 | u64 total_lost; | 54 | u64 total_lost; |
55 | u64 total_invalid_chains; | ||
55 | u32 nr_events[PERF_RECORD_HEADER_MAX]; | 56 | u32 nr_events[PERF_RECORD_HEADER_MAX]; |
56 | u32 nr_unknown_events; | 57 | u32 nr_unknown_events; |
58 | u32 nr_invalid_chains; | ||
57 | }; | 59 | }; |
58 | 60 | ||
59 | enum hist_column { | 61 | enum hist_column { |
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h index c7d72dce54b2..abc31a1dac1a 100644 --- a/tools/perf/util/parse-options.h +++ b/tools/perf/util/parse-options.h | |||
@@ -119,6 +119,10 @@ struct option { | |||
119 | { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG } | 119 | { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG } |
120 | #define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \ | 120 | #define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \ |
121 | { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT } | 121 | { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT } |
122 | #define OPT_CALLBACK_DEFAULT_NOOPT(s, l, v, a, h, f, d) \ | ||
123 | { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\ | ||
124 | .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\ | ||
125 | .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG} | ||
122 | 126 | ||
123 | /* parse_options() will filter out the processed options and leave the | 127 | /* parse_options() will filter out the processed options and leave the |
124 | * non-option argments in argv[]. | 128 | * non-option argments in argv[]. |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 52672dad1fe9..3074d38897e6 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -65,9 +65,49 @@ out_close: | |||
65 | return -1; | 65 | return -1; |
66 | } | 66 | } |
67 | 67 | ||
68 | static void perf_session__id_header_size(struct perf_session *session) | ||
69 | { | ||
70 | struct sample_data *data; | ||
71 | u64 sample_type = session->sample_type; | ||
72 | u16 size = 0; | ||
73 | |||
74 | if (!session->sample_id_all) | ||
75 | goto out; | ||
76 | |||
77 | if (sample_type & PERF_SAMPLE_TID) | ||
78 | size += sizeof(data->tid) * 2; | ||
79 | |||
80 | if (sample_type & PERF_SAMPLE_TIME) | ||
81 | size += sizeof(data->time); | ||
82 | |||
83 | if (sample_type & PERF_SAMPLE_ID) | ||
84 | size += sizeof(data->id); | ||
85 | |||
86 | if (sample_type & PERF_SAMPLE_STREAM_ID) | ||
87 | size += sizeof(data->stream_id); | ||
88 | |||
89 | if (sample_type & PERF_SAMPLE_CPU) | ||
90 | size += sizeof(data->cpu) * 2; | ||
91 | out: | ||
92 | session->id_hdr_size = size; | ||
93 | } | ||
94 | |||
95 | void perf_session__set_sample_id_all(struct perf_session *session, bool value) | ||
96 | { | ||
97 | session->sample_id_all = value; | ||
98 | perf_session__id_header_size(session); | ||
99 | } | ||
100 | |||
101 | void perf_session__set_sample_type(struct perf_session *session, u64 type) | ||
102 | { | ||
103 | session->sample_type = type; | ||
104 | } | ||
105 | |||
68 | void perf_session__update_sample_type(struct perf_session *self) | 106 | void perf_session__update_sample_type(struct perf_session *self) |
69 | { | 107 | { |
70 | self->sample_type = perf_header__sample_type(&self->header); | 108 | self->sample_type = perf_header__sample_type(&self->header); |
109 | self->sample_id_all = perf_header__sample_id_all(&self->header); | ||
110 | perf_session__id_header_size(self); | ||
71 | } | 111 | } |
72 | 112 | ||
73 | int perf_session__create_kernel_maps(struct perf_session *self) | 113 | int perf_session__create_kernel_maps(struct perf_session *self) |
@@ -240,7 +280,15 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, | |||
240 | return syms; | 280 | return syms; |
241 | } | 281 | } |
242 | 282 | ||
283 | static int process_event_synth_stub(event_t *event __used, | ||
284 | struct perf_session *session __used) | ||
285 | { | ||
286 | dump_printf(": unhandled!\n"); | ||
287 | return 0; | ||
288 | } | ||
289 | |||
243 | static int process_event_stub(event_t *event __used, | 290 | static int process_event_stub(event_t *event __used, |
291 | struct sample_data *sample __used, | ||
244 | struct perf_session *session __used) | 292 | struct perf_session *session __used) |
245 | { | 293 | { |
246 | dump_printf(": unhandled!\n"); | 294 | dump_printf(": unhandled!\n"); |
@@ -280,13 +328,13 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) | |||
280 | if (handler->unthrottle == NULL) | 328 | if (handler->unthrottle == NULL) |
281 | handler->unthrottle = process_event_stub; | 329 | handler->unthrottle = process_event_stub; |
282 | if (handler->attr == NULL) | 330 | if (handler->attr == NULL) |
283 | handler->attr = process_event_stub; | 331 | handler->attr = process_event_synth_stub; |
284 | if (handler->event_type == NULL) | 332 | if (handler->event_type == NULL) |
285 | handler->event_type = process_event_stub; | 333 | handler->event_type = process_event_synth_stub; |
286 | if (handler->tracing_data == NULL) | 334 | if (handler->tracing_data == NULL) |
287 | handler->tracing_data = process_event_stub; | 335 | handler->tracing_data = process_event_synth_stub; |
288 | if (handler->build_id == NULL) | 336 | if (handler->build_id == NULL) |
289 | handler->build_id = process_event_stub; | 337 | handler->build_id = process_event_synth_stub; |
290 | if (handler->finished_round == NULL) { | 338 | if (handler->finished_round == NULL) { |
291 | if (handler->ordered_samples) | 339 | if (handler->ordered_samples) |
292 | handler->finished_round = process_finished_round; | 340 | handler->finished_round = process_finished_round; |
@@ -413,12 +461,18 @@ static void perf_session_free_sample_buffers(struct perf_session *session) | |||
413 | } | 461 | } |
414 | } | 462 | } |
415 | 463 | ||
464 | static int perf_session_deliver_event(struct perf_session *session, | ||
465 | event_t *event, | ||
466 | struct sample_data *sample, | ||
467 | struct perf_event_ops *ops); | ||
468 | |||
416 | static void flush_sample_queue(struct perf_session *s, | 469 | static void flush_sample_queue(struct perf_session *s, |
417 | struct perf_event_ops *ops) | 470 | struct perf_event_ops *ops) |
418 | { | 471 | { |
419 | struct ordered_samples *os = &s->ordered_samples; | 472 | struct ordered_samples *os = &s->ordered_samples; |
420 | struct list_head *head = &os->samples; | 473 | struct list_head *head = &os->samples; |
421 | struct sample_queue *tmp, *iter; | 474 | struct sample_queue *tmp, *iter; |
475 | struct sample_data sample; | ||
422 | u64 limit = os->next_flush; | 476 | u64 limit = os->next_flush; |
423 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; | 477 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; |
424 | 478 | ||
@@ -429,7 +483,8 @@ static void flush_sample_queue(struct perf_session *s, | |||
429 | if (iter->timestamp > limit) | 483 | if (iter->timestamp > limit) |
430 | break; | 484 | break; |
431 | 485 | ||
432 | ops->sample(iter->event, s); | 486 | event__parse_sample(iter->event, s, &sample); |
487 | perf_session_deliver_event(s, iter->event, &sample, ops); | ||
433 | 488 | ||
434 | os->last_flush = iter->timestamp; | 489 | os->last_flush = iter->timestamp; |
435 | list_del(&iter->list); | 490 | list_del(&iter->list); |
@@ -494,8 +549,7 @@ static int process_finished_round(event_t *event __used, | |||
494 | } | 549 | } |
495 | 550 | ||
496 | /* The queue is ordered by time */ | 551 | /* The queue is ordered by time */ |
497 | static void __queue_sample_event(struct sample_queue *new, | 552 | static void __queue_event(struct sample_queue *new, struct perf_session *s) |
498 | struct perf_session *s) | ||
499 | { | 553 | { |
500 | struct ordered_samples *os = &s->ordered_samples; | 554 | struct ordered_samples *os = &s->ordered_samples; |
501 | struct sample_queue *sample = os->last_sample; | 555 | struct sample_queue *sample = os->last_sample; |
@@ -541,14 +595,17 @@ static void __queue_sample_event(struct sample_queue *new, | |||
541 | 595 | ||
542 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) | 596 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) |
543 | 597 | ||
544 | static int queue_sample_event(event_t *event, struct sample_data *data, | 598 | static int perf_session_queue_event(struct perf_session *s, event_t *event, |
545 | struct perf_session *s) | 599 | struct sample_data *data) |
546 | { | 600 | { |
547 | struct ordered_samples *os = &s->ordered_samples; | 601 | struct ordered_samples *os = &s->ordered_samples; |
548 | struct list_head *sc = &os->sample_cache; | 602 | struct list_head *sc = &os->sample_cache; |
549 | u64 timestamp = data->time; | 603 | u64 timestamp = data->time; |
550 | struct sample_queue *new; | 604 | struct sample_queue *new; |
551 | 605 | ||
606 | if (!timestamp) | ||
607 | return -ETIME; | ||
608 | |||
552 | if (timestamp < s->ordered_samples.last_flush) { | 609 | if (timestamp < s->ordered_samples.last_flush) { |
553 | printf("Warning: Timestamp below last timeslice flush\n"); | 610 | printf("Warning: Timestamp below last timeslice flush\n"); |
554 | return -EINVAL; | 611 | return -EINVAL; |
@@ -573,79 +630,142 @@ static int queue_sample_event(event_t *event, struct sample_data *data, | |||
573 | new->timestamp = timestamp; | 630 | new->timestamp = timestamp; |
574 | new->event = event; | 631 | new->event = event; |
575 | 632 | ||
576 | __queue_sample_event(new, s); | 633 | __queue_event(new, s); |
577 | 634 | ||
578 | return 0; | 635 | return 0; |
579 | } | 636 | } |
580 | 637 | ||
581 | static int perf_session__process_sample(event_t *event, struct perf_session *s, | 638 | static void callchain__dump(struct sample_data *sample) |
582 | struct perf_event_ops *ops) | ||
583 | { | 639 | { |
584 | struct sample_data data; | 640 | unsigned int i; |
585 | |||
586 | if (!ops->ordered_samples) | ||
587 | return ops->sample(event, s); | ||
588 | 641 | ||
589 | bzero(&data, sizeof(struct sample_data)); | 642 | if (!dump_trace) |
590 | event__parse_sample(event, s->sample_type, &data); | 643 | return; |
591 | 644 | ||
592 | queue_sample_event(event, &data, s); | 645 | printf("... chain: nr:%Lu\n", sample->callchain->nr); |
593 | 646 | ||
594 | return 0; | 647 | for (i = 0; i < sample->callchain->nr; i++) |
648 | printf("..... %2d: %016Lx\n", i, sample->callchain->ips[i]); | ||
595 | } | 649 | } |
596 | 650 | ||
597 | static int perf_session__process_event(struct perf_session *self, | 651 | static void perf_session__print_tstamp(struct perf_session *session, |
598 | event_t *event, | 652 | event_t *event, |
599 | struct perf_event_ops *ops, | 653 | struct sample_data *sample) |
600 | u64 file_offset) | ||
601 | { | 654 | { |
602 | trace_event(event); | 655 | if (event->header.type != PERF_RECORD_SAMPLE && |
603 | 656 | !session->sample_id_all) { | |
604 | if (event->header.type < PERF_RECORD_HEADER_MAX) { | 657 | fputs("-1 -1 ", stdout); |
605 | dump_printf("%#Lx [%#x]: PERF_RECORD_%s", | 658 | return; |
606 | file_offset, event->header.size, | ||
607 | event__name[event->header.type]); | ||
608 | hists__inc_nr_events(&self->hists, event->header.type); | ||
609 | } | 659 | } |
610 | 660 | ||
611 | if (self->header.needs_swap && event__swap_ops[event->header.type]) | 661 | if ((session->sample_type & PERF_SAMPLE_CPU)) |
612 | event__swap_ops[event->header.type](event); | 662 | printf("%u ", sample->cpu); |
613 | 663 | ||
664 | if (session->sample_type & PERF_SAMPLE_TIME) | ||
665 | printf("%Lu ", sample->time); | ||
666 | } | ||
667 | |||
668 | static int perf_session_deliver_event(struct perf_session *session, | ||
669 | event_t *event, | ||
670 | struct sample_data *sample, | ||
671 | struct perf_event_ops *ops) | ||
672 | { | ||
614 | switch (event->header.type) { | 673 | switch (event->header.type) { |
615 | case PERF_RECORD_SAMPLE: | 674 | case PERF_RECORD_SAMPLE: |
616 | return perf_session__process_sample(event, self, ops); | 675 | return ops->sample(event, sample, session); |
617 | case PERF_RECORD_MMAP: | 676 | case PERF_RECORD_MMAP: |
618 | return ops->mmap(event, self); | 677 | return ops->mmap(event, sample, session); |
619 | case PERF_RECORD_COMM: | 678 | case PERF_RECORD_COMM: |
620 | return ops->comm(event, self); | 679 | return ops->comm(event, sample, session); |
621 | case PERF_RECORD_FORK: | 680 | case PERF_RECORD_FORK: |
622 | return ops->fork(event, self); | 681 | return ops->fork(event, sample, session); |
623 | case PERF_RECORD_EXIT: | 682 | case PERF_RECORD_EXIT: |
624 | return ops->exit(event, self); | 683 | return ops->exit(event, sample, session); |
625 | case PERF_RECORD_LOST: | 684 | case PERF_RECORD_LOST: |
626 | return ops->lost(event, self); | 685 | return ops->lost(event, sample, session); |
627 | case PERF_RECORD_READ: | 686 | case PERF_RECORD_READ: |
628 | return ops->read(event, self); | 687 | return ops->read(event, sample, session); |
629 | case PERF_RECORD_THROTTLE: | 688 | case PERF_RECORD_THROTTLE: |
630 | return ops->throttle(event, self); | 689 | return ops->throttle(event, sample, session); |
631 | case PERF_RECORD_UNTHROTTLE: | 690 | case PERF_RECORD_UNTHROTTLE: |
632 | return ops->unthrottle(event, self); | 691 | return ops->unthrottle(event, sample, session); |
692 | default: | ||
693 | ++session->hists.stats.nr_unknown_events; | ||
694 | return -1; | ||
695 | } | ||
696 | } | ||
697 | |||
698 | static int perf_session__process_event(struct perf_session *session, | ||
699 | event_t *event, | ||
700 | struct perf_event_ops *ops, | ||
701 | u64 file_offset) | ||
702 | { | ||
703 | struct sample_data sample; | ||
704 | int ret; | ||
705 | |||
706 | trace_event(event); | ||
707 | |||
708 | if (session->header.needs_swap && event__swap_ops[event->header.type]) | ||
709 | event__swap_ops[event->header.type](event); | ||
710 | |||
711 | if (event->header.type >= PERF_RECORD_MMAP && | ||
712 | event->header.type <= PERF_RECORD_SAMPLE) { | ||
713 | event__parse_sample(event, session, &sample); | ||
714 | if (dump_trace) | ||
715 | perf_session__print_tstamp(session, event, &sample); | ||
716 | } | ||
717 | |||
718 | if (event->header.type < PERF_RECORD_HEADER_MAX) { | ||
719 | dump_printf("%#Lx [%#x]: PERF_RECORD_%s", | ||
720 | file_offset, event->header.size, | ||
721 | event__name[event->header.type]); | ||
722 | hists__inc_nr_events(&session->hists, event->header.type); | ||
723 | } | ||
724 | |||
725 | /* These events are processed right away */ | ||
726 | switch (event->header.type) { | ||
727 | case PERF_RECORD_SAMPLE: | ||
728 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", | ||
729 | event->header.misc, | ||
730 | sample.pid, sample.tid, sample.ip, sample.period); | ||
731 | |||
732 | if (session->sample_type & PERF_SAMPLE_CALLCHAIN) { | ||
733 | if (!ip_callchain__valid(sample.callchain, event)) { | ||
734 | pr_debug("call-chain problem with event, " | ||
735 | "skipping it.\n"); | ||
736 | ++session->hists.stats.nr_invalid_chains; | ||
737 | session->hists.stats.total_invalid_chains += | ||
738 | sample.period; | ||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | callchain__dump(&sample); | ||
743 | } | ||
744 | break; | ||
745 | |||
633 | case PERF_RECORD_HEADER_ATTR: | 746 | case PERF_RECORD_HEADER_ATTR: |
634 | return ops->attr(event, self); | 747 | return ops->attr(event, session); |
635 | case PERF_RECORD_HEADER_EVENT_TYPE: | 748 | case PERF_RECORD_HEADER_EVENT_TYPE: |
636 | return ops->event_type(event, self); | 749 | return ops->event_type(event, session); |
637 | case PERF_RECORD_HEADER_TRACING_DATA: | 750 | case PERF_RECORD_HEADER_TRACING_DATA: |
638 | /* setup for reading amidst mmap */ | 751 | /* setup for reading amidst mmap */ |
639 | lseek(self->fd, file_offset, SEEK_SET); | 752 | lseek(session->fd, file_offset, SEEK_SET); |
640 | return ops->tracing_data(event, self); | 753 | return ops->tracing_data(event, session); |
641 | case PERF_RECORD_HEADER_BUILD_ID: | 754 | case PERF_RECORD_HEADER_BUILD_ID: |
642 | return ops->build_id(event, self); | 755 | return ops->build_id(event, session); |
643 | case PERF_RECORD_FINISHED_ROUND: | 756 | case PERF_RECORD_FINISHED_ROUND: |
644 | return ops->finished_round(event, self, ops); | 757 | return ops->finished_round(event, session, ops); |
645 | default: | 758 | default: |
646 | ++self->hists.stats.nr_unknown_events; | 759 | break; |
647 | return -1; | ||
648 | } | 760 | } |
761 | |||
762 | if (ops->ordered_samples) { | ||
763 | ret = perf_session_queue_event(session, event, &sample); | ||
764 | if (ret != -ETIME) | ||
765 | return ret; | ||
766 | } | ||
767 | |||
768 | return perf_session_deliver_event(session, event, &sample, ops); | ||
649 | } | 769 | } |
650 | 770 | ||
651 | void perf_event_header__bswap(struct perf_event_header *self) | 771 | void perf_event_header__bswap(struct perf_event_header *self) |
@@ -894,6 +1014,14 @@ out_err: | |||
894 | session->hists.stats.nr_unknown_events); | 1014 | session->hists.stats.nr_unknown_events); |
895 | } | 1015 | } |
896 | 1016 | ||
1017 | if (session->hists.stats.nr_invalid_chains != 0) { | ||
1018 | ui__warning("Found invalid callchains!\n\n" | ||
1019 | "%u out of %u events were discarded for this reason.\n\n" | ||
1020 | "Consider reporting to linux-kernel@vger.kernel.org.\n\n", | ||
1021 | session->hists.stats.nr_invalid_chains, | ||
1022 | session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); | ||
1023 | } | ||
1024 | |||
897 | perf_session_free_sample_buffers(session); | 1025 | perf_session_free_sample_buffers(session); |
898 | return err; | 1026 | return err; |
899 | } | 1027 | } |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 5bf6efa3788a..ac36f99f14af 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -46,6 +46,8 @@ struct perf_session { | |||
46 | int fd; | 46 | int fd; |
47 | bool fd_pipe; | 47 | bool fd_pipe; |
48 | bool repipe; | 48 | bool repipe; |
49 | bool sample_id_all; | ||
50 | u16 id_hdr_size; | ||
49 | int cwdlen; | 51 | int cwdlen; |
50 | char *cwd; | 52 | char *cwd; |
51 | struct ordered_samples ordered_samples; | 53 | struct ordered_samples ordered_samples; |
@@ -54,7 +56,9 @@ struct perf_session { | |||
54 | 56 | ||
55 | struct perf_event_ops; | 57 | struct perf_event_ops; |
56 | 58 | ||
57 | typedef int (*event_op)(event_t *self, struct perf_session *session); | 59 | typedef int (*event_op)(event_t *self, struct sample_data *sample, |
60 | struct perf_session *session); | ||
61 | typedef int (*event_synth_op)(event_t *self, struct perf_session *session); | ||
58 | typedef int (*event_op2)(event_t *self, struct perf_session *session, | 62 | typedef int (*event_op2)(event_t *self, struct perf_session *session, |
59 | struct perf_event_ops *ops); | 63 | struct perf_event_ops *ops); |
60 | 64 | ||
@@ -67,8 +71,8 @@ struct perf_event_ops { | |||
67 | lost, | 71 | lost, |
68 | read, | 72 | read, |
69 | throttle, | 73 | throttle, |
70 | unthrottle, | 74 | unthrottle; |
71 | attr, | 75 | event_synth_op attr, |
72 | event_type, | 76 | event_type, |
73 | tracing_data, | 77 | tracing_data, |
74 | build_id; | 78 | build_id; |
@@ -104,6 +108,8 @@ int perf_session__create_kernel_maps(struct perf_session *self); | |||
104 | 108 | ||
105 | int do_read(int fd, void *buf, size_t size); | 109 | int do_read(int fd, void *buf, size_t size); |
106 | void perf_session__update_sample_type(struct perf_session *self); | 110 | void perf_session__update_sample_type(struct perf_session *self); |
111 | void perf_session__set_sample_id_all(struct perf_session *session, bool value); | ||
112 | void perf_session__set_sample_type(struct perf_session *session, u64 type); | ||
107 | void perf_session__remove_thread(struct perf_session *self, struct thread *th); | 113 | void perf_session__remove_thread(struct perf_session *self, struct thread *th); |
108 | 114 | ||
109 | static inline | 115 | static inline |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index b62a553cc67d..f44fa541d56e 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -170,7 +170,7 @@ static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, | |||
170 | return repsep_snprintf(bf, size, "%-*s", width, dso_name); | 170 | return repsep_snprintf(bf, size, "%-*s", width, dso_name); |
171 | } | 171 | } |
172 | 172 | ||
173 | return repsep_snprintf(bf, size, "%*Lx", width, self->ip); | 173 | return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); |
174 | } | 174 | } |
175 | 175 | ||
176 | /* --sort symbol */ | 176 | /* --sort symbol */ |
@@ -196,7 +196,7 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, | |||
196 | 196 | ||
197 | if (verbose) { | 197 | if (verbose) { |
198 | char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!'; | 198 | char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!'; |
199 | ret += repsep_snprintf(bf, size, "%*Lx %c ", | 199 | ret += repsep_snprintf(bf, size, "%-#*llx %c ", |
200 | BITS_PER_LONG / 4, self->ip, o); | 200 | BITS_PER_LONG / 4, self->ip, o); |
201 | } | 201 | } |
202 | 202 | ||
@@ -205,7 +205,7 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, | |||
205 | ret += repsep_snprintf(bf + ret, size - ret, "%s", | 205 | ret += repsep_snprintf(bf + ret, size - ret, "%s", |
206 | self->ms.sym->name); | 206 | self->ms.sym->name); |
207 | else | 207 | else |
208 | ret += repsep_snprintf(bf + ret, size - ret, "%*Lx", | 208 | ret += repsep_snprintf(bf + ret, size - ret, "%-#*llx", |
209 | BITS_PER_LONG / 4, self->ip); | 209 | BITS_PER_LONG / 4, self->ip); |
210 | 210 | ||
211 | return ret; | 211 | return ret; |