From: Jiri Olsa <jolsa@redhat.com>
To: Stephane Eranian <eranian@google.com>
Cc: LKML <linux-kernel@vger.kernel.org>,
Arnaldo Carvalho de Melo <acme@redhat.com>,
Peter Zijlstra <peterz@infradead.org>,
mingo@elte.hu
Subject: Re: [PATCH] perf tools: Add struct ordered_events_buffer layer
Date: Wed, 15 Aug 2018 10:48:25 +0200 [thread overview]
Message-ID: <20180815084825.GD3180@krava> (raw)
In-Reply-To: <CABPqkBSgYEFFAkddBqZbYXe9tjUY7RbMBjQsZht8ki1iOR6unw@mail.gmail.com>
On Tue, Aug 14, 2018 at 12:14:19AM -0700, Stephane Eranian wrote:
SNIP
> > @@ -104,11 +110,12 @@ static struct ordered_event *alloc_event(struct ordered_events *oe,
> > new = list_entry(cache->next, struct ordered_event, list);
> > list_del(&new->list);
> > } else if (oe->buffer) {
> > - new = oe->buffer + oe->buffer_idx;
> > + new = &oe->buffer->event[oe->buffer_idx];
> > if (++oe->buffer_idx == MAX_SAMPLE_BUFFER)
> > oe->buffer = NULL;
> > } else if (oe->cur_alloc_size < oe->max_alloc_size) {
> > - size_t size = MAX_SAMPLE_BUFFER * sizeof(*new);
> > + size_t size = sizeof(*oe->buffer) +
> > + MAX_SAMPLE_BUFFER * sizeof(*new);
> >
> > oe->buffer = malloc(size);
> > if (!oe->buffer) {
> > @@ -122,9 +129,8 @@ static struct ordered_event *alloc_event(struct ordered_events *oe,
> > oe->cur_alloc_size += size;
> > list_add(&oe->buffer->list, &oe->to_free);
> >
> > - /* First entry is abused to maintain the to_free list. */
> > - oe->buffer_idx = 2;
> > - new = oe->buffer + 1;
> > + oe->buffer_idx = 1;
> > + new = &oe->buffer->event[0];
>
> Ok, but I think this section between the malloc() and the line above
> needs some comments to clarify what is going on.
> It is still hard to read.
ok, I put some bigger comment at the top, but I'm not too happy
feel free to suggest different one ;-)
>
> > } else {
> > pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size);
> > }
> > @@ -300,15 +306,27 @@ void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t d
> > oe->deliver = deliver;
> > }
> >
> > +static void
> > +ordered_events_buffer__free(struct ordered_events_buffer *buffer,
> > + struct ordered_events *oe)
> > +{
> > + if (oe->copy_on_queue) {
> > + unsigned int i;
> > +
> > + for (i = 0; i < MAX_SAMPLE_BUFFER; i++)
> > + __free_dup_event(oe, buffer->event[i].event);
> > + }
> > +
> I have a problem with this one, given that the buffer->event[] is
> never actually zeroed.
> So what happens if you do not use all the entries by the time you have to free?
> I think one way to avoid this is by iterating only all the way to
> oe->buffer_idx.
right, please check attached patch
thanks,
jirka
---
diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c
index bad9e0296e9a..7a9707301f17 100644
--- a/tools/perf/util/ordered-events.c
+++ b/tools/perf/util/ordered-events.c
@@ -80,14 +80,20 @@ static union perf_event *dup_event(struct ordered_events *oe,
return oe->copy_on_queue ? __dup_event(oe, event) : event;
}
-static void free_dup_event(struct ordered_events *oe, union perf_event *event)
+static void __free_dup_event(struct ordered_events *oe, union perf_event *event)
{
- if (event && oe->copy_on_queue) {
+ if (event) {
oe->cur_alloc_size -= event->header.size;
free(event);
}
}
+static void free_dup_event(struct ordered_events *oe, union perf_event *event)
+{
+ if (oe->copy_on_queue)
+ __free_dup_event(oe, event);
+}
+
#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event))
static struct ordered_event *alloc_event(struct ordered_events *oe,
union perf_event *event)
@@ -100,15 +106,43 @@ static struct ordered_event *alloc_event(struct ordered_events *oe,
if (!new_event)
return NULL;
+ /*
+ * We maintain following scheme of buffers for ordered
+ * event allocation:
+ *
+ * to_free list -> buffer1 (64K)
+ * buffer2 (64K)
+ * ...
+ *
+ * Each buffer keeps an array of ordered events objects:
+ * buffer -> event[0]
+ * event[1]
+ * ...
+ *
+ * Each allocated ordered event is linked to one of
+ * following lists:
+ * - time ordered list 'events'
+ * - list of currently removed events 'cache'
+ *
+ * Allocation of the ordered event uses following order
+ * to get the memory:
+ * - use recently removed object from 'cache' list
+ * - use available object in current allocation buffer
+ * - allocate new buffer if the current buffer is full
+ *
+ * Removal of ordered event object moves it from events to
+ * the cache list.
+ */
if (!list_empty(cache)) {
new = list_entry(cache->next, struct ordered_event, list);
list_del(&new->list);
} else if (oe->buffer) {
- new = oe->buffer + oe->buffer_idx;
+ new = &oe->buffer->event[oe->buffer_idx];
if (++oe->buffer_idx == MAX_SAMPLE_BUFFER)
oe->buffer = NULL;
} else if (oe->cur_alloc_size < oe->max_alloc_size) {
- size_t size = MAX_SAMPLE_BUFFER * sizeof(*new);
+ size_t size = sizeof(*oe->buffer) +
+ MAX_SAMPLE_BUFFER * sizeof(*new);
oe->buffer = malloc(size);
if (!oe->buffer) {
@@ -122,9 +156,8 @@ static struct ordered_event *alloc_event(struct ordered_events *oe,
oe->cur_alloc_size += size;
list_add(&oe->buffer->list, &oe->to_free);
- /* First entry is abused to maintain the to_free list. */
- oe->buffer_idx = 2;
- new = oe->buffer + 1;
+ oe->buffer_idx = 1;
+ new = &oe->buffer->event[0];
} else {
pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size);
}
@@ -300,15 +333,35 @@ void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t d
oe->deliver = deliver;
}
+static void
+ordered_events_buffer__free(struct ordered_events_buffer *buffer,
+ unsigned int max, struct ordered_events *oe)
+{
+ if (oe->copy_on_queue) {
+ unsigned int i;
+
+ for (i = 0; i < max; i++)
+ __free_dup_event(oe, buffer->event[i].event);
+ }
+
+ free(buffer);
+}
+
void ordered_events__free(struct ordered_events *oe)
{
- while (!list_empty(&oe->to_free)) {
- struct ordered_event *event;
+ struct ordered_events_buffer *buffer, *tmp;
- event = list_entry(oe->to_free.next, struct ordered_event, list);
- list_del(&event->list);
- free_dup_event(oe, event->event);
- free(event);
+ /*
+ * Current buffer might not have all the events allocated
+ * yet, we need to free only allocated ones ...
+ */
+ list_del(&oe->buffer->list);
+ ordered_events_buffer__free(oe->buffer, oe->buffer_idx, oe);
+
+ /* ... and continue with the rest */
+ list_for_each_entry_safe(buffer, tmp, &oe->to_free, list) {
+ list_del(&buffer->list);
+ ordered_events_buffer__free(buffer, MAX_SAMPLE_BUFFER, oe);
}
}
diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h
index 8c7a2948593e..1338d5c345dc 100644
--- a/tools/perf/util/ordered-events.h
+++ b/tools/perf/util/ordered-events.h
@@ -25,23 +25,28 @@ struct ordered_events;
typedef int (*ordered_events__deliver_t)(struct ordered_events *oe,
struct ordered_event *event);
+struct ordered_events_buffer {
+ struct list_head list;
+ struct ordered_event event[0];
+};
+
struct ordered_events {
- u64 last_flush;
- u64 next_flush;
- u64 max_timestamp;
- u64 max_alloc_size;
- u64 cur_alloc_size;
- struct list_head events;
- struct list_head cache;
- struct list_head to_free;
- struct ordered_event *buffer;
- struct ordered_event *last;
- ordered_events__deliver_t deliver;
- int buffer_idx;
- unsigned int nr_events;
- enum oe_flush last_flush_type;
- u32 nr_unordered_events;
- bool copy_on_queue;
+ u64 last_flush;
+ u64 next_flush;
+ u64 max_timestamp;
+ u64 max_alloc_size;
+ u64 cur_alloc_size;
+ struct list_head events;
+ struct list_head cache;
+ struct list_head to_free;
+ struct ordered_events_buffer *buffer;
+ struct ordered_event *last;
+ ordered_events__deliver_t deliver;
+ int buffer_idx;
+ unsigned int nr_events;
+ enum oe_flush last_flush_type;
+ u32 nr_unordered_events;
+ bool copy_on_queue;
};
int ordered_events__queue(struct ordered_events *oe, union perf_event *event,
next prev parent reply other threads:[~2018-08-15 8:48 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-08-08 22:33 [PATCH v2] perf ordered_events: fix crash in free_dup_event() Stephane Eranian
2018-08-09 8:07 ` Jiri Olsa
2018-08-10 8:21 ` Stephane Eranian
2018-08-10 11:54 ` Jiri Olsa
2018-08-13 13:04 ` [PATCH] perf tools: Add struct ordered_events_buffer layer Jiri Olsa
2018-08-14 7:14 ` Stephane Eranian
2018-08-15 8:48 ` Jiri Olsa [this message]
2018-08-27 9:28 ` [PATCHv2] " Jiri Olsa
2018-08-27 11:07 ` Namhyung Kim
2018-08-27 15:24 ` Stephane Eranian
2018-08-27 17:05 ` [PATCHv3] " Jiri Olsa
2018-09-02 14:47 ` Jiri Olsa
2018-09-04 2:37 ` Stephane Eranian
2018-09-06 13:28 ` Jiri Olsa
2018-09-06 15:04 ` Stephane Eranian
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180815084825.GD3180@krava \
--to=jolsa@redhat.com \
--cc=acme@redhat.com \
--cc=eranian@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=peterz@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.