perf: Convert perf header attrs into attr events
authorTom Zanussi <tzanussi@gmail.com>
Fri, 2 Apr 2010 04:59:19 +0000 (23:59 -0500)
committerIngo Molnar <mingo@elte.hu>
Wed, 14 Apr 2010 09:56:07 +0000 (11:56 +0200)
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>
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-trace.c
tools/perf/util/event.h
tools/perf/util/header.c
tools/perf/util/header.h
tools/perf/util/session.c
tools/perf/util/session.h

index d4464f7fcea5b0e401491df15e1c4b52c182deb0..289d9cf3bf73c927f601a69285e726a3be5179b8 100644 (file)
@@ -584,6 +584,16 @@ static int __cmd_record(int argc, const char **argv)
 
        post_processing_offset = lseek(output, 0, SEEK_CUR);
 
+       if (pipe_output) {
+               err = event__synthesize_attrs(&session->header,
+                                             process_synthesized_event,
+                                             session);
+               if (err < 0) {
+                       pr_err("Couldn't synthesize attrs.\n");
+                       return err;
+               }
+       }
+
        err = event__synthesize_kernel_mmap(process_synthesized_event,
                                            session, "_text");
        if (err < 0)
index 00b358ff135c4b80ff7973e28ba1b03b87bd1c5d..f0486ce591a9d8f3470676a5c0b19d284041e42d 100644 (file)
@@ -267,6 +267,7 @@ static struct perf_event_ops event_ops = {
        .fork   = event__process_task,
        .lost   = event__process_lost,
        .read   = process_read_event,
+       .attr   = event__process_attr,
 };
 
 extern volatile int session_done;
index c681e85a912ca5d75b17515fef4197319bd567d5..e30eac6af5415ca402374e1e4e7ece01736ad512 100644 (file)
@@ -104,6 +104,7 @@ static int process_sample_event(event_t *event, struct perf_session *session)
 static struct perf_event_ops event_ops = {
        .sample = process_sample_event,
        .comm   = event__process_comm,
+       .attr   = event__process_attr,
 };
 
 extern volatile int session_done;
index 5c1eba671305c3399280abac28a6ee99b0231b92..b4fbf25078b97c00ae0161c5bfa29059cc04a839 100644 (file)
@@ -84,7 +84,14 @@ struct build_id_event {
 };
 
 enum perf_header_event_type { /* above any possible kernel type */
-       PERF_RECORD_HEADER_MAX                  = 64,
+       PERF_RECORD_HEADER_ATTR                 = 64,
+       PERF_RECORD_HEADER_MAX
+};
+
+struct attr_event {
+       struct perf_event_header header;
+       struct perf_event_attr attr;
+       u64 id[];
 };
 
 typedef union event_union {
@@ -96,6 +103,7 @@ typedef union event_union {
        struct lost_event               lost;
        struct read_event               read;
        struct sample_event             sample;
+       struct attr_event               attr;
 } event_t;
 
 struct events_stats {
index 8d05337d1a5913578a81355f9e8f20d76880d0e1..e36173934e8b36d14d2e64506f7aafdac017c818 100644 (file)
@@ -807,3 +807,82 @@ perf_header__find_attr(u64 id, struct perf_header *header)
 
        return NULL;
 }
+
+int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
+                          event__handler_t process,
+                          struct perf_session *session)
+{
+       event_t *ev;
+       size_t size;
+       int err;
+
+       size = sizeof(struct perf_event_attr);
+       size = ALIGN(size, sizeof(u64));
+       size += sizeof(struct perf_event_header);
+       size += ids * sizeof(u64);
+
+       ev = malloc(size);
+
+       ev->attr.attr = *attr;
+       memcpy(ev->attr.id, id, ids * sizeof(u64));
+
+       ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
+       ev->attr.header.size = size;
+
+       err = process(ev, session);
+
+       free(ev);
+
+       return err;
+}
+
+int event__synthesize_attrs(struct perf_header *self,
+                           event__handler_t process,
+                           struct perf_session *session)
+{
+       struct perf_header_attr *attr;
+       int i, err = 0;
+
+       for (i = 0; i < self->attrs; i++) {
+               attr = self->attr[i];
+
+               err = event__synthesize_attr(&attr->attr, attr->ids, attr->id,
+                                            process, session);
+               if (err) {
+                       pr_debug("failed to create perf header attribute\n");
+                       return err;
+               }
+       }
+
+       return err;
+}
+
+int event__process_attr(event_t *self, struct perf_session *session)
+{
+       struct perf_header_attr *attr;
+       unsigned int i, ids, n_ids;
+
+       attr = perf_header_attr__new(&self->attr.attr);
+       if (attr == NULL)
+               return -ENOMEM;
+
+       ids = self->header.size;
+       ids -= (void *)&self->attr.id - (void *)self;
+       n_ids = ids / sizeof(u64);
+
+       for (i = 0; i < n_ids; i++) {
+               if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) {
+                       perf_header_attr__delete(attr);
+                       return -ENOMEM;
+               }
+       }
+
+       if (perf_header__add_attr(&session->header, attr) < 0) {
+               perf_header_attr__delete(attr);
+               return -ENOMEM;
+       }
+
+       perf_session__update_sample_type(session);
+
+       return 0;
+}
index 6562ece670644b221ef4b7cd04b94427668394c1..e916ac509a69bc95d35cb6578f3562437f72282e 100644 (file)
@@ -95,4 +95,12 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
                          const char *name, bool is_kallsyms);
 int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
 
