Skip to content

Commit

Permalink
perf tools: Unify perf.data mapping and events handling
Browse files Browse the repository at this point in the history
This librarizes the perf.data file mapping and handling in various
perf tools, roughly reducing the amount of code and fixing the
places that mmap from beginning of the file whereas we want to mmap
from the beginning of the data, leading to page fault because the
mmap window is too small since the trace info are written in the
file too.

TODO:

 - convert perf timechart too

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arjan van de Ven <arjan@infradead.org>
LKML-Reference: <20091007104729.GD5043@nowhere>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Frederic Weisbecker authored and Ingo Molnar committed Oct 8, 2009
1 parent 03456a1 commit 016e92f
Show file tree
Hide file tree
Showing 6 changed files with 334 additions and 401 deletions.
2 changes: 2 additions & 0 deletions tools/perf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ LIB_H += util/values.h
LIB_H += util/sort.h
LIB_H += util/hist.h
LIB_H += util/thread.h
LIB_H += util/data_map.h

LIB_OBJS += util/abspath.o
LIB_OBJS += util/alias.o
Expand Down Expand Up @@ -378,6 +379,7 @@ LIB_OBJS += util/trace-event-info.o
LIB_OBJS += util/svghelper.o
LIB_OBJS += util/sort.o
LIB_OBJS += util/hist.o
LIB_OBJS += util/data_map.o

BUILTIN_OBJS += builtin-annotate.o
BUILTIN_OBJS += builtin-help.o
Expand Down
211 changes: 34 additions & 177 deletions tools/perf/builtin-report.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "util/parse-options.h"
#include "util/parse-events.h"

#include "util/data_map.h"
#include "util/thread.h"
#include "util/sort.h"
#include "util/hist.h"
Expand All @@ -37,7 +38,6 @@ static char *dso_list_str, *comm_list_str, *sym_list_str,
static struct strlist *dso_list, *comm_list, *sym_list;

static int force;
static int input;

static int full_paths;
static int show_nr_samples;
Expand All @@ -48,15 +48,11 @@ static struct perf_read_values show_threads_values;
static char default_pretty_printing_style[] = "normal";
static char *pretty_printing_style = default_pretty_printing_style;

static unsigned long page_size;
static unsigned long mmap_window = 32;

static int exclude_other = 1;

static char callchain_default_opt[] = "fractal,0.5";

static char __cwd[PATH_MAX];
static char *cwd = __cwd;
static char *cwd;
static int cwdlen;

static struct rb_root threads;
Expand Down Expand Up @@ -815,208 +811,71 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
return 0;
}

static int
process_event(event_t *event, unsigned long offset, unsigned long head)
{
trace_event(event);

switch (event->header.type) {
case PERF_RECORD_SAMPLE:
return process_sample_event(event, offset, head);

case PERF_RECORD_MMAP:
return process_mmap_event(event, offset, head);

case PERF_RECORD_COMM:
return process_comm_event(event, offset, head);

case PERF_RECORD_FORK:
case PERF_RECORD_EXIT:
return process_task_event(event, offset, head);

case PERF_RECORD_LOST:
return process_lost_event(event, offset, head);

case PERF_RECORD_READ:
return process_read_event(event, offset, head);

/*
* We dont process them right now but they are fine:
*/

case PERF_RECORD_THROTTLE:
case PERF_RECORD_UNTHROTTLE:
return 0;

default:
return -1;
}

return 0;
}

static int __cmd_report(void)
static int sample_type_check(u64 type)
{
int ret, rc = EXIT_FAILURE;
unsigned long offset = 0;
unsigned long head, shift;
struct stat input_stat;
struct thread *idle;
event_t *event;
uint32_t size;
char *buf;

idle = register_idle_thread(&threads, &last_match);
thread__comm_adjust(idle);

if (show_threads)
perf_read_values_init(&show_threads_values);

input = open(input_name, O_RDONLY);
if (input < 0) {
fprintf(stderr, " failed to open file: %s", input_name);
if (!strcmp(input_name, "perf.data"))
fprintf(stderr, " (try 'perf record' first)");
fprintf(stderr, "\n");
exit(-1);
}

ret = fstat(input, &input_stat);
if (ret < 0) {
perror("failed to stat file");
exit(-1);
}

if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
exit(-1);
}

