summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/perf/util/ordered-events.c49
-rw-r--r--tools/perf/util/ordered-events.h10
-rw-r--r--tools/perf/util/session.c5
3 files changed, 56 insertions, 8 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);
}
}
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;
}