summaryrefslogtreecommitdiffstats
path: root/tools/perf/util/ordered-events.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/ordered-events.c')
-rw-r--r--tools/perf/util/ordered-events.c49
1 files changed, 45 insertions, 4 deletions
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 <linux/list.h>
#include <linux/compiler.h>
+#include <linux/string.h>
#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);
}
}