Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 234351
b: refs/heads/master
c: de5fa3a
h: refs/heads/master
i:
  234349: ae3fa03
  234347: a863c12
  234343: c614a5e
  234335: f084cd5
v: v3
  • Loading branch information
Arnaldo Carvalho de Melo committed Jan 22, 2011
1 parent 9a98aaa commit c9ea4f1
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 04391debc3e1195222a4dbb162ace6542dd89c1c
refs/heads/master: de5fa3a8a05cd60f59622e88cfeb90416760d78e
171 changes: 169 additions & 2 deletions trunk/tools/perf/builtin-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@

#include "util/cache.h"
#include "util/debug.h"
#include "util/evlist.h"
#include "util/parse-options.h"
#include "util/parse-events.h"
#include "util/session.h"
#include "util/symbol.h"
#include "util/thread.h"
Expand Down Expand Up @@ -238,14 +240,14 @@ static int test__vmlinux_matches_kallsyms(void)
#include "util/evsel.h"
#include <sys/types.h>

static int trace_event__id(const char *event_name)
static int trace_event__id(const char *evname)
{
char *filename;
int err = -1, fd;

if (asprintf(&filename,
"/sys/kernel/debug/tracing/events/syscalls/%s/id",
event_name) < 0)
evname) < 0)
return -1;

fd = open(filename, O_RDONLY);
Expand Down Expand Up @@ -439,6 +441,167 @@ static int test__open_syscall_event_on_all_cpus(void)
return err;
}

/*
* This test will generate random numbers of calls to some getpid syscalls,
* then establish an mmap for a group of events that are created to monitor
* the syscalls.
*
* It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
* sample.id field to map back to its respective perf_evsel instance.
*
* Then it checks if the number of syscalls reported as perf events by
* the kernel corresponds to the number of syscalls made.
*/
static int test__basic_mmap(void)
{
int err = -1;
event_t *event;
struct thread_map *threads;
struct perf_session session;
struct cpu_map *cpus;
struct perf_evlist *evlist;
struct perf_event_attr attr = {
.type = PERF_TYPE_TRACEPOINT,
.read_format = PERF_FORMAT_ID,
.sample_type = PERF_SAMPLE_ID,
.watermark = 0,
};
cpu_set_t cpu_set;
const char *syscall_names[] = { "getsid", "getppid", "getpgrp",
"getpgid", };
pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp,
(void*)getpgid };
#define nsyscalls ARRAY_SIZE(syscall_names)
int ids[nsyscalls];
unsigned int nr_events[nsyscalls],
expected_nr_events[nsyscalls], i, j;
struct perf_evsel *evsels[nsyscalls], *evsel;

for (i = 0; i < nsyscalls; ++i) {
char name[64];

snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
ids[i] = trace_event__id(name);
if (ids[i] < 0) {
pr_debug("Is debugfs mounted on /sys/kernel/debug?\n");
return -1;
}
nr_events[i] = 0;
expected_nr_events[i] = random() % 257;
}

threads = thread_map__new(-1, getpid());
if (threads == NULL) {
pr_debug("thread_map__new\n");
return -1;
}

cpus = cpu_map__new(NULL);
if (threads == NULL) {
pr_debug("thread_map__new\n");
goto out_free_threads;
}

CPU_ZERO(&cpu_set);
CPU_SET(cpus->map[0], &cpu_set);
sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
pr_debug("sched_setaffinity() failed on CPU %d: %s ",
cpus->map[0], strerror(errno));
goto out_free_cpus;
}

evlist = perf_evlist__new();
if (threads == NULL) {
pr_debug("perf_evlist__new\n");
goto out_free_cpus;
}

/* anonymous union fields, can't be initialized above */
attr.wakeup_events = 1;
attr.sample_period = 1;

/*
* FIXME: use evsel->attr.sample_type in event__parse_sample.
* This will nicely remove the requirement that we have
* all the events with the same sample_type.
*/
session.sample_type = attr.sample_type;

for (i = 0; i < nsyscalls; ++i) {
attr.config = ids[i];
evsels[i] = perf_evsel__new(&attr, i);
if (evsels[i] == NULL) {
pr_debug("perf_evsel__new\n");
goto out_free_evlist;
}

perf_evlist__add(evlist, evsels[i]);

if (perf_evsel__open(evsels[i], cpus, threads, false, false) < 0) {
pr_debug("failed to open counter: %s, "
"tweak /proc/sys/kernel/perf_event_paranoid?\n",
strerror(errno));
goto out_close_fd;
}
}

if (perf_evlist__mmap(evlist, cpus, threads, 128, true) < 0) {
pr_debug("failed to mmap events: %d (%s)\n", errno,
strerror(errno));
goto out_close_fd;
}

for (i = 0; i < nsyscalls; ++i)
for (j = 0; j < expected_nr_events[i]; ++j) {
int foo = syscalls[i]();
++foo;
}

while ((event = perf_evlist__read_on_cpu(evlist, 0)) != NULL) {
struct sample_data sample;

if (event->header.type != PERF_RECORD_SAMPLE) {
pr_debug("unexpected %s event\n",
event__get_event_name(event->header.type));
goto out_munmap;
}

event__parse_sample(event, &session, &sample);
evsel = perf_evlist__id2evsel(evlist, sample.id);
if (evsel == NULL) {
pr_debug("event with id %" PRIu64
" doesn't map to an evsel\n", sample.id);
goto out_munmap;
}
nr_events[evsel->idx]++;
}

list_for_each_entry(evsel, &evlist->entries, node) {
if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
pr_debug("expected %d %s events, got %d\n",
expected_nr_events[evsel->idx],
event_name(evsel), nr_events[evsel->idx]);
goto out_munmap;
}
}

err = 0;
out_munmap:
perf_evlist__munmap(evlist, 1);
out_close_fd:
for (i = 0; i < nsyscalls; ++i)
perf_evsel__close_fd(evsels[i], 1, threads->nr);
out_free_evlist:
perf_evlist__delete(evlist);
out_free_cpus:
cpu_map__delete(cpus);
out_free_threads:
thread_map__delete(threads);
return err;
#undef nsyscalls
}

static struct test {
const char *desc;
int (*func)(void);
Expand All @@ -455,6 +618,10 @@ static struct test {
.desc = "detect open syscall event on all cpus",
.func = test__open_syscall_event_on_all_cpus,
},
{
.desc = "read samples using the mmap interface",
.func = test__basic_mmap,
},
{
.func = NULL,
},
Expand Down

0 comments on commit c9ea4f1

Please sign in to comment.