Skip to content

Commit

Permalink
perf evlist: Steal mmap reading routine from 'perf top'
Browse files Browse the repository at this point in the history
Will be used in the upcoming 'perf test' entry for the evlist mmap
routines.

Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Arnaldo Carvalho de Melo committed Jan 22, 2011
1 parent 98d77b7 commit 04391de
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 53 deletions.
56 changes: 3 additions & 53 deletions tools/perf/builtin-top.c
Original file line number Diff line number Diff line change
Expand Up @@ -1100,67 +1100,17 @@ static void event__process_sample(const event_t *self,

static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu)
{
struct perf_mmap *md = &evsel_list->mmap[cpu];
unsigned int head = perf_mmap__read_head(md);
unsigned int old = md->prev;
unsigned char *data = md->base + page_size;
struct sample_data sample;
int diff;

/*
* If we're further behind than half the buffer, there's a chance
* the writer will bite our tail and mess up the samples under us.
*
* If we somehow ended up ahead of the head, we got messed up.
*
* In either case, truncate and restart at head.
*/
diff = head - old;
if (diff > md->mask / 2 || diff < 0) {
fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");

/*
* head points to a known good entry, start there.
*/
old = head;
}

for (; old != head;) {
event_t *event = (event_t *)&data[old & md->mask];

event_t event_copy;

size_t size = event->header.size;

/*
* Event straddles the mmap boundary -- header should always
* be inside due to u64 alignment of output.
*/
if ((old & md->mask) + size != ((old + size) & md->mask)) {
unsigned int offset = old;
unsigned int len = min(sizeof(*event), size), cpy;
void *dst = &event_copy;

do {
cpy = min(md->mask + 1 - (offset & md->mask), len);
memcpy(dst, &data[offset & md->mask], cpy);
offset += cpy;
dst += cpy;
len -= cpy;
} while (len);

event = &event_copy;
}
event_t *event;

while ((event = perf_evlist__read_on_cpu(evsel_list, cpu)) != NULL) {
event__parse_sample(event, self, &sample);

if (event->header.type == PERF_RECORD_SAMPLE)
event__process_sample(event, &sample, self);
else
event__process(event, &sample, self);
old += size;
}

md->prev = old;
}

static void perf_session__mmap_read(struct perf_session *self)
Expand Down
62 changes: 62 additions & 0 deletions tools/perf/util/evlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,65 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
return sid->evsel;
return NULL;
}

event_t *perf_evlist__read_on_cpu(struct perf_evlist *evlist, int cpu)
{
/* XXX Move this to perf.c, making it generally available */
unsigned int page_size = sysconf(_SC_PAGE_SIZE);
struct perf_mmap *md = &evlist->mmap[cpu];
unsigned int head = perf_mmap__read_head(md);
unsigned int old = md->prev;
unsigned char *data = md->base + page_size;
event_t *event = NULL;
int diff;

/*
* If we're further behind than half the buffer, there's a chance
* the writer will bite our tail and mess up the samples under us.
*
* If we somehow ended up ahead of the head, we got messed up.
*
* In either case, truncate and restart at head.
*/
diff = head - old;
if (diff > md->mask / 2 || diff < 0) {
fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");

/*
* head points to a known good entry, start there.
*/
old = head;
}

if (old != head) {
size_t size;

event = (event_t *)&data[old & md->mask];
size = event->header.size;

/*
* Event straddles the mmap boundary -- header should always
* be inside due to u64 alignment of output.
*/
if ((old & md->mask) + size != ((old + size) & md->mask)) {
unsigned int offset = old;
unsigned int len = min(sizeof(*event), size), cpy;
void *dst = &evlist->event_copy;

do {
cpy = min(md->mask + 1 - (offset & md->mask), len);
memcpy(dst, &data[offset & md->mask], cpy);
offset += cpy;
dst += cpy;
len -= cpy;
} while (len);

event = &evlist->event_copy;
}

old += size;
}

md->prev = old;
return event;
}
4 changes: 4 additions & 0 deletions tools/perf/util/evlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <linux/list.h>
#include "../perf.h"
#include "event.h"

struct pollfd;

Expand All @@ -15,6 +16,7 @@ struct perf_evlist {
int nr_entries;
int nr_fds;
int mmap_len;
event_t event_copy;
struct perf_mmap *mmap;
struct pollfd *pollfd;
};
Expand All @@ -32,4 +34,6 @@ void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);

struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);

event_t *perf_evlist__read_on_cpu(struct perf_evlist *self, int cpu);

#endif /* __PERF_EVLIST_H */

0 comments on commit 04391de

Please sign in to comment.