diff --git a/[refs] b/[refs] index b45c7489ba2d..65308d8b064d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: fe6126722718e51fba4879517c11ac12d9775bcc +refs/heads/master: ff038f5c37c2070829004a0678372766c2b32180 diff --git a/trunk/arch/x86/kernel/cpu/perf_event.c b/trunk/arch/x86/kernel/cpu/perf_event.c index c1bbed1021d9..bd8743024204 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event.c +++ b/trunk/arch/x86/kernel/cpu/perf_event.c @@ -2229,10 +2229,10 @@ validate_event(struct cpu_hw_events *cpuc, struct perf_event *event) { struct hw_perf_event fake_event = event->hw; - if (event->pmu && event->pmu != &pmu) + if (event->pmu != &pmu) return 0; - return x86_schedule_event(cpuc, &fake_event) >= 0; + return x86_schedule_event(cpuc, &fake_event); } static int validate_group(struct perf_event *event) diff --git a/trunk/include/linux/tracepoint.h b/trunk/include/linux/tracepoint.h index 2aac8a83e89b..88a5b5a809ec 100644 --- a/trunk/include/linux/tracepoint.h +++ b/trunk/include/linux/tracepoint.h @@ -280,6 +280,10 @@ static inline void tracepoint_synchronize_unregister(void) * TRACE_EVENT_FN to perform any (un)registration work. */ +#define TRACE_EVENT_TEMPLATE(name, proto, args, tstruct, assign, print) +#define DEFINE_EVENT(template, name, proto, args) \ + DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) + #define TRACE_EVENT(name, proto, args, struct, assign, print) \ DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) #define TRACE_EVENT_FN(name, proto, args, struct, \ diff --git a/trunk/include/trace/define_trace.h b/trunk/include/trace/define_trace.h index 2a4b3bf74033..244985814a43 100644 --- a/trunk/include/trace/define_trace.h +++ b/trunk/include/trace/define_trace.h @@ -31,6 +31,10 @@ assign, print, reg, unreg) \ DEFINE_TRACE_FN(name, reg, unreg) +#undef DEFINE_EVENT +#define DEFINE_EVENT(template, name, proto, args) \ + DEFINE_TRACE(name) + #undef DECLARE_TRACE #define DECLARE_TRACE(name, proto, args) \ DEFINE_TRACE(name) @@ -63,6 +67,8 @@ #undef TRACE_EVENT #undef TRACE_EVENT_FN +#undef TRACE_EVENT_TEMPLATE +#undef DEFINE_EVENT #undef TRACE_HEADER_MULTI_READ /* Only undef what we defined in this file */ diff --git a/trunk/include/trace/ftrace.h b/trunk/include/trace/ftrace.h index c3417c13e3ed..2969f65d8002 100644 --- a/trunk/include/trace/ftrace.h +++ b/trunk/include/trace/ftrace.h @@ -18,6 +18,26 @@ #include +/* + * TRACE_EVENT_TEMPLATE can be used to add a generic function + * handlers for events. That is, if all events have the same + * parameters and just have distinct trace points. + * Each tracepoint can be defined with DEFINE_EVENT and that + * will map the TRACE_EVENT_TEMPLATE to the tracepoint. + * + * TRACE_EVENT is a one to one mapping between tracepoint and template. + */ +#undef TRACE_EVENT +#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \ + TRACE_EVENT_TEMPLATE(name, \ + PARAMS(proto), \ + PARAMS(args), \ + PARAMS(tstruct), \ + PARAMS(assign), \ + PARAMS(print)); \ + DEFINE_EVENT(name, name, PARAMS(proto), PARAMS(args)); + + #undef __field #define __field(type, item) type item; @@ -36,13 +56,15 @@ #undef TP_STRUCT__entry #define TP_STRUCT__entry(args...) args -#undef TRACE_EVENT -#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \ - struct ftrace_raw_##name { \ - struct trace_entry ent; \ - tstruct \ - char __data[0]; \ - }; \ +#undef TRACE_EVENT_TEMPLATE +#define TRACE_EVENT_TEMPLATE(name, proto, args, tstruct, assign, print) \ + struct ftrace_raw_##name { \ + struct trace_entry ent; \ + tstruct \ + char __data[0]; \ + }; +#undef DEFINE_EVENT +#define DEFINE_EVENT(template, name, proto, args) \ static struct ftrace_event_call event_##name #undef __cpparg @@ -89,12 +111,15 @@ #undef __string #define __string(item, src) __dynamic_array(char, item, -1) -#undef TRACE_EVENT -#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ +#undef TRACE_EVENT_TEMPLATE +#define TRACE_EVENT_TEMPLATE(call, proto, args, tstruct, assign, print) \ struct ftrace_data_offsets_##call { \ tstruct; \ }; +#undef DEFINE_EVENT +#define DEFINE_EVENT(template, name, proto, args) + #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) /* @@ -170,8 +195,8 @@ #undef TP_perf_assign #define TP_perf_assign(args...) -#undef TRACE_EVENT -#define TRACE_EVENT(call, proto, args, tstruct, func, print) \ +#undef TRACE_EVENT_TEMPLATE +#define TRACE_EVENT_TEMPLATE(call, proto, args, tstruct, func, print) \ static int \ ftrace_format_##call(struct ftrace_event_call *unused, \ struct trace_seq *s) \ @@ -186,6 +211,9 @@ ftrace_format_##call(struct ftrace_event_call *unused, \ return ret; \ } +#undef DEFINE_EVENT +#define DEFINE_EVENT(template, name, proto, args) + #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) /* @@ -255,10 +283,11 @@ ftrace_format_##call(struct ftrace_event_call *unused, \ ftrace_print_symbols_seq(p, value, symbols); \ }) -#undef TRACE_EVENT -#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ +#undef TRACE_EVENT_TEMPLATE +#define TRACE_EVENT_TEMPLATE(call, proto, args, tstruct, assign, print) \ static enum print_line_t \ -ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ +ftrace_raw_output_id_##call(int event_id, const char *name, \ + struct trace_iterator *iter, int flags) \ { \ struct trace_seq *s = &iter->seq; \ struct ftrace_raw_##call *field; \ @@ -268,7 +297,7 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ \ entry = iter->ent; \ \ - if (entry->type != event_##call.id) { \ + if (entry->type != event_id) { \ WARN_ON_ONCE(1); \ return TRACE_TYPE_UNHANDLED; \ } \ @@ -277,14 +306,25 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ \ p = &get_cpu_var(ftrace_event_seq); \ trace_seq_init(p); \ - ret = trace_seq_printf(s, #call ": " print); \ + ret = trace_seq_printf(s, "%s: ", name); \ + if (ret) \ + ret = trace_seq_printf(s, print); \ put_cpu(); \ if (!ret) \ return TRACE_TYPE_PARTIAL_LINE; \ \ return TRACE_TYPE_HANDLED; \ } - + +#undef DEFINE_EVENT +#define DEFINE_EVENT(template, name, proto, args) \ +static enum print_line_t \ +ftrace_raw_output_##name(struct trace_iterator *iter, int flags) \ +{ \ + return ftrace_raw_output_id_##template(event_##name.id, \ + #name, iter, flags); \ +} + #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) #undef __field_ext @@ -318,8 +358,8 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ #undef __string #define __string(item, src) __dynamic_array(char, item, -1) -#undef TRACE_EVENT -#define TRACE_EVENT(call, proto, args, tstruct, func, print) \ +#undef TRACE_EVENT_TEMPLATE +#define TRACE_EVENT_TEMPLATE(call, proto, args, tstruct, func, print) \ static int \ ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ { \ @@ -335,6 +375,9 @@ ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ return ret; \ } +#undef DEFINE_EVENT +#define DEFINE_EVENT(template, name, proto, args) + #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) /* @@ -361,10 +404,10 @@ ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ __data_size += (len) * sizeof(type); #undef __string -#define __string(item, src) __dynamic_array(char, item, strlen(src) + 1) \ +#define __string(item, src) __dynamic_array(char, item, strlen(src) + 1) -#undef TRACE_EVENT -#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ +#undef TRACE_EVENT_TEMPLATE +#define TRACE_EVENT_TEMPLATE(call, proto, args, tstruct, assign, print) \ static inline int ftrace_get_offsets_##call( \ struct ftrace_data_offsets_##call *__data_offsets, proto) \ { \ @@ -376,6 +419,9 @@ static inline int ftrace_get_offsets_##call( \ return __data_size; \ } +#undef DEFINE_EVENT +#define DEFINE_EVENT(template, name, proto, args) + #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) #ifdef CONFIG_EVENT_PROFILE @@ -397,19 +443,22 @@ static inline int ftrace_get_offsets_##call( \ * */ -#undef TRACE_EVENT -#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ +#undef TRACE_EVENT_TEMPLATE +#define TRACE_EVENT_TEMPLATE(call, proto, args, tstruct, assign, print) + +#undef DEFINE_EVENT +#define DEFINE_EVENT(template, name, proto, args) \ \ -static void ftrace_profile_##call(proto); \ +static void ftrace_profile_##name(proto); \ \ -static int ftrace_profile_enable_##call(struct ftrace_event_call *unused)\ +static int ftrace_profile_enable_##name(struct ftrace_event_call *unused)\ { \ - return register_trace_##call(ftrace_profile_##call); \ + return register_trace_##name(ftrace_profile_##name); \ } \ \ -static void ftrace_profile_disable_##call(struct ftrace_event_call *unused)\ +static void ftrace_profile_disable_##name(struct ftrace_event_call *unused)\ { \ - unregister_trace_##call(ftrace_profile_##call); \ + unregister_trace_##name(ftrace_profile_##name); \ } #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) @@ -550,15 +599,13 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *unused)\ #define __assign_str(dst, src) \ strcpy(__get_str(dst), src); -#undef TRACE_EVENT -#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ - \ -static struct ftrace_event_call event_##call; \ +#undef TRACE_EVENT_TEMPLATE +#define TRACE_EVENT_TEMPLATE(call, proto, args, tstruct, assign, print) \ \ -static void ftrace_raw_event_##call(proto) \ +static void ftrace_raw_event_id_##call(struct ftrace_event_call *event_call, \ + proto) \ { \ struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ - struct ftrace_event_call *event_call = &event_##call; \ struct ring_buffer_event *event; \ struct ftrace_raw_##call *entry; \ struct ring_buffer *buffer; \ @@ -572,7 +619,7 @@ static void ftrace_raw_event_##call(proto) \ __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ \ event = trace_current_buffer_lock_reserve(&buffer, \ - event_##call.id, \ + event_call->id, \ sizeof(*entry) + __data_size, \ irq_flags, pc); \ if (!event) \ @@ -587,6 +634,14 @@ static void ftrace_raw_event_##call(proto) \ if (!filter_current_check_discard(buffer, event_call, entry, event)) \ trace_nowake_buffer_unlock_commit(buffer, \ event, irq_flags, pc); \ +} + +#undef DEFINE_EVENT +#define DEFINE_EVENT(template, call, proto, args) \ + \ +static void ftrace_raw_event_##call(proto) \ +{ \ + ftrace_raw_event_id_##template(&event_##call, args); \ } \ \ static int ftrace_raw_reg_event_##call(struct ftrace_event_call *unused)\ @@ -630,8 +685,8 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ .raw_init = ftrace_raw_init_event_##call, \ .regfunc = ftrace_raw_reg_event_##call, \ .unregfunc = ftrace_raw_unreg_event_##call, \ - .show_format = ftrace_format_##call, \ - .define_fields = ftrace_define_fields_##call, \ + .show_format = ftrace_format_##template, \ + .define_fields = ftrace_define_fields_##template, \ _TRACE_PROFILE_INIT(call) \ } @@ -719,14 +774,15 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ #undef __perf_count #define __perf_count(c) __count = (c) -#undef TRACE_EVENT -#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ -static void ftrace_profile_##call(proto) \ +#undef TRACE_EVENT_TEMPLATE +#define TRACE_EVENT_TEMPLATE(call, proto, args, tstruct, assign, print) \ +static void \ +ftrace_profile_templ_##call(struct ftrace_event_call *event_call, \ + proto) \ { \ struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ extern int perf_swevent_get_recursion_context(void); \ extern void perf_swevent_put_recursion_context(int rctx); \ - struct ftrace_event_call *event_call = &event_##call; \ extern void perf_tp_event(int, u64, u64, void *, int); \ struct ftrace_raw_##call *entry; \ u64 __addr = 0, __count = 1; \ @@ -789,6 +845,15 @@ end_recursion: \ \ } +#undef DEFINE_EVENT +#define DEFINE_EVENT(template, call, proto, args) \ +static void ftrace_profile_##call(proto) \ +{ \ + struct ftrace_event_call *event_call = &event_##call; \ + \ + ftrace_profile_templ_##template(event_call, args); \ +} + #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) #endif /* CONFIG_EVENT_PROFILE */ diff --git a/trunk/kernel/perf_event.c b/trunk/kernel/perf_event.c index 35df94e344f2..9425c9600c89 100644 --- a/trunk/kernel/perf_event.c +++ b/trunk/kernel/perf_event.c @@ -1831,7 +1831,7 @@ static int perf_event_read_group(struct perf_event *event, size = n * sizeof(u64); - if (copy_to_user(buf + ret, values, size)) { + if (copy_to_user(buf + size, values, size)) { ret = -EFAULT; goto unlock; } @@ -3914,7 +3914,7 @@ void perf_swevent_put_recursion_context(int rctx) { struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); barrier(); - cpuctx->recursion[rctx]--; + cpuctx->recursion[rctx]++; put_cpu_var(perf_cpu_context); } EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context); diff --git a/trunk/tools/perf/.gitignore b/trunk/tools/perf/.gitignore index fe08660ce0bd..0854f110bf7f 100644 --- a/trunk/tools/perf/.gitignore +++ b/trunk/tools/perf/.gitignore @@ -12,7 +12,6 @@ perf*.1 perf*.xml perf*.html common-cmds.h -perf.data tags TAGS cscope* diff --git a/trunk/tools/perf/Documentation/perf-kmem.txt b/trunk/tools/perf/Documentation/perf-kmem.txt deleted file mode 100644 index 44b0ce35c28a..000000000000 --- a/trunk/tools/perf/Documentation/perf-kmem.txt +++ /dev/null @@ -1,44 +0,0 @@ -perf-kmem(1) -============== - -NAME ----- -perf-kmem - Tool to trace/measure kernel memory(slab) properties - -SYNOPSIS --------- -[verse] -'perf kmem' {record} [] - -DESCRIPTION ------------ -There's two variants of perf kmem: - - 'perf kmem record ' to record the kmem events - of an arbitrary workload. - - 'perf kmem' to report kernel memory statistics. - -OPTIONS -------- --i :: ---input=:: - Select the input file (default: perf.data) - ---stat=:: - Select per callsite or per allocation statistics - --s :: ---sort=:: - Sort the output (default: frag,hit,bytes) - --l :: ---line=:: - Print n lines only - ---raw-ip:: - Print raw ip instead of symbol - -SEE ALSO --------- -linkperf:perf-record[1] diff --git a/trunk/tools/perf/Makefile b/trunk/tools/perf/Makefile index de37d492e10f..3ef6621bf6cd 100644 --- a/trunk/tools/perf/Makefile +++ b/trunk/tools/perf/Makefile @@ -369,7 +369,6 @@ LIB_H += util/sort.h LIB_H += util/hist.h LIB_H += util/thread.h LIB_H += util/data_map.h -LIB_H += util/process_events.h LIB_OBJS += util/abspath.o LIB_OBJS += util/alias.o @@ -412,7 +411,6 @@ LIB_OBJS += util/svghelper.o LIB_OBJS += util/sort.o LIB_OBJS += util/hist.o LIB_OBJS += util/data_map.o -LIB_OBJS += util/process_events.o BUILTIN_OBJS += builtin-annotate.o @@ -421,7 +419,6 @@ BUILTIN_OBJS += builtin-bench.o # Benchmark modules BUILTIN_OBJS += bench/sched-messaging.o BUILTIN_OBJS += bench/sched-pipe.o -BUILTIN_OBJS += bench/mem-memcpy.o BUILTIN_OBJS += builtin-help.o BUILTIN_OBJS += builtin-sched.o diff --git a/trunk/tools/perf/bench/bench.h b/trunk/tools/perf/bench/bench.h index f7781c6267c0..9fbd8d745fa1 100644 --- a/trunk/tools/perf/bench/bench.h +++ b/trunk/tools/perf/bench/bench.h @@ -3,7 +3,6 @@ extern int bench_sched_messaging(int argc, const char **argv, const char *prefix); extern int bench_sched_pipe(int argc, const char **argv, const char *prefix); -extern int bench_mem_memcpy(int argc, const char **argv, const char *prefix __used); #define BENCH_FORMAT_DEFAULT_STR "default" #define BENCH_FORMAT_DEFAULT 0 diff --git a/trunk/tools/perf/bench/mem-memcpy.c b/trunk/tools/perf/bench/mem-memcpy.c deleted file mode 100644 index 89773178e894..000000000000 --- a/trunk/tools/perf/bench/mem-memcpy.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * mem-memcpy.c - * - * memcpy: Simple memory copy in various ways - * - * Written by Hitoshi Mitake - */ -#include - -#include "../perf.h" -#include "../util/util.h" -#include "../util/parse-options.h" -#include "../util/string.h" -#include "../util/header.h" -#include "bench.h" - -#include -#include -#include -#include -#include - -#define K 1024 - -static const char *length_str = "1MB"; -static const char *routine = "default"; -static int use_clock = 0; -static int clock_fd; - -static const struct option options[] = { - OPT_STRING('l', "length", &length_str, "1MB", - "Specify length of memory to copy. " - "available unit: B, MB, GB (upper and lower)"), - OPT_STRING('r', "routine", &routine, "default", - "Specify routine to copy"), - OPT_BOOLEAN('c', "clock", &use_clock, - "Use CPU clock for measuring"), - OPT_END() -}; - -struct routine { - const char *name; - const char *desc; - void * (*fn)(void *dst, const void *src, size_t len); -}; - -struct routine routines[] = { - { "default", - "Default memcpy() provided by glibc", - memcpy }, - { NULL, - NULL, - NULL } -}; - -static const char * const bench_mem_memcpy_usage[] = { - "perf bench mem memcpy ", - NULL -}; - -static struct perf_event_attr clock_attr = { - .type = PERF_TYPE_HARDWARE, - .config = PERF_COUNT_HW_CPU_CYCLES -}; - -static void init_clock(void) -{ - clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0); - - if (clock_fd < 0 && errno == ENOSYS) - die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); - else - BUG_ON(clock_fd < 0); -} - -static u64 get_clock(void) -{ - int ret; - u64 clk; - - ret = read(clock_fd, &clk, sizeof(u64)); - BUG_ON(ret != sizeof(u64)); - - return clk; -} - -static double timeval2double(struct timeval *ts) -{ - return (double)ts->tv_sec + - (double)ts->tv_usec / (double)1000000; -} - -int bench_mem_memcpy(int argc, const char **argv, - const char *prefix __used) -{ - int i; - void *dst, *src; - size_t length; - double bps = 0.0; - struct timeval tv_start, tv_end, tv_diff; - u64 clock_start, clock_end, clock_diff; - - clock_start = clock_end = clock_diff = 0ULL; - argc = parse_options(argc, argv, options, - bench_mem_memcpy_usage, 0); - - tv_diff.tv_sec = 0; - tv_diff.tv_usec = 0; - length = (size_t)perf_atoll((char *)length_str); - - if ((s64)length <= 0) { - fprintf(stderr, "Invalid length:%s\n", length_str); - return 1; - } - - for (i = 0; routines[i].name; i++) { - if (!strcmp(routines[i].name, routine)) - break; - } - if (!routines[i].name) { - printf("Unknown routine:%s\n", routine); - printf("Available routines...\n"); - for (i = 0; routines[i].name; i++) { - printf("\t%s ... %s\n", - routines[i].name, routines[i].desc); - } - return 1; - } - - dst = zalloc(length); - if (!dst) - die("memory allocation failed - maybe length is too large?\n"); - - src = zalloc(length); - if (!src) - die("memory allocation failed - maybe length is too large?\n"); - - if (bench_format == BENCH_FORMAT_DEFAULT) { - printf("# Copying %s Bytes from %p to %p ...\n\n", - length_str, src, dst); - } - - if (use_clock) { - init_clock(); - clock_start = get_clock(); - } else { - BUG_ON(gettimeofday(&tv_start, NULL)); - } - - routines[i].fn(dst, src, length); - - if (use_clock) { - clock_end = get_clock(); - clock_diff = clock_end - clock_start; - } else { - BUG_ON(gettimeofday(&tv_end, NULL)); - timersub(&tv_end, &tv_start, &tv_diff); - bps = (double)((double)length / timeval2double(&tv_diff)); - } - - switch (bench_format) { - case BENCH_FORMAT_DEFAULT: - if (use_clock) { - printf(" %14lf Clock/Byte\n", - (double)clock_diff / (double)length); - } else { - if (bps < K) - printf(" %14lf B/Sec\n", bps); - else if (bps < K * K) - printf(" %14lfd KB/Sec\n", bps / 1024); - else if (bps < K * K * K) - printf(" %14lf MB/Sec\n", bps / 1024 / 1024); - else { - printf(" %14lf GB/Sec\n", - bps / 1024 / 1024 / 1024); - } - } - break; - case BENCH_FORMAT_SIMPLE: - if (use_clock) { - printf("%14lf\n", - (double)clock_diff / (double)length); - } else - printf("%lf\n", bps); - break; - default: - /* reaching this means there's some disaster: */ - die("unknown format: %d\n", bench_format); - break; - } - - return 0; -} diff --git a/trunk/tools/perf/builtin-annotate.c b/trunk/tools/perf/builtin-annotate.c index 18ac5eaefc36..6b13a1ecf1e7 100644 --- a/trunk/tools/perf/builtin-annotate.c +++ b/trunk/tools/perf/builtin-annotate.c @@ -24,7 +24,6 @@ #include "util/thread.h" #include "util/sort.h" #include "util/hist.h" -#include "util/process_events.h" static char const *input_name = "perf.data"; @@ -34,9 +33,11 @@ static int input; static int full_paths; static int print_line; +static bool use_modules; static unsigned long page_size; static unsigned long mmap_window = 32; +const char *vmlinux_name; struct sym_hist { u64 sum; @@ -54,11 +55,6 @@ struct sym_priv { struct sym_ext *ext; }; -static struct symbol_conf symbol_conf = { - .priv_size = sizeof(struct sym_priv), - .try_vmlinux_path = true, -}; - static const char *sym_hist_filter; static int symbol_filter(struct map *map __used, struct symbol *sym) @@ -162,7 +158,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) if (event->header.misc & PERF_RECORD_MISC_KERNEL) { level = 'k'; - sym = kernel_maps__find_function(ip, &map, symbol_filter); + sym = kernel_maps__find_symbol(ip, &map, symbol_filter); dump_printf(" ...... dso: %s\n", map ? map->dso->long_name : ""); } else if (event->header.misc & PERF_RECORD_MISC_USER) { @@ -171,7 +167,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) if (map != NULL) { got_map: ip = map->map_ip(map, ip); - sym = map__find_function(map, ip, symbol_filter); + sym = map__find_symbol(map, ip, symbol_filter); } else { /* * If this is outside of all known maps, @@ -205,6 +201,32 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) return 0; } +static int +process_mmap_event(event_t *event, unsigned long offset, unsigned long head) +{ + struct map *map = map__new(&event->mmap, NULL, 0); + struct thread *thread = threads__findnew(event->mmap.pid); + + dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->mmap.pid, + (void *)(long)event->mmap.start, + (void *)(long)event->mmap.len, + (void *)(long)event->mmap.pgoff, + event->mmap.filename); + + if (thread == NULL || map == NULL) { + dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); + return 0; + } + + thread__insert_map(thread, map); + total_mmap++; + + return 0; +} + static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { @@ -225,6 +247,33 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) return 0; } +static int +process_fork_event(event_t *event, unsigned long offset, unsigned long head) +{ + struct thread *thread = threads__findnew(event->fork.pid); + struct thread *parent = threads__findnew(event->fork.ppid); + + dump_printf("%p [%p]: PERF_RECORD_FORK: %d:%d\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->fork.pid, event->fork.ppid); + + /* + * A thread clone will have the same PID for both + * parent and child. + */ + if (thread == parent) + return 0; + + if (!thread || !parent || thread__fork(thread, parent)) { + dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); + return -1; + } + total_fork++; + + return 0; +} + static int process_event(event_t *event, unsigned long offset, unsigned long head) { @@ -239,7 +288,7 @@ process_event(event_t *event, unsigned long offset, unsigned long head) return process_comm_event(event, offset, head); case PERF_RECORD_FORK: - return process_task_event(event, offset, head); + return process_fork_event(event, offset, head); /* * We dont process them right now but they are fine: */ @@ -589,6 +638,11 @@ static int __cmd_annotate(void) exit(0); } + if (kernel_maps__init(vmlinux_name, true, use_modules) < 0) { + pr_err("failed to create kernel maps for symbol resolution\b"); + return -1; + } + remap: buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, MAP_SHARED, input, offset); @@ -689,9 +743,8 @@ static const struct option options[] = { "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), - OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, - "file", "vmlinux pathname"), - OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, + OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), + OPT_BOOLEAN('m', "modules", &use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), OPT_BOOLEAN('l', "print-line", &print_line, "print matching source lines (may be slow)"), @@ -717,8 +770,7 @@ static void setup_sorting(void) int cmd_annotate(int argc, const char **argv, const char *prefix __used) { - if (symbol__init(&symbol_conf) < 0) - return -1; + symbol__init(sizeof(struct sym_priv)); page_size = getpagesize(); diff --git a/trunk/tools/perf/builtin-bench.c b/trunk/tools/perf/builtin-bench.c index e043eb83092a..90c39baae0de 100644 --- a/trunk/tools/perf/builtin-bench.c +++ b/trunk/tools/perf/builtin-bench.c @@ -12,7 +12,6 @@ * * Available subsystem list: * sched ... scheduler and IPC mechanism - * mem ... memory access performance * */ @@ -44,15 +43,6 @@ static struct bench_suite sched_suites[] = { NULL } }; -static struct bench_suite mem_suites[] = { - { "memcpy", - "Simple memory copy in various ways", - bench_mem_memcpy }, - { NULL, - NULL, - NULL } -}; - struct bench_subsys { const char *name; const char *summary; @@ -63,12 +53,9 @@ static struct bench_subsys subsystems[] = { { "sched", "scheduler and IPC mechanism", sched_suites }, - { "mem", - "memory access performance", - mem_suites }, { NULL, NULL, - NULL } + NULL } }; static void dump_suites(int subsys_index) diff --git a/trunk/tools/perf/builtin-help.c b/trunk/tools/perf/builtin-help.c index 9f810b17c25c..768f9c826312 100644 --- a/trunk/tools/perf/builtin-help.c +++ b/trunk/tools/perf/builtin-help.c @@ -179,7 +179,7 @@ static void add_man_viewer(const char *name) while (*p) p = &((*p)->next); - *p = zalloc(sizeof(**p) + len + 1); + *p = calloc(1, (sizeof(**p) + len + 1)); strncpy((*p)->name, name, len); } @@ -194,7 +194,7 @@ static void do_add_man_viewer_info(const char *name, size_t len, const char *value) { - struct man_viewer_info_list *new = zalloc(sizeof(*new) + len + 1); + struct man_viewer_info_list *new = calloc(1, sizeof(*new) + len + 1); strncpy(new->name, name, len); new->info = strdup(value); diff --git a/trunk/tools/perf/builtin-kmem.c b/trunk/tools/perf/builtin-kmem.c index 35722fafc4d1..256d18fa0471 100644 --- a/trunk/tools/perf/builtin-kmem.c +++ b/trunk/tools/perf/builtin-kmem.c @@ -26,28 +26,26 @@ static u64 sample_type; static int alloc_flag; static int caller_flag; +sort_fn_t alloc_sort_fn; +sort_fn_t caller_sort_fn; + static int alloc_lines = -1; static int caller_lines = -1; -static bool raw_ip; - -static char default_sort_order[] = "frag,hit,bytes"; - static char *cwd; static int cwdlen; -static int *cpunode_map; -static int max_cpu_num; - struct alloc_stat { - u64 call_site; - u64 ptr; + union { + struct { + char *name; + u64 call_site; + }; + u64 ptr; + }; u64 bytes_req; u64 bytes_alloc; u32 hit; - u32 pingpong; - - short alloc_cpu; struct rb_node node; }; @@ -58,74 +56,12 @@ static struct rb_root root_caller_stat; static struct rb_root root_caller_sorted; static unsigned long total_requested, total_allocated; -static unsigned long nr_allocs, nr_cross_allocs; struct raw_event_sample { u32 size; char data[0]; }; -#define PATH_SYS_NODE "/sys/devices/system/node" - -static void init_cpunode_map(void) -{ - FILE *fp; - int i; - - fp = fopen("/sys/devices/system/cpu/kernel_max", "r"); - if (!fp) { - max_cpu_num = 4096; - return; - } - - if (fscanf(fp, "%d", &max_cpu_num) < 1) - die("Failed to read 'kernel_max' from sysfs"); - max_cpu_num++; - - cpunode_map = calloc(max_cpu_num, sizeof(int)); - if (!cpunode_map) - die("calloc"); - for (i = 0; i < max_cpu_num; i++) - cpunode_map[i] = -1; - fclose(fp); -} - -static void setup_cpunode_map(void) -{ - struct dirent *dent1, *dent2; - DIR *dir1, *dir2; - unsigned int cpu, mem; - char buf[PATH_MAX]; - - init_cpunode_map(); - - dir1 = opendir(PATH_SYS_NODE); - if (!dir1) - return; - - while (true) { - dent1 = readdir(dir1); - if (!dent1) - break; - - if (sscanf(dent1->d_name, "node%u", &mem) < 1) - continue; - - snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name); - dir2 = opendir(buf); - if (!dir2) - continue; - while (true) { - dent2 = readdir(dir2); - if (!dent2) - break; - if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1) - continue; - cpunode_map[cpu] = mem; - } - } -} - static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { @@ -145,13 +81,16 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) return 0; } -static void insert_alloc_stat(unsigned long call_site, unsigned long ptr, - int bytes_req, int bytes_alloc, int cpu) +static void insert_alloc_stat(unsigned long ptr, + int bytes_req, int bytes_alloc) { struct rb_node **node = &root_alloc_stat.rb_node; struct rb_node *parent = NULL; struct alloc_stat *data = NULL; + if (!alloc_flag) + return; + while (*node) { parent = *node; data = rb_entry(*node, struct alloc_stat, node); @@ -170,10 +109,7 @@ static void insert_alloc_stat(unsigned long call_site, unsigned long ptr, data->bytes_alloc += bytes_req; } else { data = malloc(sizeof(*data)); - if (!data) - die("malloc"); data->ptr = ptr; - data->pingpong = 0; data->hit = 1; data->bytes_req = bytes_req; data->bytes_alloc = bytes_alloc; @@ -181,8 +117,6 @@ static void insert_alloc_stat(unsigned long call_site, unsigned long ptr, rb_link_node(&data->node, parent, node); rb_insert_color(&data->node, &root_alloc_stat); } - data->call_site = call_site; - data->alloc_cpu = cpu; } static void insert_caller_stat(unsigned long call_site, @@ -192,6 +126,9 @@ static void insert_caller_stat(unsigned long call_site, struct rb_node *parent = NULL; struct alloc_stat *data = NULL; + if (!caller_flag) + return; + while (*node) { parent = *node; data = rb_entry(*node, struct alloc_stat, node); @@ -210,10 +147,7 @@ static void insert_caller_stat(unsigned long call_site, data->bytes_alloc += bytes_req; } else { data = malloc(sizeof(*data)); - if (!data) - die("malloc"); data->call_site = call_site; - data->pingpong = 0; data->hit = 1; data->bytes_req = bytes_req; data->bytes_alloc = bytes_alloc; @@ -225,89 +159,34 @@ static void insert_caller_stat(unsigned long call_site, static void process_alloc_event(struct raw_event_sample *raw, struct event *event, - int cpu, + int cpu __used, u64 timestamp __used, struct thread *thread __used, - int node) + int node __used) { unsigned long call_site; unsigned long ptr; int bytes_req; int bytes_alloc; - int node1, node2; ptr = raw_field_value(event, "ptr", raw->data); call_site = raw_field_value(event, "call_site", raw->data); bytes_req = raw_field_value(event, "bytes_req", raw->data); bytes_alloc = raw_field_value(event, "bytes_alloc", raw->data); - insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu); + insert_alloc_stat(ptr, bytes_req, bytes_alloc); insert_caller_stat(call_site, bytes_req, bytes_alloc); total_requested += bytes_req; total_allocated += bytes_alloc; - - if (node) { - node1 = cpunode_map[cpu]; - node2 = raw_field_value(event, "node", raw->data); - if (node1 != node2) - nr_cross_allocs++; - } - nr_allocs++; -} - -static int ptr_cmp(struct alloc_stat *, struct alloc_stat *); -static int callsite_cmp(struct alloc_stat *, struct alloc_stat *); - -static struct alloc_stat *search_alloc_stat(unsigned long ptr, - unsigned long call_site, - struct rb_root *root, - sort_fn_t sort_fn) -{ - struct rb_node *node = root->rb_node; - struct alloc_stat key = { .ptr = ptr, .call_site = call_site }; - - while (node) { - struct alloc_stat *data; - int cmp; - - data = rb_entry(node, struct alloc_stat, node); - - cmp = sort_fn(&key, data); - if (cmp < 0) - node = node->rb_left; - else if (cmp > 0) - node = node->rb_right; - else - return data; - } - return NULL; } -static void process_free_event(struct raw_event_sample *raw, - struct event *event, - int cpu, +static void process_free_event(struct raw_event_sample *raw __used, + struct event *event __used, + int cpu __used, u64 timestamp __used, struct thread *thread __used) { - unsigned long ptr; - struct alloc_stat *s_alloc, *s_caller; - - ptr = raw_field_value(event, "ptr", raw->data); - - s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp); - if (!s_alloc) - return; - - if (cpu != s_alloc->alloc_cpu) { - s_alloc->pingpong++; - - s_caller = search_alloc_stat(0, s_alloc->call_site, - &root_caller_stat, callsite_cmp); - assert(s_caller); - s_caller->pingpong++; - } - s_alloc->alloc_cpu = -1; } static void @@ -412,7 +291,7 @@ static int read_events(void) register_idle_thread(); register_perf_file_handler(&file_handler); - return mmap_dispatch_perf_file(&header, input_name, 0, 0, + return mmap_dispatch_perf_file(&header, input_name, NULL, false, 0, 0, &cwdlen, &cwd); } @@ -428,10 +307,10 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller) { struct rb_node *next; - printf("%.102s\n", graph_dotted_line); - printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); - printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n"); - printf("%.102s\n", graph_dotted_line); + printf("%.78s\n", graph_dotted_line); + printf("%-28s|", is_caller ? "Callsite": "Alloc Ptr"); + printf("Total_alloc/Per | Total_req/Per | Hit | Frag\n"); + printf("%.78s\n", graph_dotted_line); next = rb_first(root); @@ -439,39 +318,36 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller) struct alloc_stat *data = rb_entry(next, struct alloc_stat, node); struct symbol *sym = NULL; - char buf[BUFSIZ]; + char bf[BUFSIZ]; u64 addr; if (is_caller) { addr = data->call_site; - if (!raw_ip) - sym = kernel_maps__find_function(addr, NULL, NULL); + sym = kernel_maps__find_symbol(addr, NULL, NULL); } else addr = data->ptr; if (sym != NULL) - snprintf(buf, sizeof(buf), "%s+%Lx", sym->name, + snprintf(bf, sizeof(bf), "%s/%Lx", sym->name, addr - sym->start); else - snprintf(buf, sizeof(buf), "%#Lx", addr); - printf(" %-34s |", buf); + snprintf(bf, sizeof(bf), "%#Lx", addr); - printf(" %9llu/%-5lu | %9llu/%-5lu | %6lu | %8lu | %6.3f%%\n", - (unsigned long long)data->bytes_alloc, + printf("%-28s|%8llu/%-6lu |%8llu/%-6lu|%6lu|%8.3f%%\n", + bf, (unsigned long long)data->bytes_alloc, (unsigned long)data->bytes_alloc / data->hit, (unsigned long long)data->bytes_req, (unsigned long)data->bytes_req / data->hit, (unsigned long)data->hit, - (unsigned long)data->pingpong, fragmentation(data->bytes_req, data->bytes_alloc)); next = rb_next(next); } if (n_lines == -1) - printf(" ... | ... | ... | ... | ... | ... \n"); + printf(" ... | ... | ... | ... | ... \n"); - printf("%.102s\n", graph_dotted_line); + printf(" ------------------------------------------------------------------------------\n"); } static void print_summary(void) @@ -483,7 +359,6 @@ static void print_summary(void) total_allocated - total_requested); printf("Internal fragmentation: %f%%\n", fragmentation(total_requested, total_allocated)); - printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs); } static void print_result(void) @@ -495,34 +370,20 @@ static void print_result(void) print_summary(); } -struct sort_dimension { - const char name[20]; - sort_fn_t cmp; - struct list_head list; -}; - -static LIST_HEAD(caller_sort); -static LIST_HEAD(alloc_sort); - static void sort_insert(struct rb_root *root, struct alloc_stat *data, - struct list_head *sort_list) + sort_fn_t sort_fn) { struct rb_node **new = &(root->rb_node); struct rb_node *parent = NULL; - struct sort_dimension *sort; while (*new) { struct alloc_stat *this; - int cmp = 0; + int cmp; this = rb_entry(*new, struct alloc_stat, node); parent = *new; - list_for_each_entry(sort, sort_list, list) { - cmp = sort->cmp(data, this); - if (cmp) - break; - } + cmp = sort_fn(data, this); if (cmp > 0) new = &((*new)->rb_left); @@ -535,7 +396,7 @@ static void sort_insert(struct rb_root *root, struct alloc_stat *data, } static void __sort_result(struct rb_root *root, struct rb_root *root_sorted, - struct list_head *sort_list) + sort_fn_t sort_fn) { struct rb_node *node; struct alloc_stat *data; @@ -547,14 +408,14 @@ static void __sort_result(struct rb_root *root, struct rb_root *root_sorted, rb_erase(node, root); data = rb_entry(node, struct alloc_stat, node); - sort_insert(root_sorted, data, sort_list); + sort_insert(root_sorted, data, sort_fn); } } static void sort_result(void) { - __sort_result(&root_alloc_stat, &root_alloc_sorted, &alloc_sort); - __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); + __sort_result(&root_alloc_stat, &root_alloc_sorted, alloc_sort_fn); + __sort_result(&root_caller_stat, &root_caller_sorted, caller_sort_fn); } static int __cmd_kmem(void) @@ -572,6 +433,7 @@ static const char * const kmem_usage[] = { NULL }; + static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r) { if (l->ptr < r->ptr) @@ -581,11 +443,6 @@ static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r) return 0; } -static struct sort_dimension ptr_sort_dimension = { - .name = "ptr", - .cmp = ptr_cmp, -}; - static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r) { if (l->call_site < r->call_site) @@ -595,11 +452,6 @@ static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r) return 0; } -static struct sort_dimension callsite_sort_dimension = { - .name = "callsite", - .cmp = callsite_cmp, -}; - static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r) { if (l->hit < r->hit) @@ -609,11 +461,6 @@ static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r) return 0; } -static struct sort_dimension hit_sort_dimension = { - .name = "hit", - .cmp = hit_cmp, -}; - static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r) { if (l->bytes_alloc < r->bytes_alloc) @@ -623,11 +470,6 @@ static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r) return 0; } -static struct sort_dimension bytes_sort_dimension = { - .name = "bytes", - .cmp = bytes_cmp, -}; - static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r) { double x, y; @@ -642,88 +484,31 @@ static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r) return 0; } -static struct sort_dimension frag_sort_dimension = { - .name = "frag", - .cmp = frag_cmp, -}; - -static int pingpong_cmp(struct alloc_stat *l, struct alloc_stat *r) -{ - if (l->pingpong < r->pingpong) - return -1; - else if (l->pingpong > r->pingpong) - return 1; - return 0; -} - -static struct sort_dimension pingpong_sort_dimension = { - .name = "pingpong", - .cmp = pingpong_cmp, -}; - -static struct sort_dimension *avail_sorts[] = { - &ptr_sort_dimension, - &callsite_sort_dimension, - &hit_sort_dimension, - &bytes_sort_dimension, - &frag_sort_dimension, - &pingpong_sort_dimension, -}; - -#define NUM_AVAIL_SORTS \ - (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *)) - -static int sort_dimension__add(const char *tok, struct list_head *list) -{ - struct sort_dimension *sort; - int i; - - for (i = 0; i < NUM_AVAIL_SORTS; i++) { - if (!strcmp(avail_sorts[i]->name, tok)) { - sort = malloc(sizeof(*sort)); - if (!sort) - die("malloc"); - memcpy(sort, avail_sorts[i], sizeof(*sort)); - list_add_tail(&sort->list, list); - return 0; - } - } - - return -1; -} - -static int setup_sorting(struct list_head *sort_list, const char *arg) -{ - char *tok; - char *str = strdup(arg); - - if (!str) - die("strdup"); - - while (true) { - tok = strsep(&str, ","); - if (!tok) - break; - if (sort_dimension__add(tok, sort_list) < 0) { - error("Unknown --sort key: '%s'", tok); - return -1; - } - } - - free(str); - return 0; -} - static int parse_sort_opt(const struct option *opt __used, const char *arg, int unset __used) { + sort_fn_t sort_fn; + if (!arg) return -1; + if (strcmp(arg, "ptr") == 0) + sort_fn = ptr_cmp; + else if (strcmp(arg, "call_site") == 0) + sort_fn = callsite_cmp; + else if (strcmp(arg, "hit") == 0) + sort_fn = hit_cmp; + else if (strcmp(arg, "bytes") == 0) + sort_fn = bytes_cmp; + else if (strcmp(arg, "frag") == 0) + sort_fn = frag_cmp; + else + return -1; + if (caller_flag > alloc_flag) - return setup_sorting(&caller_sort, arg); + caller_sort_fn = sort_fn; else - return setup_sorting(&alloc_sort, arg); + alloc_sort_fn = sort_fn; return 0; } @@ -767,13 +552,12 @@ static const struct option kmem_options[] = { OPT_CALLBACK(0, "stat", NULL, "|", "stat selector, Pass 'alloc' or 'caller'.", parse_stat_opt), - OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", - "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", + OPT_CALLBACK('s', "sort", NULL, "key", + "sort by key: ptr, call_site, hit, bytes, frag", parse_sort_opt), OPT_CALLBACK('l', "line", NULL, "num", "show n lins", parse_line_opt), - OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), OPT_END() }; @@ -820,12 +604,10 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __used) else if (argc) usage_with_options(kmem_usage, kmem_options); - if (list_empty(&caller_sort)) - setup_sorting(&caller_sort, default_sort_order); - if (list_empty(&alloc_sort)) - setup_sorting(&alloc_sort, default_sort_order); - - setup_cpunode_map(); + if (!alloc_sort_fn) + alloc_sort_fn = bytes_cmp; + if (!caller_sort_fn) + caller_sort_fn = bytes_cmp; return __cmd_kmem(); } diff --git a/trunk/tools/perf/builtin-probe.c b/trunk/tools/perf/builtin-probe.c index a2f6daf01ecb..d78a3d945492 100644 --- a/trunk/tools/perf/builtin-probe.c +++ b/trunk/tools/perf/builtin-probe.c @@ -309,9 +309,9 @@ static int synthesize_probe_event(struct probe_point *pp) { char *buf; int i, len, ret; - pp->probes[0] = buf = zalloc(MAX_CMDLEN); + pp->probes[0] = buf = (char *)calloc(MAX_CMDLEN, sizeof(char)); if (!buf) - die("Failed to allocate memory by zalloc."); + die("Failed to allocate memory by calloc."); ret = snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset); if (ret <= 0 || ret >= MAX_CMDLEN) goto error; diff --git a/trunk/tools/perf/builtin-report.c b/trunk/tools/perf/builtin-report.c index e4b1004e76ea..fe474b7f8ad0 100644 --- a/trunk/tools/perf/builtin-report.c +++ b/trunk/tools/perf/builtin-report.c @@ -30,7 +30,6 @@ #include "util/thread.h" #include "util/sort.h" #include "util/hist.h" -#include "util/process_events.h" static char const *input_name = "perf.data"; @@ -39,6 +38,7 @@ static char *dso_list_str, *comm_list_str, *sym_list_str, static struct strlist *dso_list, *comm_list, *sym_list; static int force; +static bool use_modules; static int full_paths; static int show_nr_samples; @@ -52,13 +52,15 @@ static char *pretty_printing_style = default_pretty_printing_style; static int exclude_other = 1; static char callchain_default_opt[] = "fractal,0.5"; +const char *vmlinux_name; + +static char *cwd; +static int cwdlen; static struct perf_header *header; static u64 sample_type; -struct symbol_conf symbol_conf; - static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) @@ -448,14 +450,14 @@ resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp) * trick of looking in the whole kernel symbol list. */ if ((long long)ip < 0) - return kernel_maps__find_function(ip, mapp, NULL); + return kernel_maps__find_symbol(ip, mapp, NULL); } dump_printf(" ...... dso: %s\n", map ? map->dso->long_name : ""); dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip); *ipp = ip; - return map ? map__find_function(map, ip, NULL) : NULL; + return map ? map__find_symbol(map, ip, NULL) : NULL; } static int call__match(struct symbol *sym) @@ -495,7 +497,7 @@ static struct symbol **resolve_callchain(struct thread *thread, case PERF_CONTEXT_HV: break; case PERF_CONTEXT_KERNEL: - sym = kernel_maps__find_function(ip, NULL, NULL); + sym = kernel_maps__find_symbol(ip, NULL, NULL); break; default: sym = resolve_symbol(thread, NULL, &ip); @@ -715,7 +717,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) if (cpumode == PERF_RECORD_MISC_KERNEL) { level = 'k'; - sym = kernel_maps__find_function(ip, &map, NULL); + sym = kernel_maps__find_symbol(ip, &map, NULL); dump_printf(" ...... dso: %s\n", map ? map->dso->long_name : ""); } else if (cpumode == PERF_RECORD_MISC_USER) { @@ -748,6 +750,33 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) return 0; } +static int +process_mmap_event(event_t *event, unsigned long offset, unsigned long head) +{ + struct map *map = map__new(&event->mmap, cwd, cwdlen); + struct thread *thread = threads__findnew(event->mmap.pid); + + dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->mmap.pid, + event->mmap.tid, + (void *)(long)event->mmap.start, + (void *)(long)event->mmap.len, + (void *)(long)event->mmap.pgoff, + event->mmap.filename); + + if (thread == NULL || map == NULL) { + dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); + return 0; + } + + thread__insert_map(thread, map); + total_mmap++; + + return 0; +} + static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { @@ -768,6 +797,38 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) return 0; } +static int +process_task_event(event_t *event, unsigned long offset, unsigned long head) +{ + struct thread *thread = threads__findnew(event->fork.pid); + struct thread *parent = threads__findnew(event->fork.ppid); + + dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT", + event->fork.pid, event->fork.tid, + event->fork.ppid, event->fork.ptid); + + /* + * A thread clone will have the same PID for both + * parent and child. + */ + if (thread == parent) + return 0; + + if (event->header.type == PERF_RECORD_EXIT) + return 0; + + if (!thread || !parent || thread__fork(thread, parent)) { + dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); + return -1; + } + total_fork++; + + return 0; +} + static int process_lost_event(event_t *event, unsigned long offset, unsigned long head) { @@ -865,7 +926,8 @@ static int __cmd_report(void) register_perf_file_handler(&file_handler); - ret = mmap_dispatch_perf_file(&header, input_name, force, + ret = mmap_dispatch_perf_file(&header, input_name, vmlinux_name, + !vmlinux_name, force, full_paths, &cwdlen, &cwd); if (ret) return ret; @@ -962,10 +1024,9 @@ static const struct option options[] = { "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), - OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, - "file", "vmlinux pathname"), + OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), - OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, + OPT_BOOLEAN('m', "modules", &use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, "Show a column with the number of samples"), @@ -1035,8 +1096,7 @@ static void setup_list(struct strlist **list, const char *list_str, int cmd_report(int argc, const char **argv, const char *prefix __used) { - if (symbol__init(&symbol_conf) < 0) - return -1; + symbol__init(0); argc = parse_options(argc, argv, options, report_usage, 0); diff --git a/trunk/tools/perf/builtin-sched.c b/trunk/tools/perf/builtin-sched.c index 19eb708a706b..260f57a72ee0 100644 --- a/trunk/tools/perf/builtin-sched.c +++ b/trunk/tools/perf/builtin-sched.c @@ -225,7 +225,7 @@ static void calibrate_sleep_measurement_overhead(void) static struct sched_atom * get_new_event(struct task_desc *task, u64 timestamp) { - struct sched_atom *event = zalloc(sizeof(*event)); + struct sched_atom *event = calloc(1, sizeof(*event)); unsigned long idx = task->nr_events; size_t size; @@ -293,7 +293,7 @@ add_sched_event_wakeup(struct task_desc *task, u64 timestamp, return; } - wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem)); + wakee_event->wait_sem = calloc(1, sizeof(*wakee_event->wait_sem)); sem_init(wakee_event->wait_sem, 0, 0); wakee_event->specific_wait = 1; event->wait_sem = wakee_event->wait_sem; @@ -323,7 +323,7 @@ static struct task_desc *register_pid(unsigned long pid, const char *comm) if (task) return task; - task = zalloc(sizeof(*task)); + task = calloc(1, sizeof(*task)); task->pid = pid; task->nr = nr_tasks; strcpy(task->comm, comm); @@ -962,7 +962,9 @@ __thread_latency_insert(struct rb_root *root, struct work_atoms *data, static void thread_atoms_insert(struct thread *thread) { - struct work_atoms *atoms = zalloc(sizeof(*atoms)); + struct work_atoms *atoms; + + atoms = calloc(sizeof(*atoms), 1); if (!atoms) die("No memory"); @@ -994,7 +996,9 @@ add_sched_out_event(struct work_atoms *atoms, char run_state, u64 timestamp) { - struct work_atom *atom = zalloc(sizeof(*atom)); + struct work_atom *atom; + + atom = calloc(sizeof(*atom), 1); if (!atom) die("Non memory"); @@ -1714,7 +1718,7 @@ static int read_events(void) register_idle_thread(); register_perf_file_handler(&file_handler); - return mmap_dispatch_perf_file(&header, input_name, 0, 0, + return mmap_dispatch_perf_file(&header, input_name, NULL, false, 0, 0, &cwdlen, &cwd); } diff --git a/trunk/tools/perf/builtin-top.c b/trunk/tools/perf/builtin-top.c index ded6cf65ad9c..6a5de90e9b83 100644 --- a/trunk/tools/perf/builtin-top.c +++ b/trunk/tools/perf/builtin-top.c @@ -79,7 +79,7 @@ static int dump_symtab = 0; static bool hide_kernel_symbols = false; static bool hide_user_symbols = false; static struct winsize winsize; -struct symbol_conf symbol_conf; +const char *vmlinux_name; /* * Source @@ -128,7 +128,7 @@ struct sym_entry { static inline struct symbol *sym_entry__symbol(struct sym_entry *self) { - return ((void *)self) + symbol_conf.priv_size; + return ((void *)self) + symbol__priv_size; } static void get_term_dimensions(struct winsize *ws) @@ -181,7 +181,7 @@ static void parse_source(struct sym_entry *syme) return; if (syme->src == NULL) { - syme->src = zalloc(sizeof(*source)); + syme->src = calloc(1, sizeof(*source)); if (syme->src == NULL) return; pthread_mutex_init(&syme->src->lock, NULL); @@ -451,8 +451,9 @@ static void print_sym_table(void) struct sym_entry *syme, *n; struct rb_root tmp = RB_ROOT; struct rb_node *nd; - int sym_width = 0, dso_width = 0, max_dso_width; + int sym_width = 0, dso_width = 0; const int win_width = winsize.ws_col - 1; + struct dso *unique_dso = NULL, *first_dso = NULL; samples = userspace_samples = 0; @@ -538,6 +539,11 @@ static void print_sym_table(void) (int)syme->snap_count < count_filter) continue; + if (first_dso == NULL) + unique_dso = first_dso = syme->map->dso; + else if (syme->map->dso != first_dso) + unique_dso = NULL; + if (syme->map->dso->long_name_len > dso_width) dso_width = syme->map->dso->long_name_len; @@ -547,10 +553,14 @@ static void print_sym_table(void) printed = 0; - max_dso_width = winsize.ws_col - sym_width - 29; - if (dso_width > max_dso_width) - dso_width = max_dso_width; - putchar('\n'); + if (unique_dso) + printf("DSO: %s\n", unique_dso->long_name); + else { + int max_dso_width = winsize.ws_col - sym_width - 29; + if (dso_width > max_dso_width) + dso_width = max_dso_width; + putchar('\n'); + } if (nr_counters == 1) printf(" samples pcnt"); else @@ -558,13 +568,17 @@ static void print_sym_table(void) if (verbose) printf(" RIP "); - printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); + printf(" %-*.*s", sym_width, sym_width, "function"); + if (!unique_dso) + printf(" DSO"); + putchar('\n'); printf(" %s _______ _____", nr_counters == 1 ? " " : "______"); if (verbose) printf(" ________________"); printf(" %-*.*s", sym_width, sym_width, graph_line); - printf(" %-*.*s", dso_width, dso_width, graph_line); + if (!unique_dso) + printf(" %-*.*s", dso_width, dso_width, graph_line); puts("\n"); for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { @@ -589,10 +603,12 @@ static void print_sym_table(void) if (verbose) printf(" %016llx", sym->start); printf(" %-*.*s", sym_width, sym_width, sym->name); - printf(" %-*.*s\n", dso_width, dso_width, - dso_width >= syme->map->dso->long_name_len ? - syme->map->dso->long_name : - syme->map->dso->short_name); + if (!unique_dso) + printf(" %-*.*s", dso_width, dso_width, + dso_width >= syme->map->dso->long_name_len ? + syme->map->dso->long_name : + syme->map->dso->short_name); + printf("\n"); } } @@ -695,7 +711,7 @@ static void print_mapped_keys(void) fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); - if (symbol_conf.vmlinux_name) { + if (vmlinux_name) { fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); fprintf(stdout, "\t[S] stop annotation.\n"); @@ -732,7 +748,7 @@ static int key_mapped(int c) case 'F': case 's': case 'S': - return symbol_conf.vmlinux_name ? 1 : 0; + return vmlinux_name ? 1 : 0; default: break; } @@ -948,7 +964,7 @@ static void event__process_sample(const event_t *self, int counter) map = thread__find_map(thread, ip); if (map != NULL) { ip = map->map_ip(map, ip); - sym = map__find_function(map, ip, symbol_filter); + sym = map__find_symbol(map, ip, symbol_filter); if (sym == NULL) return; userspace_samples++; @@ -968,7 +984,7 @@ static void event__process_sample(const event_t *self, int counter) if (hide_kernel_symbols) return; - sym = kernel_maps__find_function(ip, &map, symbol_filter); + sym = kernel_maps__find_symbol(ip, &map, symbol_filter); if (sym == NULL) return; break; @@ -1261,8 +1277,7 @@ static const struct option options[] = { "system-wide collection from all CPUs"), OPT_INTEGER('C', "CPU", &profile_cpu, "CPU to profile on"), - OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, - "file", "vmlinux pathname"), + OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, "hide kernel symbols"), OPT_INTEGER('m', "mmap-pages", &mmap_pages, @@ -1296,7 +1311,7 @@ static const struct option options[] = { int cmd_top(int argc, const char **argv, const char *prefix __used) { - int counter; + int counter, err; page_size = sysconf(_SC_PAGE_SIZE); @@ -1314,16 +1329,15 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) if (!nr_counters) nr_counters = 1; - symbol_conf.priv_size = (sizeof(struct sym_entry) + - (nr_counters + 1) * sizeof(unsigned long)); - if (symbol_conf.vmlinux_name == NULL) - symbol_conf.try_vmlinux_path = true; - if (symbol__init(&symbol_conf) < 0) - return -1; + symbol__init(sizeof(struct sym_entry) + + (nr_counters + 1) * sizeof(unsigned long)); if (delay_secs < 1) delay_secs = 1; + err = kernel_maps__init(vmlinux_name, !vmlinux_name, true); + if (err < 0) + return err; parse_source(sym_filter_entry); /* diff --git a/trunk/tools/perf/builtin-trace.c b/trunk/tools/perf/builtin-trace.c index 75972fd073df..b71198e5dc14 100644 --- a/trunk/tools/perf/builtin-trace.c +++ b/trunk/tools/perf/builtin-trace.c @@ -131,7 +131,7 @@ static int __cmd_trace(void) register_idle_thread(); register_perf_file_handler(&file_handler); - return mmap_dispatch_perf_file(&header, input_name, + return mmap_dispatch_perf_file(&header, input_name, NULL, false, 0, 0, &cwdlen, &cwd); } diff --git a/trunk/tools/perf/command-list.txt b/trunk/tools/perf/command-list.txt index 02b09ea17a3e..d3a6e18e4a5e 100644 --- a/trunk/tools/perf/command-list.txt +++ b/trunk/tools/perf/command-list.txt @@ -14,4 +14,3 @@ perf-timechart mainporcelain common perf-top mainporcelain common perf-trace mainporcelain common perf-probe mainporcelain common -perf-kmem mainporcelain common diff --git a/trunk/tools/perf/util/data_map.c b/trunk/tools/perf/util/data_map.c index b238462b8983..f318d19b2562 100644 --- a/trunk/tools/perf/util/data_map.c +++ b/trunk/tools/perf/util/data_map.c @@ -101,6 +101,8 @@ int perf_header__read_build_ids(int input, off_t offset, off_t size) int mmap_dispatch_perf_file(struct perf_header **pheader, const char *input_name, + const char *vmlinux_name, + bool try_vmlinux_path, int force, int full_paths, int *cwdlen, @@ -170,6 +172,12 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, curr_handler->sample_type_check(sample_type) < 0) goto out_delete; + err = -ENOMEM; + if (kernel_maps__init(vmlinux_name, try_vmlinux_path, true) < 0) { + pr_err("failed to setup the kernel maps to resolve symbols\n"); + goto out_delete; + } + if (!full_paths) { if (getcwd(__cwd, sizeof(__cwd)) == NULL) { pr_err("failed to get the current directory\n"); diff --git a/trunk/tools/perf/util/data_map.h b/trunk/tools/perf/util/data_map.h index ae036ecd7625..3f0d21b3819e 100644 --- a/trunk/tools/perf/util/data_map.h +++ b/trunk/tools/perf/util/data_map.h @@ -23,6 +23,8 @@ struct perf_file_handler { void register_perf_file_handler(struct perf_file_handler *handler); int mmap_dispatch_perf_file(struct perf_header **pheader, const char *input_name, + const char *vmlinux_name, + bool try_vmlinux_path, int force, int full_paths, int *cwdlen, diff --git a/trunk/tools/perf/util/event.h b/trunk/tools/perf/util/event.h index 882a9531db97..f1e392612652 100644 --- a/trunk/tools/perf/util/event.h +++ b/trunk/tools/perf/util/event.h @@ -119,10 +119,9 @@ void map__delete(struct map *self); struct map *map__clone(struct map *self); int map__overlap(struct map *l, struct map *r); size_t map__fprintf(struct map *self, FILE *fp); -struct symbol *map__find_function(struct map *self, u64 ip, - symbol_filter_t filter); -void map__fixup_start(struct map *self, struct rb_root *symbols); -void map__fixup_end(struct map *self, struct rb_root *symbols); +struct symbol *map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter); +void map__fixup_start(struct map *self); +void map__fixup_end(struct map *self); int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); void event__synthesize_threads(int (*process)(event_t *event)); diff --git a/trunk/tools/perf/util/header.c b/trunk/tools/perf/util/header.c index 4b586569bb02..1332f8ec04aa 100644 --- a/trunk/tools/perf/util/header.c +++ b/trunk/tools/perf/util/header.c @@ -63,7 +63,7 @@ int perf_header_attr__add_id(struct perf_header_attr *self, u64 id) */ struct perf_header *perf_header__new(void) { - struct perf_header *self = zalloc(sizeof(*self)); + struct perf_header *self = calloc(sizeof(*self), 1); if (self != NULL) { self->size = 1; @@ -253,6 +253,12 @@ static int perf_header__adds_write(struct perf_header *self, int fd) buildid_sec = &feat_sec[idx++]; + /* + * Read the kernel buildid nad the list of loaded modules with + * its build_ids: + */ + kernel_maps__init(NULL, false, true); + /* Write build-ids */ buildid_sec->offset = lseek(fd, 0, SEEK_CUR); err = dsos__write_buildid_table(fd); diff --git a/trunk/tools/perf/util/include/asm/bug.h b/trunk/tools/perf/util/include/asm/bug.h deleted file mode 100644 index 7fcc6810adc2..000000000000 --- a/trunk/tools/perf/util/include/asm/bug.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _PERF_ASM_GENERIC_BUG_H -#define _PERF_ASM_GENERIC_BUG_H - -#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0) - -#define WARN(condition, format...) ({ \ - int __ret_warn_on = !!(condition); \ - if (unlikely(__ret_warn_on)) \ - __WARN_printf(format); \ - unlikely(__ret_warn_on); \ -}) - -#define WARN_ONCE(condition, format...) ({ \ - static int __warned; \ - int __ret_warn_once = !!(condition); \ - \ - if (unlikely(__ret_warn_once)) \ - if (WARN(!__warned, format)) \ - __warned = 1; \ - unlikely(__ret_warn_once); \ -}) -#endif diff --git a/trunk/tools/perf/util/include/linux/bitops.h b/trunk/tools/perf/util/include/linux/bitops.h index 8d63116e9435..ace57c36d1d0 100644 --- a/trunk/tools/perf/util/include/linux/bitops.h +++ b/trunk/tools/perf/util/include/linux/bitops.h @@ -7,8 +7,6 @@ #define CONFIG_GENERIC_FIND_FIRST_BIT #include "../../../../include/linux/bitops.h" -#undef __KERNEL__ - static inline void set_bit(int nr, unsigned long *addr) { addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG); diff --git a/trunk/tools/perf/util/map.c b/trunk/tools/perf/util/map.c index 41c5c4a20010..09412321a80d 100644 --- a/trunk/tools/perf/util/map.c +++ b/trunk/tools/perf/util/map.c @@ -80,18 +80,18 @@ void map__delete(struct map *self) free(self); } -void map__fixup_start(struct map *self, struct rb_root *symbols) +void map__fixup_start(struct map *self) { - struct rb_node *nd = rb_first(symbols); + struct rb_node *nd = rb_first(&self->dso->syms); if (nd != NULL) { struct symbol *sym = rb_entry(nd, struct symbol, rb_node); self->start = sym->start; } } -void map__fixup_end(struct map *self, struct rb_root *symbols) +void map__fixup_end(struct map *self) { - struct rb_node *nd = rb_last(symbols); + struct rb_node *nd = rb_last(&self->dso->syms); if (nd != NULL) { struct symbol *sym = rb_entry(nd, struct symbol, rb_node); self->end = sym->end; @@ -100,8 +100,8 @@ void map__fixup_end(struct map *self, struct rb_root *symbols) #define DSO__DELETED "(deleted)" -struct symbol *map__find_function(struct map *self, u64 ip, - symbol_filter_t filter) +struct symbol * +map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter) { if (!self->dso->loaded) { int nr = dso__load(self->dso, self, filter); @@ -136,7 +136,7 @@ struct symbol *map__find_function(struct map *self, u64 ip, } } - return self->dso->find_function(self->dso, ip); + return self->dso->find_symbol(self->dso, ip); } struct map *map__clone(struct map *self) diff --git a/trunk/tools/perf/util/parse-events.c b/trunk/tools/perf/util/parse-events.c index 9e5dbd66d34d..070027469270 100644 --- a/trunk/tools/perf/util/parse-events.c +++ b/trunk/tools/perf/util/parse-events.c @@ -197,7 +197,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) if (id == config) { closedir(evt_dir); closedir(sys_dir); - path = zalloc(sizeof(path)); + path = calloc(1, sizeof(path)); path->system = malloc(MAX_EVENT_LENGTH); if (!path->system) { free(path); diff --git a/trunk/tools/perf/util/process_event.c b/trunk/tools/perf/util/process_event.c deleted file mode 100644 index a970789581a2..000000000000 --- a/trunk/tools/perf/util/process_event.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "process_event.h" - -char *cwd; -int cwdlen; - -int -process_mmap_event(event_t *event, unsigned long offset, unsigned long head) -{ - struct map *map = map__new(&event->mmap, cwd, cwdlen); - struct thread *thread = threads__findnew(event->mmap.pid); - - dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->mmap.pid, - event->mmap.tid, - (void *)(long)event->mmap.start, - (void *)(long)event->mmap.len, - (void *)(long)event->mmap.pgoff, - event->mmap.filename); - - if (thread == NULL || map == NULL) { - dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); - return 0; - } - - thread__insert_map(thread, map); - total_mmap++; - - return 0; - -} - -int -process_comm_event(event_t *event, unsigned long offset, unsigned long head) -{ - struct thread *thread = threads__findnew(event->comm.pid); - - dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->comm.comm, event->comm.pid); - - if (thread == NULL || - thread__set_comm_adjust(thread, event->comm.comm)) { - dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); - return -1; - } - total_comm++; - - return 0; -} - diff --git a/trunk/tools/perf/util/process_event.h b/trunk/tools/perf/util/process_event.h deleted file mode 100644 index 6f68c69736cd..000000000000 --- a/trunk/tools/perf/util/process_event.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __PROCESS_EVENT_H -#define __PROCESS_EVENT_H - -#include "../builtin.h" -#include "util.h" - -#include "color.h" -#include -#include "cache.h" -#include -#include "symbol.h" -#include "string.h" - -#include "../perf.h" -#include "debug.h" - -#include "parse-options.h" -#include "parse-events.h" - -#include "thread.h" -#include "sort.h" -#include "hist.h" - -extern char *cwd; -extern int cwdlen; -extern int process_mmap_event(event_t *, unsigned long, unsigned long); -extern int process_comm_event(event_t *, unsigned long , unsigned long); - -#endif /* __PROCESS_H */ diff --git a/trunk/tools/perf/util/process_events.c b/trunk/tools/perf/util/process_events.c deleted file mode 100644 index a9204363efd8..000000000000 --- a/trunk/tools/perf/util/process_events.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "process_events.h" - -char *cwd; -int cwdlen; - -int -process_mmap_event(event_t *event, unsigned long offset, unsigned long head) -{ - struct map *map = map__new(&event->mmap, cwd, cwdlen); - struct thread *thread = threads__findnew(event->mmap.pid); - - dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->mmap.pid, - event->mmap.tid, - (void *)(long)event->mmap.start, - (void *)(long)event->mmap.len, - (void *)(long)event->mmap.pgoff, - event->mmap.filename); - - if (thread == NULL || map == NULL) { - dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); - return 0; - } - - thread__insert_map(thread, map); - total_mmap++; - - return 0; -} - -int -process_task_event(event_t *event, unsigned long offset, unsigned long head) -{ - struct thread *thread = threads__findnew(event->fork.pid); - struct thread *parent = threads__findnew(event->fork.ppid); - - dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT", - event->fork.pid, event->fork.tid, - event->fork.ppid, event->fork.ptid); - - /* - * A thread clone will have the same PID for both - * parent and child. - */ - if (thread == parent) - return 0; - - if (event->header.type == PERF_RECORD_EXIT) - return 0; - - if (!thread || !parent || thread__fork(thread, parent)) { - dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); - return -1; - } - total_fork++; - - return 0; -} - diff --git a/trunk/tools/perf/util/process_events.h b/trunk/tools/perf/util/process_events.h deleted file mode 100644 index 73d092f83283..000000000000 --- a/trunk/tools/perf/util/process_events.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __PROCESS_EVENTS_H -#define __PROCESS_EVENTS_H - -#include "../builtin.h" - -#include "util.h" -#include "color.h" -#include -#include "cache.h" -#include -#include "symbol.h" -#include "string.h" -#include "callchain.h" -#include "strlist.h" -#include "values.h" - -#include "../perf.h" -#include "debug.h" -#include "header.h" - -#include "parse-options.h" -#include "parse-events.h" - -#include "data_map.h" -#include "thread.h" -#include "sort.h" -#include "hist.h" - -extern char *cwd; -extern int cwdlen; - -extern int process_mmap_event(event_t *, unsigned long , unsigned long); -extern int process_task_event(event_t *, unsigned long, unsigned long); - -#endif /* __PROCESS_EVENTS_H */ diff --git a/trunk/tools/perf/util/symbol.c b/trunk/tools/perf/util/symbol.c index 4ed379b915fe..44d81d5ae8cf 100644 --- a/trunk/tools/perf/util/symbol.c +++ b/trunk/tools/perf/util/symbol.c @@ -6,7 +6,6 @@ #include "debug.h" -#include #include #include #include @@ -38,16 +37,11 @@ unsigned int symbol__priv_size; static int vmlinux_path__nr_entries; static char **vmlinux_path; -static struct symbol_conf symbol_conf__defaults = { - .use_modules = true, - .try_vmlinux_path = true, -}; - static struct rb_root kernel_maps; -static void symbols__fixup_end(struct rb_root *self) +static void dso__fixup_sym_end(struct dso *self) { - struct rb_node *nd, *prevnd = rb_first(self); + struct rb_node *nd, *prevnd = rb_first(&self->syms); struct symbol *curr, *prev; if (prevnd == NULL) @@ -94,14 +88,15 @@ static void kernel_maps__fixup_end(void) static struct symbol *symbol__new(u64 start, u64 len, const char *name) { size_t namelen = strlen(name) + 1; - struct symbol *self = zalloc(symbol__priv_size + - sizeof(*self) + namelen); - if (self == NULL) + struct symbol *self = calloc(1, (symbol__priv_size + + sizeof(*self) + namelen)); + if (!self) return NULL; - if (symbol__priv_size) + if (symbol__priv_size) { + memset(self, 0, symbol__priv_size); self = ((void *)self) + symbol__priv_size; - + } self->start = start; self->end = len ? start + len - 1 : start; @@ -144,8 +139,8 @@ struct dso *dso__new(const char *name) strcpy(self->name, name); dso__set_long_name(self, self->name); self->short_name = self->name; - self->functions = RB_ROOT; - self->find_function = dso__find_function; + self->syms = RB_ROOT; + self->find_symbol = dso__find_symbol; self->slen_calculated = 0; self->origin = DSO__ORIG_NOT_FOUND; self->loaded = 0; @@ -155,22 +150,22 @@ struct dso *dso__new(const char *name) return self; } -static void symbols__delete(struct rb_root *self) +static void dso__delete_symbols(struct dso *self) { struct symbol *pos; - struct rb_node *next = rb_first(self); + struct rb_node *next = rb_first(&self->syms); while (next) { pos = rb_entry(next, struct symbol, rb_node); next = rb_next(&pos->rb_node); - rb_erase(&pos->rb_node, self); + rb_erase(&pos->rb_node, &self->syms); symbol__delete(pos); } } void dso__delete(struct dso *self) { - symbols__delete(&self->functions); + dso__delete_symbols(self); if (self->long_name != self->name) free(self->long_name); free(self); @@ -182,9 +177,9 @@ void dso__set_build_id(struct dso *self, void *build_id) self->has_build_id = 1; } -static void symbols__insert(struct rb_root *self, struct symbol *sym) +static void dso__insert_symbol(struct dso *self, struct symbol *sym) { - struct rb_node **p = &self->rb_node; + struct rb_node **p = &self->syms.rb_node; struct rb_node *parent = NULL; const u64 ip = sym->start; struct symbol *s; @@ -198,17 +193,17 @@ static void symbols__insert(struct rb_root *self, struct symbol *sym) p = &(*p)->rb_right; } rb_link_node(&sym->rb_node, parent, p); - rb_insert_color(&sym->rb_node, self); + rb_insert_color(&sym->rb_node, &self->syms); } -static struct symbol *symbols__find(struct rb_root *self, u64 ip) +struct symbol *dso__find_symbol(struct dso *self, u64 ip) { struct rb_node *n; if (self == NULL) return NULL; - n = self->rb_node; + n = self->syms.rb_node; while (n) { struct symbol *s = rb_entry(n, struct symbol, rb_node); @@ -224,11 +219,6 @@ static struct symbol *symbols__find(struct rb_root *self, u64 ip) return NULL; } -struct symbol *dso__find_function(struct dso *self, u64 ip) -{ - return symbols__find(&self->functions, ip); -} - int build_id__sprintf(u8 *self, int len, char *bf) { char *bid = bf; @@ -258,9 +248,9 @@ size_t dso__fprintf(struct dso *self, FILE *fp) size_t ret = fprintf(fp, "dso: %s (", self->short_name); ret += dso__fprintf_buildid(self, fp); - ret += fprintf(fp, ")\nFunctions:\n"); + ret += fprintf(fp, ")\n"); - for (nd = rb_first(&self->functions); nd; nd = rb_next(nd)) { + for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { struct symbol *pos = rb_entry(nd, struct symbol, rb_node); ret += symbol__fprintf(pos, fp); } @@ -325,7 +315,7 @@ static int kernel_maps__load_all_kallsyms(void) * kernel_maps__split_kallsyms, when we have split the * maps per module */ - symbols__insert(&kernel_map->dso->functions, sym); + dso__insert_symbol(kernel_map->dso, sym); } free(line); @@ -349,7 +339,7 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter) struct map *map = kernel_map; struct symbol *pos; int count = 0; - struct rb_node *next = rb_first(&kernel_map->dso->functions); + struct rb_node *next = rb_first(&kernel_map->dso->syms); int kernel_range = 0; while (next) { @@ -399,13 +389,12 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter) } if (filter && filter(map, pos)) { - rb_erase(&pos->rb_node, &kernel_map->dso->functions); + rb_erase(&pos->rb_node, &kernel_map->dso->syms); symbol__delete(pos); } else { if (map != kernel_map) { - rb_erase(&pos->rb_node, - &kernel_map->dso->functions); - symbols__insert(&map->dso->functions, pos); + rb_erase(&pos->rb_node, &kernel_map->dso->syms); + dso__insert_symbol(map->dso, pos); } count++; } @@ -420,7 +409,7 @@ static int kernel_maps__load_kallsyms(symbol_filter_t filter) if (kernel_maps__load_all_kallsyms()) return -1; - symbols__fixup_end(&kernel_map->dso->functions); + dso__fixup_sym_end(kernel_map->dso); kernel_map->dso->origin = DSO__ORIG_KERNEL; return kernel_maps__split_kallsyms(filter); @@ -491,7 +480,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map, if (filter && filter(map, sym)) symbol__delete(sym); else { - symbols__insert(&self->functions, sym); + dso__insert_symbol(self, sym); nr_syms++; } } @@ -689,7 +678,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, if (filter && filter(map, f)) symbol__delete(f); else { - symbols__insert(&self->functions, f); + dso__insert_symbol(self, f); ++nr; } } @@ -711,7 +700,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, if (filter && filter(map, f)) symbol__delete(f); else { - symbols__insert(&self->functions, f); + dso__insert_symbol(self, f); ++nr; } } @@ -885,7 +874,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, if (filter && filter(curr_map, f)) symbol__delete(f); else { - symbols__insert(&curr_dso->functions, f); + dso__insert_symbol(curr_dso, f); nr++; } } @@ -894,7 +883,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, * For misannotated, zeroed, ASM function sizes. */ if (nr > 0) - symbols__fixup_end(&self->functions); + dso__fixup_sym_end(self); err = nr; out_elf_end: elf_end(elf); @@ -1166,8 +1155,8 @@ static void kernel_maps__insert(struct map *map) maps__insert(&kernel_maps, map); } -struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp, - symbol_filter_t filter) +struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp, + symbol_filter_t filter) { struct map *map = maps__find(&kernel_maps, ip); @@ -1176,10 +1165,8 @@ struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp, if (map) { ip = map->map_ip(map, ip); - return map__find_function(map, ip, filter); - } else - WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps), - "Empty kernel_maps, was symbol__init() called?\n"); + return map__find_symbol(map, ip, filter); + } return NULL; } @@ -1438,8 +1425,8 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, if (err > 0) { out_fixup: - map__fixup_start(map, &map->dso->functions); - map__fixup_end(map, &map->dso->functions); + map__fixup_start(map); + map__fixup_end(map); } return err; @@ -1498,9 +1485,9 @@ size_t dsos__fprintf_buildid(FILE *fp) return ret; } -static int kernel_maps__create_kernel_map(const struct symbol_conf *conf) +static int kernel_maps__create_kernel_map(const char *vmlinux_name) { - struct dso *kernel = dso__new(conf->vmlinux_name ?: "[kernel.kallsyms]"); + struct dso *kernel = dso__new(vmlinux_name ?: "[kernel.kallsyms]"); if (kernel == NULL) return -1; @@ -1590,21 +1577,18 @@ static int vmlinux_path__init(void) return -1; } -static int kernel_maps__init(const struct symbol_conf *conf) +int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path, + bool use_modules) { - const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; - - symbol__priv_size = pconf->priv_size; - - if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) + if (try_vmlinux_path && vmlinux_path__init() < 0) return -1; - if (kernel_maps__create_kernel_map(pconf) < 0) { + if (kernel_maps__create_kernel_map(vmlinux_name) < 0) { vmlinux_path__exit(); return -1; } - if (pconf->use_modules && kernel_maps__create_module_maps() < 0) + if (use_modules && kernel_maps__create_module_maps() < 0) pr_debug("Failed to load list of modules in use, " "continuing...\n"); /* @@ -1614,8 +1598,8 @@ static int kernel_maps__init(const struct symbol_conf *conf) return 0; } -int symbol__init(struct symbol_conf *conf) +void symbol__init(unsigned int priv_size) { elf_version(EV_CURRENT); - return kernel_maps__init(conf); + symbol__priv_size = priv_size; } diff --git a/trunk/tools/perf/util/symbol.h b/trunk/tools/perf/util/symbol.h index 65846d0c5df7..8c4d026e067a 100644 --- a/trunk/tools/perf/util/symbol.h +++ b/trunk/tools/perf/util/symbol.h @@ -49,13 +49,6 @@ struct symbol { char name[0]; }; -struct symbol_conf { - unsigned short priv_size; - bool try_vmlinux_path, - use_modules; - const char *vmlinux_name; -}; - extern unsigned int symbol__priv_size; static inline void *symbol__priv(struct symbol *self) @@ -65,8 +58,8 @@ static inline void *symbol__priv(struct symbol *self) struct dso { struct list_head node; - struct rb_root functions; - struct symbol *(*find_function)(struct dso *, u64 ip); + struct rb_root syms; + struct symbol *(*find_symbol)(struct dso *, u64 ip); u8 adjust_symbols:1; u8 slen_calculated:1; u8 loaded:1; @@ -83,7 +76,7 @@ struct dso { struct dso *dso__new(const char *name); void dso__delete(struct dso *self); -struct symbol *dso__find_function(struct dso *self, u64 ip); +struct symbol *dso__find_symbol(struct dso *self, u64 ip); struct dso *dsos__findnew(const char *name); int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); @@ -100,9 +93,11 @@ int sysfs__read_build_id(const char *filename, void *bf, size_t size); bool dsos__read_build_ids(void); int build_id__sprintf(u8 *self, int len, char *bf); +int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path, + bool use_modules); size_t kernel_maps__fprintf(FILE *fp); -int symbol__init(struct symbol_conf *conf); +void symbol__init(unsigned int priv_size); extern struct list_head dsos; extern struct map *kernel_map; diff --git a/trunk/tools/perf/util/thread.c b/trunk/tools/perf/util/thread.c index 1796625f7784..0f6d78c9863a 100644 --- a/trunk/tools/perf/util/thread.c +++ b/trunk/tools/perf/util/thread.c @@ -11,7 +11,7 @@ static struct thread *last_match; static struct thread *thread__new(pid_t pid) { - struct thread *self = zalloc(sizeof(*self)); + struct thread *self = calloc(1, sizeof(*self)); if (self != NULL) { self->pid = pid; diff --git a/trunk/tools/perf/util/thread.h b/trunk/tools/perf/util/thread.h index 74cba6487edb..e4b8d437725a 100644 --- a/trunk/tools/perf/util/thread.h +++ b/trunk/tools/perf/util/thread.h @@ -26,8 +26,8 @@ size_t threads__fprintf(FILE *fp); void maps__insert(struct rb_root *maps, struct map *map); struct map *maps__find(struct rb_root *maps, u64 ip); -struct symbol *kernel_maps__find_function(const u64 ip, struct map **mapp, - symbol_filter_t filter); +struct symbol *kernel_maps__find_symbol(const u64 ip, struct map **mapp, + symbol_filter_t filter); struct map *kernel_maps__find_by_dso_name(const char *name); static inline struct map *thread__find_map(struct thread *self, u64 ip) diff --git a/trunk/tools/perf/util/util.h b/trunk/tools/perf/util/util.h index c673d8825883..e1c623e0c99e 100644 --- a/trunk/tools/perf/util/util.h +++ b/trunk/tools/perf/util/util.h @@ -290,15 +290,17 @@ static inline char *gitstrchrnul(const char *s, int c) * Wrappers: */ extern char *xstrdup(const char *str); -extern void *xmalloc(size_t size) __attribute__((weak)); +extern void *xmalloc(size_t size); extern void *xmemdupz(const void *data, size_t len); extern char *xstrndup(const char *str, size_t len); -extern void *xrealloc(void *ptr, size_t size) __attribute__((weak)); - -static inline void *zalloc(size_t size) -{ - return calloc(1, size); -} +extern void *xrealloc(void *ptr, size_t size); +extern void *xcalloc(size_t nmemb, size_t size); +extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); +extern ssize_t xread(int fd, void *buf, size_t len); +extern ssize_t xwrite(int fd, const void *buf, size_t len); +extern int xdup(int fd); +extern FILE *xfdopen(int fd, const char *mode); +extern int xmkstemp(char *template); static inline size_t xsize_t(off_t len) { diff --git a/trunk/tools/perf/util/wrapper.c b/trunk/tools/perf/util/wrapper.c index bf44ca85d23b..4574ac28396f 100644 --- a/trunk/tools/perf/util/wrapper.c +++ b/trunk/tools/perf/util/wrapper.c @@ -79,12 +79,43 @@ void *xrealloc(void *ptr, size_t size) return ret; } +void *xcalloc(size_t nmemb, size_t size) +{ + void *ret = calloc(nmemb, size); + if (!ret && (!nmemb || !size)) + ret = calloc(1, 1); + if (!ret) { + release_pack_memory(nmemb * size, -1); + ret = calloc(nmemb, size); + if (!ret && (!nmemb || !size)) + ret = calloc(1, 1); + if (!ret) + die("Out of memory, calloc failed"); + } + return ret; +} + +void *xmmap(void *start, size_t length, + int prot, int flags, int fd, off_t offset) +{ + void *ret = mmap(start, length, prot, flags, fd, offset); + if (ret == MAP_FAILED) { + if (!length) + return NULL; + release_pack_memory(length, fd); + ret = mmap(start, length, prot, flags, fd, offset); + if (ret == MAP_FAILED) + die("Out of memory? mmap failed: %s", strerror(errno)); + } + return ret; +} + /* * xread() is the same a read(), but it automatically restarts read() * operations with a recoverable error (EAGAIN and EINTR). xread() * DOES NOT GUARANTEE that "len" bytes is read even if the data is available. */ -static ssize_t xread(int fd, void *buf, size_t len) +ssize_t xread(int fd, void *buf, size_t len) { ssize_t nr; while (1) { @@ -100,7 +131,7 @@ static ssize_t xread(int fd, void *buf, size_t len) * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT * GUARANTEE that "len" bytes is written even if the operation is successful. */ -static ssize_t xwrite(int fd, const void *buf, size_t len) +ssize_t xwrite(int fd, const void *buf, size_t len) { ssize_t nr; while (1) { @@ -148,3 +179,29 @@ ssize_t write_in_full(int fd, const void *buf, size_t count) return total; } + +int xdup(int fd) +{ + int ret = dup(fd); + if (ret < 0) + die("dup failed: %s", strerror(errno)); + return ret; +} + +FILE *xfdopen(int fd, const char *mode) +{ + FILE *stream = fdopen(fd, mode); + if (stream == NULL) + die("Out of memory? fdopen failed: %s", strerror(errno)); + return stream; +} + +int xmkstemp(char *template) +{ + int fd; + + fd = mkstemp(template); + if (fd < 0) + die("Unable to create temporary file: %s", strerror(errno)); + return fd; +}