diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index 706ce1a66169..fd4be94125fb 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -1,5 +1,6 @@ #include #include +#include #include "ordered-events.h" #include "evlist.h" #include "session.h" @@ -57,11 +58,45 @@ static void queue_event(struct ordered_events *oe, struct ordered_event *new) } } +static union perf_event *__dup_event(struct ordered_events *oe, + union perf_event *event) +{ + union perf_event *new_event = NULL; + + if (oe->cur_alloc_size < oe->max_alloc_size) { + new_event = memdup(event, event->header.size); + if (new_event) + oe->cur_alloc_size += event->header.size; + } + + return new_event; +} + +static union perf_event *dup_event(struct ordered_events *oe, + union perf_event *event) +{ + return oe->copy_on_queue ? __dup_event(oe, event) : event; +} + +static void free_dup_event(struct ordered_events *oe, union perf_event *event) +{ + if (oe->copy_on_queue) { + oe->cur_alloc_size -= event->header.size; + free(event); + } +} + #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event)) -static struct ordered_event *alloc_event(struct ordered_events *oe) +static struct ordered_event *alloc_event(struct ordered_events *oe, + union perf_event *event) { struct list_head *cache = &oe->cache; struct ordered_event *new = NULL; + union perf_event *new_event; + + new_event = dup_event(oe, event); + if (!new_event) + return NULL; if (!list_empty(cache)) { new = list_entry(cache->next, struct ordered_event, list); @@ -74,8 +109,10 @@ static struct ordered_event *alloc_event(struct ordered_events *oe) size_t size = MAX_SAMPLE_BUFFER * sizeof(*new); oe->buffer = malloc(size); - if (!oe->buffer) + if (!oe->buffer) { + free_dup_event(oe, new_event); return NULL; + } pr("alloc size %" PRIu64 "B (+%zu), max %" PRIu64 "B\n", oe->cur_alloc_size, size, oe->max_alloc_size); @@ -90,15 +127,17 @@ static struct ordered_event *alloc_event(struct ordered_events *oe) pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size); } + new->event = new_event; return new; } struct ordered_event * -ordered_events__new(struct ordered_events *oe, u64 timestamp) +ordered_events__new(struct ordered_events *oe, u64 timestamp, + union perf_event *event) { struct ordered_event *new; - new = alloc_event(oe); + new = alloc_event(oe, event); if (new) { new->timestamp = timestamp; queue_event(oe, new); @@ -111,6 +150,7 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve { list_move(&event->list, &oe->cache); oe->nr_events--; + free_dup_event(oe, event->event); } static int __ordered_events__flush(struct perf_session *s, @@ -240,6 +280,7 @@ void ordered_events__free(struct ordered_events *oe) event = list_entry(oe->to_free.next, struct ordered_event, list); list_del(&event->list); + free_dup_event(oe, event->event); free(event); } } diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h index 3b2f20542a01..7b8f9b011f38 100644 --- a/tools/perf/util/ordered-events.h +++ b/tools/perf/util/ordered-events.h @@ -34,9 +34,11 @@ struct ordered_events { int buffer_idx; unsigned int nr_events; enum oe_flush last_flush_type; + bool copy_on_queue; }; -struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timestamp); +struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timestamp, + union perf_event *event); void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event); int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, enum oe_flush how); @@ -48,4 +50,10 @@ void ordered_events__set_alloc_size(struct ordered_events *oe, u64 size) { oe->max_alloc_size = size; } + +static inline +void ordered_events__set_copy_on_queue(struct ordered_events *oe, bool copy) +{ + oe->copy_on_queue = copy; +} #endif /* __ORDERED_EVENTS_H */ diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 896bac73ea08..6702ac28754b 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -532,17 +532,16 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event, return -EINVAL; } - new = ordered_events__new(oe, timestamp); + new = ordered_events__new(oe, timestamp, event); if (!new) { ordered_events__flush(s, tool, OE_FLUSH__HALF); - new = ordered_events__new(oe, timestamp); + new = ordered_events__new(oe, timestamp, event); } if (!new) return -ENOMEM; new->file_offset = file_offset; - new->event = event; return 0; }