perf auxtrace: Add support for queuing AUX area samples
authorAdrian Hunter <adrian.hunter@intel.com>
Fri, 15 Nov 2019 12:42:21 +0000 (14:42 +0200)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 22 Nov 2019 13:48:13 +0000 (10:48 -0300)
Add functions to queue AUX area samples in advance
(auxtrace_queue_data()) or individually (auxtrace_queues__add_sample())
or find out what queue a sample belongs on
(auxtrace_queues__sample_queue()).

auxtrace_queue_data() can also queue snapshot data which keeps snapshots
and samples ordered with respect to each other in case support for that
is desired.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lore.kernel.org/lkml/20191115124225.5247-12-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/auxtrace.c
tools/perf/util/auxtrace.h

index 4f5c5fe3516b6cf618908ae961c2771841d3e484..eb087e7df6f4bc1c98398a9e98b12dfd64761f0e 100644 (file)
@@ -1004,6 +1004,113 @@ struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue,
        }
 }
 
+struct auxtrace_queue *auxtrace_queues__sample_queue(struct auxtrace_queues *queues,
+                                                    struct perf_sample *sample,
+                                                    struct perf_session *session)
+{
+       struct perf_sample_id *sid;
+       unsigned int idx;
+       u64 id;
+
+       id = sample->id;
+       if (!id)
+               return NULL;
+
+       sid = perf_evlist__id2sid(session->evlist, id);
+       if (!sid)
+               return NULL;
+
+       idx = sid->idx;
+
+       if (idx >= queues->nr_queues)
+               return NULL;
+
+       return &queues->queue_array[idx];
+}
+
+int auxtrace_queues__add_sample(struct auxtrace_queues *queues,
+                               struct perf_session *session,
+                               struct perf_sample *sample, u64 data_offset,
+                               u64 reference)
+{
+       struct auxtrace_buffer buffer = {
+               .pid = -1,
+               .data_offset = data_offset,
+               .reference = reference,
+               .size = sample->aux_sample.size,
+       };
+       struct perf_sample_id *sid;
+       u64 id = sample->id;
+       unsigned int idx;
+
+       if (!id)
+               return -EINVAL;
+
+       sid = perf_evlist__id2sid(session->evlist, id);
+       if (!sid)
+               return -ENOENT;
+
+       idx = sid->idx;
+       buffer.tid = sid->tid;
+       buffer.cpu = sid->cpu;
+
+       return auxtrace_queues__add_buffer(queues, session, idx, &buffer, NULL);
+}
+
+struct queue_data {
+       bool samples;
+       bool events;
+};
+
+static int auxtrace_queue_data_cb(struct perf_session *session,
+                                 union perf_event *event, u64 offset,
+                                 void *data)
+{
+       struct queue_data *qd = data;
+       struct perf_sample sample;
+       int err;
+
+       if (qd->events && event->header.type == PERF_RECORD_AUXTRACE) {
+               if (event->header.size < sizeof(struct perf_record_auxtrace))
+                       return -EINVAL;
+               offset += event->header.size;
+               return session->auxtrace->queue_data(session, NULL, event,
+                                                    offset);
+       }
+
+       if (!qd->samples || event->header.type != PERF_RECORD_SAMPLE)
+               return 0;
+
+       err = perf_evlist__parse_sample(session->evlist, event, &sample);
+       if (err)
+               return err;
+
+       if (!sample.aux_sample.size)
+               return 0;
+
+       offset += sample.aux_sample.data - (void *)event;
+
+       return session->auxtrace->queue_data(session, &sample, NULL, offset);
+}
+
+int auxtrace_queue_data(struct perf_session *session, bool samples, bool events)
+{
+       struct queue_data qd = {
+               .samples = samples,
+               .events = events,
+       };
+
+       if (auxtrace__dont_decode(session))
+               return 0;
+
+       if (!session->auxtrace || !session->auxtrace->queue_data)
+               return -EINVAL;
+
+       return perf_session__peek_events(session, session->header.data_offset,
+                                        session->header.data_size,
+                                        auxtrace_queue_data_cb, &qd);
+}
+
 void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd)
 {
        size_t adj = buffer->data_offset & (page_size - 1);
index 4a8ac7de6e22d87d6ec76895fd717a9d36859aed..749d72cd9c7b0eaaf6f82ea1fc63ee71d6ca8b50 100644 (file)
@@ -141,6 +141,8 @@ struct auxtrace_index {
  * struct auxtrace - session callbacks to allow AUX area data decoding.
  * @process_event: lets the decoder see all session events
  * @process_auxtrace_event: process a PERF_RECORD_AUXTRACE event
+ * @queue_data: queue an AUX sample or PERF_RECORD_AUXTRACE event for later
+ *              processing
  * @dump_auxtrace_sample: dump AUX area sample data
  * @flush_events: process any remaining data
  * @free_events: free resources associated with event processing
@@ -154,6 +156,9 @@ struct auxtrace {
        int (*process_auxtrace_event)(struct perf_session *session,
                                      union perf_event *event,
                                      struct perf_tool *tool);
+       int (*queue_data)(struct perf_session *session,
+                         struct perf_sample *sample, union perf_event *event,
+                         u64 data_offset);
        void (*dump_auxtrace_sample)(struct perf_session *session,
                                     struct perf_sample *sample);
        int (*flush_events)(struct perf_session *session,
@@ -467,9 +472,19 @@ int auxtrace_queues__add_event(struct auxtrace_queues *queues,
                               struct perf_session *session,
                               union perf_event *event, off_t data_offset,
                               struct auxtrace_buffer **buffer_ptr);
+struct auxtrace_queue *
+auxtrace_queues__sample_queue(struct auxtrace_queues *queues,
+                             struct perf_sample *sample,
+                             struct perf_session *session);
+int auxtrace_queues__add_sample(struct auxtrace_queues *queues,
+                               struct perf_session *session,
+                               struct perf_sample *sample, u64 data_offset,
+                               u64 reference);
 void auxtrace_queues__free(struct auxtrace_queues *queues);
 int auxtrace_queues__process_index(struct auxtrace_queues *queues,
                                   struct perf_session *session);
+int auxtrace_queue_data(struct perf_session *session, bool samples,
+                       bool events);
 struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue,
                                              struct auxtrace_buffer *buffer);
 void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd);