Commit 7a77bc2c authored by Adrian Hunter's avatar Adrian Hunter Committed by Arnaldo Carvalho de Melo

perf tests: Add kcore to the object code reading test

Make the "object code reading" test attempt to read from kcore.

The test uses objdump which struggles with kcore. i.e.  doesn't always
work, sometimes takes a long time.  The test has been made to work
around those issues.
Signed-off-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1375875537-4509-10-git-send-email-adrian.hunter@intel.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 82e75d00
......@@ -20,6 +20,11 @@
#define BUFSZ 1024
#define READLEN 128
struct state {
u64 done[1024];
size_t done_cnt;
};
static unsigned int hex(char c)
{
if (c >= '0' && c <= '9')
......@@ -107,6 +112,9 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
pr_debug("Objdump command is: %s\n", cmd);
/* Ignore objdump errors */
strcat(cmd, " 2>/dev/null");
f = popen(cmd, "r");
if (!f) {
pr_debug("popen failed\n");
......@@ -126,7 +134,8 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
}
static int read_object_code(u64 addr, size_t len, u8 cpumode,
struct thread *thread, struct machine *machine)
struct thread *thread, struct machine *machine,
struct state *state)
{
struct addr_location al;
unsigned char buf1[BUFSZ];
......@@ -146,7 +155,8 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
pr_debug("File is: %s\n", al.map->dso->long_name);
if (al.map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
if (al.map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
!dso__is_kcore(al.map->dso)) {
pr_debug("Unexpected kernel address - skipping\n");
return 0;
}
......@@ -175,6 +185,24 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
if (map__load(al.map, NULL))
return -1;
/* objdump struggles with kcore - try each map only once */
if (dso__is_kcore(al.map->dso)) {
size_t d;
for (d = 0; d < state->done_cnt; d++) {
if (state->done[d] == al.map->start) {
pr_debug("kcore map tested already");
pr_debug(" - skipping\n");
return 0;
}
}
if (state->done_cnt >= ARRAY_SIZE(state->done)) {
pr_debug("Too many kcore maps - skipping\n");
return 0;
}
state->done[state->done_cnt++] = al.map->start;
}
/* Read the object code using objdump */
objdump_addr = map__rip_2objdump(al.map, al.addr);
ret = read_via_objdump(al.map->dso->long_name, objdump_addr, buf2, len);
......@@ -186,10 +214,19 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
if (cpumode == PERF_RECORD_MISC_KERNEL ||
cpumode == PERF_RECORD_MISC_GUEST_KERNEL) {
len -= ret;
if (len)
if (len) {
pr_debug("Reducing len to %zu\n", len);
else
} else if (dso__is_kcore(al.map->dso)) {
/*
* objdump cannot handle very large segments
* that may be found in kcore.
*/
pr_debug("objdump failed for kcore");
pr_debug(" - skipping\n");
return 0;
} else {
return -1;
}
}
}
if (ret < 0) {
......@@ -209,7 +246,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
static int process_sample_event(struct machine *machine,
struct perf_evlist *evlist,
union perf_event *event)
union perf_event *event, struct state *state)
{
struct perf_sample sample;
struct thread *thread;
......@@ -228,14 +265,15 @@ static int process_sample_event(struct machine *machine,
cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
return read_object_code(sample.ip, READLEN, cpumode, thread, machine);
return read_object_code(sample.ip, READLEN, cpumode, thread, machine,
state);
}
static int process_event(struct machine *machine, struct perf_evlist *evlist,
union perf_event *event)
union perf_event *event, struct state *state)
{
if (event->header.type == PERF_RECORD_SAMPLE)
return process_sample_event(machine, evlist, event);
return process_sample_event(machine, evlist, event, state);
if (event->header.type < PERF_RECORD_MAX)
return machine__process_event(machine, event);
......@@ -243,14 +281,15 @@ static int process_event(struct machine *machine, struct perf_evlist *evlist,
return 0;
}
static int process_events(struct machine *machine, struct perf_evlist *evlist)
static int process_events(struct machine *machine, struct perf_evlist *evlist,
struct state *state)
{
union perf_event *event;
int i, ret;
for (i = 0; i < evlist->nr_mmaps; i++) {
while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
ret = process_event(machine, evlist, event);
ret = process_event(machine, evlist, event, state);
if (ret < 0)
return ret;
}
......@@ -331,10 +370,12 @@ static void do_something(void)
enum {
TEST_CODE_READING_OK,
TEST_CODE_READING_NO_VMLINUX,
TEST_CODE_READING_NO_KCORE,
TEST_CODE_READING_NO_ACCESS,
TEST_CODE_READING_NO_KERNEL_OBJ,
};
static int do_test_code_reading(void)
static int do_test_code_reading(bool try_kcore)
{
struct machines machines;
struct machine *machine;
......@@ -348,6 +389,9 @@ static int do_test_code_reading(void)
.uses_mmap = true,
},
};
struct state state = {
.done_cnt = 0,
};
struct thread_map *threads = NULL;
struct cpu_map *cpus = NULL;
struct perf_evlist *evlist = NULL;
......@@ -355,7 +399,7 @@ static int do_test_code_reading(void)
int err = -1, ret;
pid_t pid;
struct map *map;
bool have_vmlinux, excl_kernel = false;
bool have_vmlinux, have_kcore, excl_kernel = false;
pid = getpid();
......@@ -368,6 +412,10 @@ static int do_test_code_reading(void)
goto out_err;
}
/* Force the use of kallsyms instead of vmlinux to try kcore */
if (try_kcore)
symbol_conf.kallsyms_name = "/proc/kallsyms";
/* Load kernel map */
map = machine->vmlinux_maps[MAP__FUNCTION];
ret = map__load(map, NULL);
......@@ -375,9 +423,15 @@ static int do_test_code_reading(void)
pr_debug("map__load failed\n");
goto out_err;
}
have_vmlinux = map->dso->symtab_type == DSO_BINARY_TYPE__VMLINUX;
/* No point getting kernel events if there is no vmlinux */
if (!have_vmlinux)
have_vmlinux = dso__is_vmlinux(map->dso);
have_kcore = dso__is_kcore(map->dso);
/* 2nd time through we just try kcore */
if (try_kcore && !have_kcore)
return TEST_CODE_READING_NO_KCORE;
/* No point getting kernel events if there is no kernel object */
if (!have_vmlinux && !have_kcore)
excl_kernel = true;
threads = thread_map__new_by_tid(pid);
......@@ -461,11 +515,13 @@ static int do_test_code_reading(void)
perf_evlist__disable(evlist);
ret = process_events(machine, evlist);
ret = process_events(machine, evlist, &state);
if (ret < 0)
goto out_err;
if (!have_vmlinux)
if (!have_vmlinux && !have_kcore && !try_kcore)
err = TEST_CODE_READING_NO_KERNEL_OBJ;
else if (!have_vmlinux && !try_kcore)
err = TEST_CODE_READING_NO_VMLINUX;
else if (excl_kernel)
err = TEST_CODE_READING_NO_ACCESS;
......@@ -492,7 +548,9 @@ int test__code_reading(void)
{
int ret;
ret = do_test_code_reading();
ret = do_test_code_reading(false);
if (!ret)
ret = do_test_code_reading(true);
switch (ret) {
case TEST_CODE_READING_OK:
......@@ -500,9 +558,15 @@ int test__code_reading(void)
case TEST_CODE_READING_NO_VMLINUX:
fprintf(stderr, " (no vmlinux)");
return 0;
case TEST_CODE_READING_NO_KCORE:
fprintf(stderr, " (no kcore)");
return 0;
case TEST_CODE_READING_NO_ACCESS:
fprintf(stderr, " (no access)");
return 0;
case TEST_CODE_READING_NO_KERNEL_OBJ:
fprintf(stderr, " (no kernel obj)");
return 0;
default:
return -1;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment