diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-02-03 13:52:05 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-02-04 03:33:27 -0500 |
commit | 6122e4e4f5d0913e319ef8a4dc60a47afe4abc0a (patch) | |
tree | 77e8995f360f3cb3a8f7c392708ccf58836b0573 | |
parent | 7b2567c1f57c059de29d3f2ca03aca84473865c8 (diff) |
perf record: Stop intercepting events, use postprocessing to get build-ids
We want to stream events as fast as possible to perf.data, and
also in the future we want to have splice working, when no
interception will be possible.
Using build_id__mark_dso_hit_ops to create the list of DSOs that
back MMAPs we also optimize disk usage in the build-id cache by
only caching DSOs that had hits.
Suggested-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1265223128-11786-6-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | tools/perf/builtin-record.c | 37 | ||||
-rw-r--r-- | tools/perf/util/header.c | 7 | ||||
-rw-r--r-- | tools/perf/util/session.c | 64 | ||||
-rw-r--r-- | tools/perf/util/session.h | 3 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 13 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 2 |
6 files changed, 73 insertions, 53 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 949167efa1ed..706f00196b87 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #include "perf.h" | 13 | #include "perf.h" |
14 | 14 | ||
15 | #include "util/build-id.h" | ||
15 | #include "util/util.h" | 16 | #include "util/util.h" |
16 | #include "util/parse-options.h" | 17 | #include "util/parse-options.h" |
17 | #include "util/parse-events.h" | 18 | #include "util/parse-events.h" |
@@ -65,6 +66,7 @@ static int nr_poll = 0; | |||
65 | static int nr_cpu = 0; | 66 | static int nr_cpu = 0; |
66 | 67 | ||
67 | static int file_new = 1; | 68 | static int file_new = 1; |
69 | static off_t post_processing_offset; | ||
68 | 70 | ||
69 | static struct perf_session *session; | 71 | static struct perf_session *session; |
70 | 72 | ||
@@ -114,26 +116,10 @@ static void write_output(void *buf, size_t size) | |||
114 | } | 116 | } |
115 | } | 117 | } |
116 | 118 | ||
117 | static void write_event(event_t *buf, size_t size) | ||
118 | { | ||
119 | /* | ||
120 | * Add it to the list of DSOs, so that when we finish this | ||
121 | * record session we can pick the available build-ids. | ||
122 | */ | ||
123 | if (buf->header.type == PERF_RECORD_MMAP) { | ||
124 | struct list_head *head = &dsos__user; | ||
125 | if (buf->mmap.header.misc == 1) | ||
126 | head = &dsos__kernel; | ||
127 | __dsos__findnew(head, buf->mmap.filename); | ||
128 | } | ||
129 | |||
130 | write_output(buf, size); | ||
131 | } | ||
132 | |||
133 | static int process_synthesized_event(event_t *event, | 119 | static int process_synthesized_event(event_t *event, |
134 | struct perf_session *self __used) | 120 | struct perf_session *self __used) |
135 | { | 121 | { |
136 | write_event(event, event->header.size); | 122 | write_output(event, event->header.size); |
137 | return 0; | 123 | return 0; |
138 | } | 124 | } |
139 | 125 | ||
@@ -185,14 +171,14 @@ static void mmap_read(struct mmap_data *md) | |||
185 | size = md->mask + 1 - (old & md->mask); | 171 | size = md->mask + 1 - (old & md->mask); |
186 | old += size; | 172 | old += size; |
187 | 173 | ||
188 | write_event(buf, size); | 174 | write_output(buf, size); |
189 | } | 175 | } |
190 | 176 | ||
191 | buf = &data[old & md->mask]; | 177 | buf = &data[old & md->mask]; |
192 | size = head - old; | 178 | size = head - old; |
193 | old += size; | 179 | old += size; |
194 | 180 | ||
195 | write_event(buf, size); | 181 | write_output(buf, size); |
196 | 182 | ||
197 | md->prev = old; | 183 | md->prev = old; |
198 | mmap_write_tail(md, old); | 184 | mmap_write_tail(md, old); |
@@ -402,10 +388,21 @@ static void open_counters(int cpu, pid_t pid) | |||
402 | nr_cpu++; | 388 | nr_cpu++; |
403 | } | 389 | } |
404 | 390 | ||
391 | static int process_buildids(void) | ||
392 | { | ||
393 | u64 size = lseek(output, 0, SEEK_CUR); | ||
394 | |||
395 | session->fd = output; | ||
396 | return __perf_session__process_events(session, post_processing_offset, | ||
397 | size - post_processing_offset, | ||
398 | size, &build_id__mark_dso_hit_ops); | ||
399 | } | ||
400 | |||
405 | static void atexit_header(void) | 401 | static void atexit_header(void) |
406 | { | 402 | { |
407 | session->header.data_size += bytes_written; | 403 | session->header.data_size += bytes_written; |
408 | 404 | ||
405 | process_buildids(); | ||
409 | perf_header__write(&session->header, output, true); | 406 | perf_header__write(&session->header, output, true); |
410 | } | 407 | } |
411 | 408 | ||
@@ -558,6 +555,8 @@ static int __cmd_record(int argc, const char **argv) | |||
558 | return err; | 555 | return err; |
559 | } | 556 | } |
560 | 557 | ||
558 | post_processing_offset = lseek(output, 0, SEEK_CUR); | ||
559 | |||
561 | err = event__synthesize_kernel_mmap(process_synthesized_event, | 560 | err = event__synthesize_kernel_mmap(process_synthesized_event, |
562 | session, "_text"); | 561 | session, "_text"); |
563 | if (err < 0) { | 562 | if (err < 0) { |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ed3efd728b41..d5facd5ab1f7 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -205,8 +205,11 @@ static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd) | |||
205 | dsos__for_each_with_build_id(pos, head) { | 205 | dsos__for_each_with_build_id(pos, head) { |
206 | int err; | 206 | int err; |
207 | struct build_id_event b; | 207 | struct build_id_event b; |
208 | size_t len = pos->long_name_len + 1; | 208 | size_t len; |
209 | 209 | ||
210 | if (!pos->hit) | ||
211 | continue; | ||
212 | len = pos->long_name_len + 1; | ||
210 | len = ALIGN(len, NAME_ALIGN); | 213 | len = ALIGN(len, NAME_ALIGN); |
211 | memset(&b, 0, sizeof(b)); | 214 | memset(&b, 0, sizeof(b)); |
212 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); | 215 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); |
@@ -371,7 +374,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
371 | u64 sec_start; | 374 | u64 sec_start; |
372 | int idx = 0, err; | 375 | int idx = 0, err; |
373 | 376 | ||
374 | if (dsos__read_build_ids()) | 377 | if (dsos__read_build_ids(true)) |
375 | perf_header__set_feat(self, HEADER_BUILD_ID); | 378 | perf_header__set_feat(self, HEADER_BUILD_ID); |
376 | 379 | ||
377 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); | 380 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index aa8a03120bbd..74cbc64a3a3c 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -385,8 +385,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se | |||
385 | return thread; | 385 | return thread; |
386 | } | 386 | } |
387 | 387 | ||
388 | int perf_session__process_events(struct perf_session *self, | 388 | int __perf_session__process_events(struct perf_session *self, |
389 | struct perf_event_ops *ops) | 389 | u64 data_offset, u64 data_size, |
390 | u64 file_size, struct perf_event_ops *ops) | ||
390 | { | 391 | { |
391 | int err, mmap_prot, mmap_flags; | 392 | int err, mmap_prot, mmap_flags; |
392 | u64 head, shift; | 393 | u64 head, shift; |
@@ -396,32 +397,11 @@ int perf_session__process_events(struct perf_session *self, | |||
396 | uint32_t size; | 397 | uint32_t size; |
397 | char *buf; | 398 | char *buf; |
398 | 399 | ||
399 | if (perf_session__register_idle_thread(self) == NULL) | ||
400 | return -ENOMEM; | ||
401 | |||
402 | perf_event_ops__fill_defaults(ops); | 400 | perf_event_ops__fill_defaults(ops); |
403 | 401 | ||
404 | page_size = sysconf(_SC_PAGESIZE); | 402 | page_size = sysconf(_SC_PAGESIZE); |
405 | 403 | ||
406 | head = self->header.data_offset; | 404 | head = data_offset; |
407 | |||
408 | if (!symbol_conf.full_paths) { | ||
409 | char bf[PATH_MAX]; | ||
410 | |||
411 | if (getcwd(bf, sizeof(bf)) == NULL) { | ||
412 | err = -errno; | ||
413 | out_getcwd_err: | ||
414 | pr_err("failed to get the current directory\n"); | ||
415 | goto out_err; | ||
416 | } | ||
417 | self->cwd = strdup(bf); | ||
418 | if (self->cwd == NULL) { | ||
419 | err = -ENOMEM; | ||
420 | goto out_getcwd_err; | ||
421 | } | ||
422 | self->cwdlen = strlen(self->cwd); | ||
423 | } | ||
424 | |||
425 | shift = page_size * (head / page_size); | 405 | shift = page_size * (head / page_size); |
426 | offset += shift; | 406 | offset += shift; |
427 | head -= shift; | 407 | head -= shift; |
@@ -486,10 +466,10 @@ more: | |||
486 | 466 | ||
487 | head += size; | 467 | head += size; |
488 | 468 | ||
489 | if (offset + head >= self->header.data_offset + self->header.data_size) | 469 | if (offset + head >= data_offset + data_size) |
490 | goto done; | 470 | goto done; |
491 | 471 | ||
492 | if (offset + head < self->size) | 472 | if (offset + head < file_size) |
493 | goto more; | 473 | goto more; |
494 | done: | 474 | done: |
495 | err = 0; | 475 | err = 0; |
@@ -497,6 +477,38 @@ out_err: | |||
497 | return err; | 477 | return err; |
498 | } | 478 | } |
499 | 479 | ||
480 | int perf_session__process_events(struct perf_session *self, | ||
481 | struct perf_event_ops *ops) | ||
482 | { | ||
483 | int err; | ||
484 | |||
485 | if (perf_session__register_idle_thread(self) == NULL) | ||
486 | return -ENOMEM; | ||
487 | |||
488 | if (!symbol_conf.full_paths) { | ||
489 | char bf[PATH_MAX]; | ||
490 | |||
491 | if (getcwd(bf, sizeof(bf)) == NULL) { | ||
492 | err = -errno; | ||
493 | out_getcwd_err: | ||
494 | pr_err("failed to get the current directory\n"); | ||
495 | goto out_err; | ||
496 | } | ||
497 | self->cwd = strdup(bf); | ||
498 | if (self->cwd == NULL) { | ||
499 | err = -ENOMEM; | ||
500 | goto out_getcwd_err; | ||
501 | } | ||
502 | self->cwdlen = strlen(self->cwd); | ||
503 | } | ||
504 | |||
505 | err = __perf_session__process_events(self, self->header.data_offset, | ||
506 | self->header.data_size, | ||
507 | self->size, ops); | ||
508 | out_err: | ||
509 | return err; | ||
510 | } | ||
511 | |||
500 | bool perf_session__has_traces(struct perf_session *self, const char *msg) | 512 | bool perf_session__has_traces(struct perf_session *self, const char *msg) |
501 | { | 513 | { |
502 | if (!(self->sample_type & PERF_SAMPLE_RAW)) { | 514 | if (!(self->sample_type & PERF_SAMPLE_RAW)) { |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 752d75aebade..31950fcd8a4d 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -50,6 +50,9 @@ void perf_session__delete(struct perf_session *self); | |||
50 | 50 | ||
51 | void perf_event_header__bswap(struct perf_event_header *self); | 51 | void perf_event_header__bswap(struct perf_event_header *self); |
52 | 52 | ||
53 | int __perf_session__process_events(struct perf_session *self, | ||
54 | u64 data_offset, u64 data_size, u64 size, | ||
55 | struct perf_event_ops *ops); | ||
53 | int perf_session__process_events(struct perf_session *self, | 56 | int perf_session__process_events(struct perf_session *self, |
54 | struct perf_event_ops *event_ops); | 57 | struct perf_event_ops *event_ops); |
55 | 58 | ||
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e752837363ee..bfb055459670 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -1076,25 +1076,28 @@ static bool dso__build_id_equal(const struct dso *self, u8 *build_id) | |||
1076 | return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; | 1076 | return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; |
1077 | } | 1077 | } |
1078 | 1078 | ||
1079 | static bool __dsos__read_build_ids(struct list_head *head) | 1079 | static bool __dsos__read_build_ids(struct list_head *head, bool with_hits) |
1080 | { | 1080 | { |
1081 | bool have_build_id = false; | 1081 | bool have_build_id = false; |
1082 | struct dso *pos; | 1082 | struct dso *pos; |
1083 | 1083 | ||
1084 | list_for_each_entry(pos, head, node) | 1084 | list_for_each_entry(pos, head, node) { |
1085 | if (with_hits && !pos->hit) | ||
1086 | continue; | ||
1085 | if (filename__read_build_id(pos->long_name, pos->build_id, | 1087 | if (filename__read_build_id(pos->long_name, pos->build_id, |
1086 | sizeof(pos->build_id)) > 0) { | 1088 | sizeof(pos->build_id)) > 0) { |
1087 | have_build_id = true; | 1089 | have_build_id = true; |
1088 | pos->has_build_id = true; | 1090 | pos->has_build_id = true; |
1089 | } | 1091 | } |
1092 | } | ||
1090 | 1093 | ||
1091 | return have_build_id; | 1094 | return have_build_id; |
1092 | } | 1095 | } |
1093 | 1096 | ||
1094 | bool dsos__read_build_ids(void) | 1097 | bool dsos__read_build_ids(bool with_hits) |
1095 | { | 1098 | { |
1096 | bool kbuildids = __dsos__read_build_ids(&dsos__kernel), | 1099 | bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits), |
1097 | ubuildids = __dsos__read_build_ids(&dsos__user); | 1100 | ubuildids = __dsos__read_build_ids(&dsos__user, with_hits); |
1098 | return kbuildids || ubuildids; | 1101 | return kbuildids || ubuildids; |
1099 | } | 1102 | } |
1100 | 1103 | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index e90568a9e467..1b4192ee5300 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -157,7 +157,7 @@ struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, | |||
157 | 157 | ||
158 | int filename__read_build_id(const char *filename, void *bf, size_t size); | 158 | int filename__read_build_id(const char *filename, void *bf, size_t size); |
159 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); | 159 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); |
160 | bool dsos__read_build_ids(void); | 160 | bool dsos__read_build_ids(bool with_hits); |
161 | int build_id__sprintf(const u8 *self, int len, char *bf); | 161 | int build_id__sprintf(const u8 *self, int len, char *bf); |
162 | int kallsyms__parse(const char *filename, void *arg, | 162 | int kallsyms__parse(const char *filename, void *arg, |
163 | int (*process_symbol)(void *arg, const char *name, | 163 | int (*process_symbol)(void *arg, const char *name, |