+int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
+                          event__handler_t process,
+                          struct perf_session *session);
+int event__synthesize_attrs(struct perf_header *self,
+                           event__handler_t process,
+                           struct perf_session *session);
+int event__process_attr(event_t *self, struct perf_session *session);
+
 #endif /* __PERF_HEADER_H */
index 2c1277cb4ae4528e931afb4498410bc60b61cec9..bc81864cd04e834a506f0dac03762f8a96fab6e5 100644 (file)
@@ -200,6 +200,8 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
                handler->throttle = process_event_stub;
        if (handler->unthrottle == NULL)
                handler->unthrottle = process_event_stub;
+       if (handler->attr == NULL)
+               handler->attr = process_event_stub;
 }
 
 static const char *event__name[] = {
@@ -213,6 +215,7 @@ static const char *event__name[] = {
        [PERF_RECORD_FORK]       = "FORK",
        [PERF_RECORD_READ]       = "READ",
        [PERF_RECORD_SAMPLE]     = "SAMPLE",
+       [PERF_RECORD_HEADER_ATTR]        = "ATTR",
 };
 
 unsigned long event__total[PERF_RECORD_HEADER_MAX];
@@ -279,6 +282,26 @@ static void event__read_swap(event_t *self)
        self->read.id           = bswap_64(self->read.id);
 }
 
+static void event__attr_swap(event_t *self)
+{
+       size_t size;
+
+       self->attr.attr.type            = bswap_32(self->attr.attr.type);
+       self->attr.attr.size            = bswap_32(self->attr.attr.size);
+       self->attr.attr.config          = bswap_64(self->attr.attr.config);
+       self->attr.attr.sample_period   = bswap_64(self->attr.attr.sample_period);
+       self->attr.attr.sample_type     = bswap_64(self->attr.attr.sample_type);
+       self->attr.attr.read_format     = bswap_64(self->attr.attr.read_format);
+       self->attr.attr.wakeup_events   = bswap_32(self->attr.attr.wakeup_events);
+       self->attr.attr.bp_type         = bswap_32(self->attr.attr.bp_type);
+       self->attr.attr.bp_addr         = bswap_64(self->attr.attr.bp_addr);
+       self->attr.attr.bp_len          = bswap_64(self->attr.attr.bp_len);
+
+       size = self->header.size;
+       size -= (void *)&self->attr.id - (void *)self;
+       mem_bswap_64(self->attr.id, size);
+}
+
 typedef void (*event__swap_op)(event_t *self);
 
 static event__swap_op event__swap_ops[] = {
@@ -289,6 +312,7 @@ static event__swap_op event__swap_ops[] = {
        [PERF_RECORD_LOST]   = event__all64_swap,
        [PERF_RECORD_READ]   = event__read_swap,
        [PERF_RECORD_SAMPLE] = event__all64_swap,
+       [PERF_RECORD_HEADER_ATTR]   = event__attr_swap,
        [PERF_RECORD_HEADER_MAX]    = NULL,
 };
 
@@ -329,6 +353,8 @@ static int perf_session__process_event(struct perf_session *self,
                return ops->throttle(event, self);
        case PERF_RECORD_UNTHROTTLE:
                return ops->unthrottle(event, self);
+       case PERF_RECORD_HEADER_ATTR:
+               return ops->attr(event, self);
        default:
                self->unknown_events++;
                return -1;
index 5f78911366556847bf5b74fdf3011c2a4ab75dfc..45a13741351ddfa5b5cbe4d7bf0924a52b8f0ce8 100644 (file)
@@ -44,7 +44,8 @@ struct perf_event_ops {
                 lost,
                 read,
                 throttle,
-                unthrottle;
+                unthrottle,
+                attr;
 };
 
 struct perf_session *perf_session__new(const char *filename, int mode, bool force);