Skip to content

Commit

Permalink
perf evlist: Move the mmap array from perf_evsel
Browse files Browse the repository at this point in the history
Adopting the new model used in 'perf record', where we don't have a map
per thread per cpu, instead we have an mmap per cpu, established on the
first fd for that cpu and ask the kernel using the
PERF_EVENT_IOC_SET_OUTPUT ioctl to send events for the other fds on that
cpu for the one with the mmap.

The methods moved from perf_evsel to perf_evlist, but for easing review
they were modified in place, in evsel.c, the next patch will move the
migrated methods to evlist.c.

With this 'perf top' now uses the same mmap model used by 'perf record'
and the next patches will make 'perf record' use these new routines,
establishing a common codebase for both tools.

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 115d2d8 commit 70db753
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 77 deletions.
56 changes: 28 additions & 28 deletions tools/perf/builtin-top.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ static struct cpu_map *cpus;
static int realtime_prio = 0;
static bool group = false;
static unsigned int page_size;
static unsigned int mmap_pages = 16;
static unsigned int mmap_pages = 128;
static int freq = 1000; /* 1 KHz */

static int delay_secs = 2;
Expand Down Expand Up @@ -991,8 +991,7 @@ static int symbol_filter(struct map *map, struct symbol *sym)

static void event__process_sample(const event_t *self,
struct sample_data *sample,
struct perf_session *session,
struct perf_evsel *evsel)
struct perf_session *session)
{
u64 ip = self->ip.ip;
struct sym_entry *syme;
Expand Down Expand Up @@ -1085,8 +1084,12 @@ static void event__process_sample(const event_t *self,

syme = symbol__priv(al.sym);
if (!syme->skip) {
syme->count[evsel->idx]++;
struct perf_evsel *evsel;

syme->origin = origin;
evsel = perf_evlist__id2evsel(evsel_list, sample->id);
assert(evsel != NULL);
syme->count[evsel->idx]++;
record_precise_ip(syme, evsel->idx, ip);
pthread_mutex_lock(&active_symbols_lock);
if (list_empty(&syme->node) || !syme->node.next)
Expand All @@ -1095,11 +1098,9 @@ static void event__process_sample(const event_t *self,
}
}

static void perf_session__mmap_read_counter(struct perf_session *self,
struct perf_evsel *evsel,
int cpu, int thread_idx)
static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu)
{
struct perf_mmap *md = xyarray__entry(evsel->mmap, cpu, thread_idx);
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;
Expand Down Expand Up @@ -1153,7 +1154,7 @@ static void perf_session__mmap_read_counter(struct perf_session *self,

event__parse_sample(event, self, &sample);
if (event->header.type == PERF_RECORD_SAMPLE)
event__process_sample(event, &sample, self, evsel);
event__process_sample(event, &sample, self);
else
event__process(event, &sample, self);
old += size;
Expand All @@ -1164,19 +1165,10 @@ static void perf_session__mmap_read_counter(struct perf_session *self,

static void perf_session__mmap_read(struct perf_session *self)
{
struct perf_evsel *counter;
int i, thread_index;

for (i = 0; i < cpus->nr; i++) {
list_for_each_entry(counter, &evsel_list->entries, node) {
for (thread_index = 0;
thread_index < threads->nr;
thread_index++) {
perf_session__mmap_read_counter(self,
counter, i, thread_index);
}
}
}
int i;

for (i = 0; i < cpus->nr; i++)
perf_session__mmap_read_cpu(self, i);
}

static void start_counters(struct perf_evlist *evlist)
Expand All @@ -1194,6 +1186,11 @@ static void start_counters(struct perf_evlist *evlist)
attr->sample_freq = freq;
}

if (evlist->nr_entries > 1) {
attr->sample_type |= PERF_SAMPLE_ID;
attr->read_format |= PERF_FORMAT_ID;
}

attr->mmap = 1;
try_again:
if (perf_evsel__open(counter, cpus, threads, group, inherit) < 0) {
Expand Down Expand Up @@ -1225,15 +1222,16 @@ static void start_counters(struct perf_evlist *evlist)
die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
exit(-1);
}

if (perf_evsel__mmap(counter, cpus, threads, mmap_pages, evlist) < 0)
die("failed to mmap with %d (%s)\n", errno, strerror(errno));
}

if (perf_evlist__mmap(evlist, cpus, threads, mmap_pages, true) < 0)
die("failed to mmap with %d (%s)\n", errno, strerror(errno));
}

static int __cmd_top(void)
{
pthread_t thread;
struct perf_evsel *first;
int ret;
/*
* FIXME: perf_session__new should allow passing a O_MMAP, so that all this
Expand All @@ -1249,6 +1247,8 @@ static int __cmd_top(void)
event__synthesize_threads(event__process, session);

start_counters(evsel_list);
first = list_entry(evsel_list->entries.next, struct perf_evsel, node);
perf_session__set_sample_type(session, first->attr.sample_type);

/* Wait for a minimal set of events before starting the snapshot */
poll(evsel_list->pollfd, evsel_list->nr_fds, 100);
Expand Down Expand Up @@ -1394,8 +1394,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
usage_with_options(top_usage, options);

list_for_each_entry(pos, &evsel_list->entries, node) {
if (perf_evsel__alloc_mmap(pos, cpus->nr, threads->nr) < 0 ||
perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
goto out_free_fd;
/*
* Fill in the ones not specifically initialized via -c:
Expand All @@ -1406,7 +1405,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
pos->attr.sample_period = default_interval;
}

if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0)
if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0 ||
perf_evlist__alloc_mmap(evsel_list, cpus->nr) < 0)
goto out_free_fd;

sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node);
Expand Down
27 changes: 27 additions & 0 deletions tools/perf/util/evlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@
#include "evsel.h"
#include "util.h"

#include <linux/bitops.h>
#include <linux/hash.h>

struct perf_evlist *perf_evlist__new(void)
{
struct perf_evlist *evlist = zalloc(sizeof(*evlist));

if (evlist != NULL) {
int i;

for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i)
INIT_HLIST_HEAD(&evlist->heads[i]);
INIT_LIST_HEAD(&evlist->entries);
}

Expand All @@ -29,6 +36,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist)
void perf_evlist__delete(struct perf_evlist *evlist)
{
perf_evlist__purge(evlist);
free(evlist->mmap);
free(evlist->pollfd);
free(evlist);
}
Expand Down Expand Up @@ -68,3 +76,22 @@ void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
evlist->pollfd[evlist->nr_fds].events = POLLIN;
evlist->nr_fds++;
}

struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
{
struct hlist_head *head;
struct hlist_node *pos;
struct perf_sample_id *sid;
int hash;

if (evlist->nr_entries == 1)
return list_entry(evlist->entries.next, struct perf_evsel, node);

hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
head = &evlist->heads[hash];

hlist_for_each_entry(sid, pos, head, node)
if (sid->id == id)
return sid->evsel;
return NULL;
}
9 changes: 9 additions & 0 deletions tools/perf/util/evlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@
#define __PERF_EVLIST_H 1

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

struct pollfd;

#define PERF_EVLIST__HLIST_BITS 8
#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)

struct perf_evlist {
struct list_head entries;
struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
int nr_entries;
int nr_fds;
int mmap_len;
struct perf_mmap *mmap;
struct pollfd *pollfd;
};

Expand All @@ -23,4 +30,6 @@ int perf_evlist__add_default(struct perf_evlist *evlist);
int perf_evlist__alloc_pollfd(struct perf_evlist *evlist, int ncpus, int nthreads);
void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);

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

#endif /* __PERF_EVLIST_H */
Loading

0 comments on commit 70db753

Please sign in to comment.