if (!input_stat.st_size) {
fprintf(stderr, "zero-sized file, nothing to do!\n");
exit(0);
}

header = perf_header__read(input);
head = header->data_offset;

sample_type = perf_header__sample_type(header);
sample_type = type;

if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
if (sort__has_parent) {
fprintf(stderr, "selected --sort parent, but no"
" callchain data. Did you call"
" perf record without -g?\n");
exit(-1);
return -1;
}
if (callchain) {
fprintf(stderr, "selected -g but no callchain data."
" Did you call perf record without"
" -g?\n");
exit(-1);
return -1;
}
} else if (callchain_param.mode != CHAIN_NONE && !callchain) {
callchain = 1;
if (register_callchain_param(&callchain_param) < 0) {
fprintf(stderr, "Can't register callchain"
" params\n");
exit(-1);
return -1;
}
}

if (load_kernel() < 0) {
perror("failed to load kernel symbols");
return EXIT_FAILURE;
}

if (!full_paths) {
if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
perror("failed to get the current directory");
return EXIT_FAILURE;
}
cwdlen = strlen(cwd);
} else {
cwd = NULL;
cwdlen = 0;
}

shift = page_size * (head / page_size);
offset += shift;
head -= shift;

remap:
buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
MAP_SHARED, input, offset);
if (buf == MAP_FAILED) {
perror("failed to mmap file");
exit(-1);
}

more:
event = (event_t *)(buf + head);

size = event->header.size;
if (!size)
size = 8;

if (head + event->header.size >= page_size * mmap_window) {
int munmap_ret;

shift = page_size * (head / page_size);

munmap_ret = munmap(buf, page_size * mmap_window);
assert(munmap_ret == 0);

offset += shift;
head -= shift;
goto remap;
}

size = event->header.size;

dump_printf("\n%p [%p]: event: %d\n",
(void *)(offset + head),
(void *)(long)event->header.size,
event->header.type);

if (!size || process_event(event, offset, head) < 0) {

dump_printf("%p [%p]: skipping unknown header type: %d\n",
(void *)(offset + head),
(void *)(long)(event->header.size),
event->header.type);

total_unknown++;
return 0;
}

/*
* assume we lost track of the stream, check alignment, and
* increment a single u64 in the hope to catch on again 'soon'.
*/
static struct perf_file_handler file_handler = {
.process_sample_event = process_sample_event,
.process_mmap_event = process_mmap_event,
.process_comm_event = process_comm_event,
.process_exit_event = process_task_event,
.process_fork_event = process_task_event,
.process_lost_event = process_lost_event,
.process_read_event = process_read_event,
.sample_type_check = sample_type_check,
};

if (unlikely(head & 7))
head &= ~7ULL;

size = 8;
}
static int __cmd_report(void)
{
struct thread *idle;
int ret;

head += size;
idle = register_idle_thread(&threads, &last_match);
thread__comm_adjust(idle);

if (offset + head >= header->data_offset + header->data_size)
goto done;
if (show_threads)
perf_read_values_init(&show_threads_values);

if (offset + head < (unsigned long)input_stat.st_size)
goto more;
register_perf_file_handler(&file_handler);

done:
rc = EXIT_SUCCESS;
close(input);
ret = mmap_dispatch_perf_file(&header, input_name, force, full_paths,
&cwdlen, &cwd);
if (ret)
return ret;

dump_printf(" IP events: %10ld\n", total);
dump_printf(" mmap events: %10ld\n", total_mmap);
dump_printf(" comm events: %10ld\n", total_comm);
dump_printf(" fork events: %10ld\n", total_fork);
dump_printf(" lost events: %10ld\n", total_lost);
dump_printf(" unknown events: %10ld\n", total_unknown);
dump_printf(" unknown events: %10ld\n", file_handler.total_unknown);

if (dump_trace)
return 0;
Expand All @@ -1034,7 +893,7 @@ static int __cmd_report(void)
if (show_threads)
perf_read_values_destroy(&show_threads_values);

return rc;
return ret;
}

static int
Expand Down Expand Up @@ -1177,8 +1036,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
{
symbol__init();

page_size = getpagesize();

argc = parse_options(argc, argv, options, report_usage, 0);

setup_sorting();
Expand Down
Loading

0 comments on commit 016e92f

Please sign in to comment.