diff options
author | Tom Zanussi <tzanussi@gmail.com> | 2010-04-02 00:59:19 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-04-14 05:56:07 -0400 |
commit | 2c46dbb517a10b18d459e6ceffefde5bfb290cf6 (patch) | |
tree | 20853decc73cd1fc69c2db7d8227d11cce6ee4de | |
parent | c239da3b4b55dbb8f30bcb8d1a0d63fc44a567c3 (diff) |
perf: Convert perf header attrs into attr events
Bypasses the attr perf header code and replaces it with a
synthesized event and processing function that accomplishes the
same thing, used when reading/writing perf data to/from a pipe.
Making the attrs into events allows them to be streamed over a
pipe along with the rest of the header data (in later patches).
It also paves the way to allowing events to be added and removed
from perf sessions dynamically.
Signed-off-by: Tom Zanussi <tzanussi@gmail.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Cc: fweisbec@gmail.com
Cc: rostedt@goodmis.org
Cc: k-keiichi@bx.jp.nec.com
Cc: acme@ghostprotocols.net
LKML-Reference: <1270184365-8281-6-git-send-email-tzanussi@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | tools/perf/builtin-record.c | 10 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 1 | ||||
-rw-r--r-- | tools/perf/builtin-trace.c | 1 | ||||
-rw-r--r-- | tools/perf/util/event.h | 10 | ||||
-rw-r--r-- | tools/perf/util/header.c | 79 | ||||
-rw-r--r-- | tools/perf/util/header.h | 8 | ||||
-rw-r--r-- | tools/perf/util/session.c | 26 | ||||
-rw-r--r-- | tools/perf/util/session.h | 3 |
8 files changed, 136 insertions, 2 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d4464f7fcea5..289d9cf3bf73 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -584,6 +584,16 @@ static int __cmd_record(int argc, const char **argv) | |||
584 | 584 | ||
585 | post_processing_offset = lseek(output, 0, SEEK_CUR); | 585 | post_processing_offset = lseek(output, 0, SEEK_CUR); |
586 | 586 | ||
587 | if (pipe_output) { | ||
588 | err = event__synthesize_attrs(&session->header, | ||
589 | process_synthesized_event, | ||
590 | session); | ||
591 | if (err < 0) { | ||
592 | pr_err("Couldn't synthesize attrs.\n"); | ||
593 | return err; | ||
594 | } | ||
595 | } | ||
596 | |||
587 | err = event__synthesize_kernel_mmap(process_synthesized_event, | 597 | err = event__synthesize_kernel_mmap(process_synthesized_event, |
588 | session, "_text"); | 598 | session, "_text"); |
589 | if (err < 0) | 599 | if (err < 0) |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 00b358ff135c..f0486ce591a9 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -267,6 +267,7 @@ static struct perf_event_ops event_ops = { | |||
267 | .fork = event__process_task, | 267 | .fork = event__process_task, |
268 | .lost = event__process_lost, | 268 | .lost = event__process_lost, |
269 | .read = process_read_event, | 269 | .read = process_read_event, |
270 | .attr = event__process_attr, | ||
270 | }; | 271 | }; |
271 | 272 | ||
272 | extern volatile int session_done; | 273 | extern volatile int session_done; |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index c681e85a912c..e30eac6af541 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -104,6 +104,7 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
104 | static struct perf_event_ops event_ops = { | 104 | static struct perf_event_ops event_ops = { |
105 | .sample = process_sample_event, | 105 | .sample = process_sample_event, |
106 | .comm = event__process_comm, | 106 | .comm = event__process_comm, |
107 | .attr = event__process_attr, | ||
107 | }; | 108 | }; |
108 | 109 | ||
109 | extern volatile int session_done; | 110 | extern volatile int session_done; |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 5c1eba671305..b4fbf25078b9 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -84,7 +84,14 @@ struct build_id_event { | |||
84 | }; | 84 | }; |
85 | 85 | ||
86 | enum perf_header_event_type { /* above any possible kernel type */ | 86 | enum perf_header_event_type { /* above any possible kernel type */ |
87 | PERF_RECORD_HEADER_MAX = 64, | 87 | PERF_RECORD_HEADER_ATTR = 64, |
88 | PERF_RECORD_HEADER_MAX | ||
89 | }; | ||
90 | |||
91 | struct attr_event { | ||
92 | struct perf_event_header header; | ||
93 | struct perf_event_attr attr; | ||
94 | u64 id[]; | ||
88 | }; | 95 | }; |
89 | 96 | ||
90 | typedef union event_union { | 97 | typedef union event_union { |
@@ -96,6 +103,7 @@ typedef union event_union { | |||
96 | struct lost_event lost; | 103 | struct lost_event lost; |
97 | struct read_event read; | 104 | struct read_event read; |
98 | struct sample_event sample; | 105 | struct sample_event sample; |
106 | struct attr_event attr; | ||
99 | } event_t; | 107 | } event_t; |
100 | 108 | ||
101 | struct events_stats { | 109 | struct events_stats { |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 8d05337d1a59..e36173934e8b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -807,3 +807,82 @@ perf_header__find_attr(u64 id, struct perf_header *header) | |||
807 | 807 | ||
808 | return NULL; | 808 | return NULL; |
809 | } | 809 | } |
810 | |||
811 | int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | ||
812 | event__handler_t process, | ||
813 | struct perf_session *session) | ||
814 | { | ||
815 | event_t *ev; | ||
816 | size_t size; | ||
817 | int err; | ||
818 | |||
819 | size = sizeof(struct perf_event_attr); | ||
820 | size = ALIGN(size, sizeof(u64)); | ||
821 | size += sizeof(struct perf_event_header); | ||
822 | size += ids * sizeof(u64); | ||
823 | |||
824 | ev = malloc(size); | ||
825 | |||
826 | ev->attr.attr = *attr; | ||
827 | memcpy(ev->attr.id, id, ids * sizeof(u64)); | ||
828 | |||
829 | ev->attr.header.type = PERF_RECORD_HEADER_ATTR; | ||
830 | ev->attr.header.size = size; | ||
831 | |||
832 | err = process(ev, session); | ||
833 | |||
834 | free(ev); | ||
835 | |||
836 | return err; | ||
837 | } | ||
838 | |||
839 | int event__synthesize_attrs(struct perf_header *self, | ||
840 | event__handler_t process, | ||
841 | struct perf_session *session) | ||
842 | { | ||
843 | struct perf_header_attr *attr; | ||
844 | int i, err = 0; | ||
845 | |||
846 | for (i = 0; i < self->attrs; i++) { | ||
847 | attr = self->attr[i]; | ||
848 | |||
849 | err = event__synthesize_attr(&attr->attr, attr->ids, attr->id, | ||
850 | process, session); | ||
851 | if (err) { | ||
852 | pr_debug("failed to create perf header attribute\n"); | ||
853 | return err; | ||
854 | } | ||
855 | } | ||
856 | |||
857 | return err; | ||
858 | } | ||
859 | |||
860 | int event__process_attr(event_t *self, struct perf_session *session) | ||
861 | { | ||
862 | struct perf_header_attr *attr; | ||
863 | unsigned int i, ids, n_ids; | ||
864 | |||
865 | attr = perf_header_attr__new(&self->attr.attr); | ||
866 | if (attr == NULL) | ||
867 | return -ENOMEM; | ||
868 | |||
869 | ids = self->header.size; | ||
870 | ids -= (void *)&self->attr.id - (void *)self; | ||
871 | n_ids = ids / sizeof(u64); | ||
872 | |||
873 | for (i = 0; i < n_ids; i++) { | ||
874 | if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) { | ||
875 | perf_header_attr__delete(attr); | ||
876 | return -ENOMEM; | ||
877 | } | ||
878 | } | ||
879 | |||
880 | if (perf_header__add_attr(&session->header, attr) < 0) { | ||
881 | perf_header_attr__delete(attr); | ||
882 | return -ENOMEM; | ||
883 | } | ||
884 | |||
885 | perf_session__update_sample_type(session); | ||
886 | |||
887 | return 0; | ||
888 | } | ||
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 6562ece67064..e916ac509a69 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -95,4 +95,12 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | |||
95 | const char *name, bool is_kallsyms); | 95 | const char *name, bool is_kallsyms); |
96 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); | 96 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); |
97 | 97 | ||
98 | int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | ||
99 | event__handler_t process, | ||
100 | struct perf_session *session); | ||
101 | int event__synthesize_attrs(struct perf_header *self, | ||
102 | event__handler_t process, | ||
103 | struct perf_session *session); | ||
104 | int event__process_attr(event_t *self, struct perf_session *session); | ||
105 | |||
98 | #endif /* __PERF_HEADER_H */ | 106 | #endif /* __PERF_HEADER_H */ |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 2c1277cb4ae4..bc81864cd04e 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -200,6 +200,8 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) | |||
200 | handler->throttle = process_event_stub; | 200 | handler->throttle = process_event_stub; |
201 | if (handler->unthrottle == NULL) | 201 | if (handler->unthrottle == NULL) |
202 | handler->unthrottle = process_event_stub; | 202 | handler->unthrottle = process_event_stub; |
203 | if (handler->attr == NULL) | ||
204 | handler->attr = process_event_stub; | ||
203 | } | 205 | } |
204 | 206 | ||
205 | static const char *event__name[] = { | 207 | static const char *event__name[] = { |
@@ -213,6 +215,7 @@ static const char *event__name[] = { | |||
213 | [PERF_RECORD_FORK] = "FORK", | 215 | [PERF_RECORD_FORK] = "FORK", |
214 | [PERF_RECORD_READ] = "READ", | 216 | [PERF_RECORD_READ] = "READ", |
215 | [PERF_RECORD_SAMPLE] = "SAMPLE", | 217 | [PERF_RECORD_SAMPLE] = "SAMPLE", |
218 | [PERF_RECORD_HEADER_ATTR] = "ATTR", | ||
216 | }; | 219 | }; |
217 | 220 | ||
218 | unsigned long event__total[PERF_RECORD_HEADER_MAX]; | 221 | unsigned long event__total[PERF_RECORD_HEADER_MAX]; |
@@ -279,6 +282,26 @@ static void event__read_swap(event_t *self) | |||
279 | self->read.id = bswap_64(self->read.id); | 282 | self->read.id = bswap_64(self->read.id); |
280 | } | 283 | } |
281 | 284 | ||
285 | static void event__attr_swap(event_t *self) | ||
286 | { | ||
287 | size_t size; | ||
288 | |||
289 | self->attr.attr.type = bswap_32(self->attr.attr.type); | ||
290 | self->attr.attr.size = bswap_32(self->attr.attr.size); | ||
291 | self->attr.attr.config = bswap_64(self->attr.attr.config); | ||
292 | self->attr.attr.sample_period = bswap_64(self->attr.attr.sample_period); | ||
293 | self->attr.attr.sample_type = bswap_64(self->attr.attr.sample_type); | ||
294 | self->attr.attr.read_format = bswap_64(self->attr.attr.read_format); | ||
295 | self->attr.attr.wakeup_events = bswap_32(self->attr.attr.wakeup_events); | ||
296 | self->attr.attr.bp_type = bswap_32(self->attr.attr.bp_type); | ||
297 | self->attr.attr.bp_addr = bswap_64(self->attr.attr.bp_addr); | ||
298 | self->attr.attr.bp_len = bswap_64(self->attr.attr.bp_len); | ||
299 | |||
300 | size = self->header.size; | ||
301 | size -= (void *)&self->attr.id - (void *)self; | ||
302 | mem_bswap_64(self->attr.id, size); | ||
303 | } | ||
304 | |||
282 | typedef void (*event__swap_op)(event_t *self); | 305 | typedef void (*event__swap_op)(event_t *self); |
283 | 306 | ||
284 | static event__swap_op event__swap_ops[] = { | 307 | static event__swap_op event__swap_ops[] = { |
@@ -289,6 +312,7 @@ static event__swap_op event__swap_ops[] = { | |||
289 | [PERF_RECORD_LOST] = event__all64_swap, | 312 | [PERF_RECORD_LOST] = event__all64_swap, |
290 | [PERF_RECORD_READ] = event__read_swap, | 313 | [PERF_RECORD_READ] = event__read_swap, |
291 | [PERF_RECORD_SAMPLE] = event__all64_swap, | 314 | [PERF_RECORD_SAMPLE] = event__all64_swap, |
315 | [PERF_RECORD_HEADER_ATTR] = event__attr_swap, | ||
292 | [PERF_RECORD_HEADER_MAX] = NULL, | 316 | [PERF_RECORD_HEADER_MAX] = NULL, |
293 | }; | 317 | }; |
294 | 318 | ||
@@ -329,6 +353,8 @@ static int perf_session__process_event(struct perf_session *self, | |||
329 | return ops->throttle(event, self); | 353 | return ops->throttle(event, self); |
330 | case PERF_RECORD_UNTHROTTLE: | 354 | case PERF_RECORD_UNTHROTTLE: |
331 | return ops->unthrottle(event, self); | 355 | return ops->unthrottle(event, self); |
356 | case PERF_RECORD_HEADER_ATTR: | ||
357 | return ops->attr(event, self); | ||
332 | default: | 358 | default: |
333 | self->unknown_events++; | 359 | self->unknown_events++; |
334 | return -1; | 360 | return -1; |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 5f7891136655..45a13741351d 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -44,7 +44,8 @@ struct perf_event_ops { | |||
44 | lost, | 44 | lost, |
45 | read, | 45 | read, |
46 | throttle, | 46 | throttle, |
47 | unthrottle; | 47 | unthrottle, |
48 | attr; | ||
48 | }; | 49 | }; |
49 | 50 | ||
50 | struct perf_session *perf_session__new(const char *filename, int mode, bool force); | 51 | struct perf_session *perf_session__new(const char *filename, int mode, bool force); |