From 919d590f13c94c5465db723178e4b72200fd5f90 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 20 Nov 2012 10:51:02 +0100 Subject: perf symbols: Fix dso__fprintf() print statement Was ignoring the dso type (function vs. variable) and was therefore printing bogus information. Signed-off-by: Stephane Eranian Cc: Ingo Molnar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20121120095101.GA5939@quad Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index d6d9a465acdb..be437850edc8 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -583,7 +583,7 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) if (dso->short_name != dso->long_name) ret += fprintf(fp, "%s, ", dso->long_name); ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], - dso->loaded ? "" : "NOT "); + dso__loaded(dso, type) ? "" : "NOT "); ret += dso__fprintf_buildid(dso, fp); ret += fprintf(fp, ")\n"); for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { -- cgit v1.2.3-59-g8ed1b From 752914208ada0d9ae0a6b3bf2906d43f3605832f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 15 Nov 2012 01:47:40 +0900 Subject: perf ui: Always compile error printing code It is used everywhere so always build it regardless of ui engine. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1352911664-24620-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 14 +++++--------- tools/perf/ui/util.c | 10 ++++++++++ tools/perf/util/debug.c | 22 ---------------------- tools/perf/util/debug.h | 33 ++------------------------------- 4 files changed, 17 insertions(+), 62 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 891bc77bdb2c..8fca560cf78e 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -378,8 +378,11 @@ LIB_H += util/rblist.h LIB_H += util/intlist.h LIB_H += util/perf_regs.h LIB_H += util/unwind.h -LIB_H += ui/helpline.h LIB_H += util/vdso.h +LIB_H += ui/helpline.h +LIB_H += ui/progress.h +LIB_H += ui/util.h +LIB_H += ui/ui.h LIB_OBJS += $(OUTPUT)util/abspath.o LIB_OBJS += $(OUTPUT)util/alias.o @@ -453,6 +456,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o LIB_OBJS += $(OUTPUT)ui/setup.o LIB_OBJS += $(OUTPUT)ui/helpline.o LIB_OBJS += $(OUTPUT)ui/progress.o +LIB_OBJS += $(OUTPUT)ui/util.o LIB_OBJS += $(OUTPUT)ui/hist.o LIB_OBJS += $(OUTPUT)ui/stdio/hist.o @@ -646,7 +650,6 @@ ifndef NO_NEWT LIB_OBJS += $(OUTPUT)ui/browsers/hists.o LIB_OBJS += $(OUTPUT)ui/browsers/map.o LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o - LIB_OBJS += $(OUTPUT)ui/util.o LIB_OBJS += $(OUTPUT)ui/tui/setup.o LIB_OBJS += $(OUTPUT)ui/tui/util.o LIB_OBJS += $(OUTPUT)ui/tui/helpline.o @@ -655,9 +658,6 @@ ifndef NO_NEWT LIB_H += ui/browsers/map.h LIB_H += ui/keysyms.h LIB_H += ui/libslang.h - LIB_H += ui/progress.h - LIB_H += ui/util.h - LIB_H += ui/ui.h endif endif @@ -677,10 +677,6 @@ ifndef NO_GTK2 LIB_OBJS += $(OUTPUT)ui/gtk/util.o LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o LIB_OBJS += $(OUTPUT)ui/gtk/progress.o - # Make sure that it'd be included only once. - ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),) - LIB_OBJS += $(OUTPUT)ui/util.o - endif endif endif diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c index 4f989774c8c6..3014a7cd5271 100644 --- a/tools/perf/ui/util.c +++ b/tools/perf/ui/util.c @@ -52,6 +52,16 @@ int ui__warning(const char *format, ...) return ret; } +int ui__error_paranoid(void) +{ + return ui__error("Permission error - are you root?\n" + "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" + " -1 - Not paranoid at all\n" + " 0 - Disallow raw tracepoint access for unpriv\n" + " 1 - Disallow cpu events for unpriv\n" + " 2 - Disallow kernel profiling for unpriv\n"); +} + /** * perf_error__register - Register error logging functions diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 03f830b48148..39861a2a7d18 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -49,28 +49,6 @@ int dump_printf(const char *fmt, ...) return ret; } -#if !defined(NEWT_SUPPORT) && !defined(GTK2_SUPPORT) -int ui__warning(const char *format, ...) -{ - va_list args; - - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - return 0; -} -#endif - -int ui__error_paranoid(void) -{ - return ui__error("Permission error - are you root?\n" - "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" - " -1 - Not paranoid at all\n" - " 0 - Disallow raw tracepoint access for unpriv\n" - " 1 - Disallow cpu events for unpriv\n" - " 2 - Disallow kernel profiling for unpriv\n"); -} - void trace_event(union perf_event *event) { unsigned char *raw_event = (void *)event; diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 83e8d234af6b..6e2667fb8211 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -5,6 +5,8 @@ #include #include "event.h" #include "../ui/helpline.h" +#include "../ui/progress.h" +#include "../ui/util.h" extern int verbose; extern bool quiet, dump_trace; @@ -12,38 +14,7 @@ extern bool quiet, dump_trace; int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void trace_event(union perf_event *event); -struct ui_progress; -struct perf_error_ops; - -#if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT) - -#include "../ui/progress.h" int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); -#include "../ui/util.h" - -#else - -static inline void ui_progress__update(u64 curr __maybe_unused, - u64 total __maybe_unused, - const char *title __maybe_unused) {} -static inline void ui_progress__finish(void) {} - -#define ui__error(format, arg...) ui__warning(format, ##arg) - -static inline int -perf_error__register(struct perf_error_ops *eops __maybe_unused) -{ - return 0; -} - -static inline int -perf_error__unregister(struct perf_error_ops *eops __maybe_unused) -{ - return 0; -} - -#endif /* NEWT_SUPPORT || GTK2_SUPPORT */ - int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); int ui__error_paranoid(void); -- cgit v1.2.3-59-g8ed1b From b56e53312d445967f6bdb91e5667c56755e47450 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 15 Nov 2012 01:47:41 +0900 Subject: perf ui/helpline: Introduce ui_helpline__vshow() The ui_helpline__vshow() will be used for pr_* functions. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1352911664-24620-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/gtk/helpline.c | 23 ++++++++++++----------- tools/perf/ui/helpline.c | 12 ++++++++++++ tools/perf/ui/helpline.h | 22 ++-------------------- tools/perf/ui/tui/helpline.c | 29 +++++++++++++++-------------- tools/perf/util/debug.c | 6 ++---- 5 files changed, 43 insertions(+), 49 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/ui/gtk/helpline.c b/tools/perf/ui/gtk/helpline.c index 5db4432ff12a..3388cbd12186 100644 --- a/tools/perf/ui/gtk/helpline.c +++ b/tools/perf/ui/gtk/helpline.c @@ -24,17 +24,7 @@ static void gtk_helpline_push(const char *msg) pgctx->statbar_ctx_id, msg); } -static struct ui_helpline gtk_helpline_fns = { - .pop = gtk_helpline_pop, - .push = gtk_helpline_push, -}; - -void perf_gtk__init_helpline(void) -{ - helpline_fns = >k_helpline_fns; -} - -int perf_gtk__show_helpline(const char *fmt, va_list ap) +static int gtk_helpline_show(const char *fmt, va_list ap) { int ret; char *ptr; @@ -54,3 +44,14 @@ int perf_gtk__show_helpline(const char *fmt, va_list ap) return ret; } + +static struct ui_helpline gtk_helpline_fns = { + .pop = gtk_helpline_pop, + .push = gtk_helpline_push, + .show = gtk_helpline_show, +}; + +void perf_gtk__init_helpline(void) +{ + helpline_fns = >k_helpline_fns; +} diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c index a49bcf3c190b..700fb3cfa1c7 100644 --- a/tools/perf/ui/helpline.c +++ b/tools/perf/ui/helpline.c @@ -16,9 +16,16 @@ static void nop_helpline__push(const char *msg __maybe_unused) { } +static int nop_helpline__show(const char *fmt __maybe_unused, + va_list ap __maybe_unused) +{ + return 0; +} + static struct ui_helpline default_helpline_fns = { .pop = nop_helpline__pop, .push = nop_helpline__push, + .show = nop_helpline__show, }; struct ui_helpline *helpline_fns = &default_helpline_fns; @@ -59,3 +66,8 @@ void ui_helpline__puts(const char *msg) ui_helpline__pop(); ui_helpline__push(msg); } + +int ui_helpline__vshow(const char *fmt, va_list ap) +{ + return helpline_fns->show(fmt, ap); +} diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h index baa28a4d16b9..46181f4fc07e 100644 --- a/tools/perf/ui/helpline.h +++ b/tools/perf/ui/helpline.h @@ -9,6 +9,7 @@ struct ui_helpline { void (*pop)(void); void (*push)(const char *msg); + int (*show)(const char *fmt, va_list ap); }; extern struct ui_helpline *helpline_fns; @@ -20,28 +21,9 @@ void ui_helpline__push(const char *msg); void ui_helpline__vpush(const char *fmt, va_list ap); void ui_helpline__fpush(const char *fmt, ...); void ui_helpline__puts(const char *msg); +int ui_helpline__vshow(const char *fmt, va_list ap); extern char ui_helpline__current[512]; - -#ifdef NEWT_SUPPORT extern char ui_helpline__last_msg[]; -int ui_helpline__show_help(const char *format, va_list ap); -#else -static inline int ui_helpline__show_help(const char *format __maybe_unused, - va_list ap __maybe_unused) -{ - return 0; -} -#endif /* NEWT_SUPPORT */ - -#ifdef GTK2_SUPPORT -int perf_gtk__show_helpline(const char *format, va_list ap); -#else -static inline int perf_gtk__show_helpline(const char *format __maybe_unused, - va_list ap __maybe_unused) -{ - return 0; -} -#endif /* GTK2_SUPPORT */ #endif /* _PERF_UI_HELPLINE_H_ */ diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c index 2884d2f41e33..1c8b9afd5d6e 100644 --- a/tools/perf/ui/tui/helpline.c +++ b/tools/perf/ui/tui/helpline.c @@ -8,6 +8,8 @@ #include "../ui.h" #include "../libslang.h" +char ui_helpline__last_msg[1024]; + static void tui_helpline__pop(void) { } @@ -23,20 +25,7 @@ static void tui_helpline__push(const char *msg) strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; } -struct ui_helpline tui_helpline_fns = { - .pop = tui_helpline__pop, - .push = tui_helpline__push, -}; - -void ui_helpline__init(void) -{ - helpline_fns = &tui_helpline_fns; - ui_helpline__puts(" "); -} - -char ui_helpline__last_msg[1024]; - -int ui_helpline__show_help(const char *format, va_list ap) +static int tui_helpline__show(const char *format, va_list ap) { int ret; static int backlog; @@ -55,3 +44,15 @@ int ui_helpline__show_help(const char *format, va_list ap) return ret; } + +struct ui_helpline tui_helpline_fns = { + .pop = tui_helpline__pop, + .push = tui_helpline__push, + .show = tui_helpline__show, +}; + +void ui_helpline__init(void) +{ + helpline_fns = &tui_helpline_fns; + ui_helpline__puts(" "); +} diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 39861a2a7d18..391c9a9e946f 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -23,10 +23,8 @@ int eprintf(int level, const char *fmt, ...) if (verbose >= level) { va_start(args, fmt); - if (use_browser == 1) - ret = ui_helpline__show_help(fmt, args); - else if (use_browser == 2) - ret = perf_gtk__show_helpline(fmt, args); + if (use_browser > 1) + ui_helpline__vshow(fmt, args); else ret = vfprintf(stderr, fmt, args); va_end(args); -- cgit v1.2.3-59-g8ed1b From 03cd20949964f5cda600a56e12ffac39dfec4cb0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 21 Nov 2012 13:43:19 +0900 Subject: perf session: Free environment information when deleting session The perf session environment information was saved (so allocated) during perf_session__open, but was not freed. As free(3) handles NULL pointer input properly it won't cause a issue for writing modes - e.g. perf record Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Feng Tang Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1353472999-23042-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index ce6f51162386..d5fb60760bac 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -204,11 +204,28 @@ static void perf_session__delete_threads(struct perf_session *session) machine__delete_threads(&session->host_machine); } +static void perf_session_env__delete(struct perf_session_env *env) +{ + free(env->hostname); + free(env->os_release); + free(env->version); + free(env->arch); + free(env->cpu_desc); + free(env->cpuid); + + free(env->cmdline); + free(env->sibling_cores); + free(env->sibling_threads); + free(env->numa_nodes); + free(env->pmu_mappings); +} + void perf_session__delete(struct perf_session *self) { perf_session__destroy_kernel_maps(self); perf_session__delete_dead_threads(self); perf_session__delete_threads(self); + perf_session_env__delete(&self->header.env); machine__exit(&self->host_machine); close(self->fd); free(self); -- cgit v1.2.3-59-g8ed1b From 35d48ddfc0627443bd7ad2750a3f65d42cb742a0 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 10 Nov 2012 14:12:19 -0500 Subject: perf tools: Fix mmap limitations on 32-bit This is a suggested patch to fix the bug I reported at: http://marc.info/?l=linux-kernel&m=135033028924652&w=2 Essentially, there is a hard requirement that when perf analyzes a trace, it must have the entire thing mmap()'d. Therefore the scheme used on 32-bit where we have a fixed (8) number of 32MB mmaps, and cycle through them, simply does not work. One of the reasons this requirement exists is because the iterators maintain references to perf entry objects and those references don't just simply go away when this mmap code decides to cycle an old mmap area out and reuse it. At this point, those entry pointers now point to garbage resulting in unpredictable behavior and crashes. It is better to try to mmap() as much as we can and if we do actually run into address space limitations, the failure of the mmap() call will indicate that and stop processing. I noticed that perf_session->mmap_window is set to a constant in one location, and only used in one other location. So I got rid of it altogether. So we adjust the size of the mmaps[] array to the maximum we could need. On 64-bit we only need one slot. On 32-bit we could need up to 128 (128 * 32MB == 4GB). I've verified that this allows a large (~600MB) perf.data file to be analyzed properly with a 32-bit perf binary, which previously was not possible. Signed-off-by: David S. Miller Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20121110.141219.582924082787523608.davem@davemloft.net Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 25 ++++++++++++++----------- tools/perf/util/session.h | 1 - 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index d5fb60760bac..aa5e58255cba 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -128,15 +128,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, goto out; memcpy(self->filename, filename, len); - /* - * On 64bit we can mmap the data file in one go. No need for tiny mmap - * slices. On 32bit we use 32MB. - */ -#if BITS_PER_LONG == 64 - self->mmap_window = ULLONG_MAX; -#else - self->mmap_window = 32 * 1024 * 1024ULL; -#endif self->machines = RB_ROOT; self->repipe = repipe; INIT_LIST_HEAD(&self->ordered_samples.samples); @@ -1386,6 +1377,18 @@ fetch_mmaped_event(struct perf_session *session, return event; } +/* + * On 64bit we can mmap the data file in one go. No need for tiny mmap + * slices. On 32bit we use 32MB. + */ +#if BITS_PER_LONG == 64 +#define MMAP_SIZE ULLONG_MAX +#define NUM_MMAPS 1 +#else +#define MMAP_SIZE (32 * 1024 * 1024ULL) +#define NUM_MMAPS 128 +#endif + int __perf_session__process_events(struct perf_session *session, u64 data_offset, u64 data_size, u64 file_size, struct perf_tool *tool) @@ -1393,7 +1396,7 @@ int __perf_session__process_events(struct perf_session *session, u64 head, page_offset, file_offset, file_pos, progress_next; int err, mmap_prot, mmap_flags, map_idx = 0; size_t mmap_size; - char *buf, *mmaps[8]; + char *buf, *mmaps[NUM_MMAPS]; union perf_event *event; uint32_t size; @@ -1408,7 +1411,7 @@ int __perf_session__process_events(struct perf_session *session, progress_next = file_size / 16; - mmap_size = session->mmap_window; + mmap_size = MMAP_SIZE; if (mmap_size > file_size) mmap_size = file_size; diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index cea133a6bdf1..c18fabdff19b 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -30,7 +30,6 @@ struct ordered_samples { struct perf_session { struct perf_header header; unsigned long size; - unsigned long mmap_window; struct machine host_machine; struct rb_root machines; struct perf_evlist *evlist; -- cgit v1.2.3-59-g8ed1b From 1240005e0d3a7e03c2fd05603fb01676e5a004f7 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 13 Oct 2012 00:06:16 +0200 Subject: perf hists: Introduce perf_hpp__list for period related columns Adding perf_hpp__list list to register and contain all period related columns the command is interested in. This way we get rid of static array holding all possible columns and enable commands to register their own columns. It'll be handy for diff command in future to process and display data for multiple files. Signed-off-by: Jiri Olsa Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Paul Mackerras Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Link: http://lkml.kernel.org/n/tip-kiykge4igrcl7etmpmveto1h@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 21 ++++----- tools/perf/builtin-report.c | 1 + tools/perf/ui/browsers/hists.c | 20 +++++---- tools/perf/ui/gtk/browser.c | 30 +++++-------- tools/perf/ui/hist.c | 96 +++++++++++++++++++++++------------------- tools/perf/ui/setup.c | 1 + tools/perf/ui/stdio/hist.c | 17 +++----- tools/perf/util/hist.h | 11 ++++- 8 files changed, 101 insertions(+), 96 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 93b852f8a5d5..9fbbc01c5ad7 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -597,40 +597,35 @@ static const struct option options[] = { static void ui_init(void) { - perf_hpp__init(); - - /* No overhead column. */ - perf_hpp__column_enable(PERF_HPP__OVERHEAD, false); - /* * Display baseline/delta/ratio/displacement/ * formula/periods columns. */ - perf_hpp__column_enable(PERF_HPP__BASELINE, true); + perf_hpp__column_enable(PERF_HPP__BASELINE); switch (compute) { case COMPUTE_DELTA: - perf_hpp__column_enable(PERF_HPP__DELTA, true); + perf_hpp__column_enable(PERF_HPP__DELTA); break; case COMPUTE_RATIO: - perf_hpp__column_enable(PERF_HPP__RATIO, true); + perf_hpp__column_enable(PERF_HPP__RATIO); break; case COMPUTE_WEIGHTED_DIFF: - perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF, true); + perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF); break; default: BUG_ON(1); }; if (show_displacement) - perf_hpp__column_enable(PERF_HPP__DISPL, true); + perf_hpp__column_enable(PERF_HPP__DISPL); if (show_formula) - perf_hpp__column_enable(PERF_HPP__FORMULA, true); + perf_hpp__column_enable(PERF_HPP__FORMULA); if (show_period) { - perf_hpp__column_enable(PERF_HPP__PERIOD, true); - perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE, true); + perf_hpp__column_enable(PERF_HPP__PERIOD); + perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE); } } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index fc251005dd3d..5134acf1c39a 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -692,6 +692,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) setup_browser(true); else { use_browser = 0; + perf_hpp__column_enable(PERF_HPP__OVERHEAD); perf_hpp__init(); } diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index ccc4bd161420..57b82c26cd05 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -587,6 +587,8 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us) void hist_browser__init_hpp(void) { + perf_hpp__column_enable(PERF_HPP__OVERHEAD); + perf_hpp__init(); perf_hpp__format[PERF_HPP__OVERHEAD].color = @@ -607,12 +609,13 @@ static int hist_browser__show_entry(struct hist_browser *browser, { char s[256]; double percent; - int i, printed = 0; + int printed = 0; int width = browser->b.width; char folded_sign = ' '; bool current_entry = ui_browser__is_current_entry(&browser->b, row); off_t row_offset = entry->row_offset; bool first = true; + struct perf_hpp_fmt *fmt; if (current_entry) { browser->he_selection = entry; @@ -629,12 +632,11 @@ static int hist_browser__show_entry(struct hist_browser *browser, .buf = s, .size = sizeof(s), }; + int i = 0; ui_browser__gotorc(&browser->b, row, 0); - for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { - if (!perf_hpp__format[i].cond) - continue; + perf_hpp__for_each_format(fmt) { if (!first) { slsmg_printf(" "); @@ -642,14 +644,14 @@ static int hist_browser__show_entry(struct hist_browser *browser, } first = false; - if (perf_hpp__format[i].color) { + if (fmt->color) { hpp.ptr = &percent; /* It will set percent for us. See HPP__COLOR_FN above. */ - width -= perf_hpp__format[i].color(&hpp, entry); + width -= fmt->color(&hpp, entry); ui_browser__set_percent_color(&browser->b, percent, current_entry); - if (i == PERF_HPP__OVERHEAD && symbol_conf.use_callchain) { + if (!i && symbol_conf.use_callchain) { slsmg_printf("%c ", folded_sign); width -= 2; } @@ -659,9 +661,11 @@ static int hist_browser__show_entry(struct hist_browser *browser, if (!current_entry || !browser->b.navkeypressed) ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); } else { - width -= perf_hpp__format[i].entry(&hpp, entry); + width -= fmt->entry(&hpp, entry); slsmg_printf("%s", s); } + + i++; } /* The scroll bar isn't being used */ diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c index 253b6219a39e..e59ba337f494 100644 --- a/tools/perf/ui/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c @@ -74,6 +74,8 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us) void perf_gtk__init_hpp(void) { + perf_hpp__column_enable(PERF_HPP__OVERHEAD); + perf_hpp__init(); perf_hpp__format[PERF_HPP__OVERHEAD].color = @@ -90,13 +92,14 @@ void perf_gtk__init_hpp(void) static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) { + struct perf_hpp_fmt *fmt; GType col_types[MAX_COLUMNS]; GtkCellRenderer *renderer; struct sort_entry *se; GtkListStore *store; struct rb_node *nd; GtkWidget *view; - int i, col_idx; + int col_idx; int nr_cols; char s[512]; @@ -107,12 +110,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) nr_cols = 0; - for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { - if (!perf_hpp__format[i].cond) - continue; - + perf_hpp__for_each_format(fmt) col_types[nr_cols++] = G_TYPE_STRING; - } list_for_each_entry(se, &hist_entry__sort_list, list) { if (se->elide) @@ -129,12 +128,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) col_idx = 0; - for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { - if (!perf_hpp__format[i].cond) - continue; - - perf_hpp__format[i].header(&hpp); - + perf_hpp__for_each_format(fmt) { + fmt->header(&hpp); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, s, renderer, "markup", @@ -166,14 +161,11 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) col_idx = 0; - for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { - if (!perf_hpp__format[i].cond) - continue; - - if (perf_hpp__format[i].color) - perf_hpp__format[i].color(&hpp, h); + perf_hpp__for_each_format(fmt) { + if (fmt->color) + fmt->color(&hpp, h); else - perf_hpp__format[i].entry(&hpp, h); + fmt->entry(&hpp, h); gtk_list_store_set(store, &iter, col_idx++, s, -1); } diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index aa84130024d5..0a5281fe41d6 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -386,60 +386,71 @@ static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) return scnprintf(hpp->buf, hpp->size, fmt, buf); } -#define HPP__COLOR_PRINT_FNS(_name) \ - .header = hpp__header_ ## _name, \ - .width = hpp__width_ ## _name, \ - .color = hpp__color_ ## _name, \ - .entry = hpp__entry_ ## _name +#define HPP__COLOR_PRINT_FNS(_name) \ + { \ + .header = hpp__header_ ## _name, \ + .width = hpp__width_ ## _name, \ + .color = hpp__color_ ## _name, \ + .entry = hpp__entry_ ## _name \ + } -#define HPP__PRINT_FNS(_name) \ - .header = hpp__header_ ## _name, \ - .width = hpp__width_ ## _name, \ - .entry = hpp__entry_ ## _name +#define HPP__PRINT_FNS(_name) \ + { \ + .header = hpp__header_ ## _name, \ + .width = hpp__width_ ## _name, \ + .entry = hpp__entry_ ## _name \ + } struct perf_hpp_fmt perf_hpp__format[] = { - { .cond = false, HPP__COLOR_PRINT_FNS(baseline) }, - { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, - { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, - { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, - { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) }, - { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) }, - { .cond = false, HPP__PRINT_FNS(samples) }, - { .cond = false, HPP__PRINT_FNS(period) }, - { .cond = false, HPP__PRINT_FNS(period_baseline) }, - { .cond = false, HPP__PRINT_FNS(delta) }, - { .cond = false, HPP__PRINT_FNS(ratio) }, - { .cond = false, HPP__PRINT_FNS(wdiff) }, - { .cond = false, HPP__PRINT_FNS(displ) }, - { .cond = false, HPP__PRINT_FNS(formula) } + HPP__COLOR_PRINT_FNS(baseline), + HPP__COLOR_PRINT_FNS(overhead), + HPP__COLOR_PRINT_FNS(overhead_sys), + HPP__COLOR_PRINT_FNS(overhead_us), + HPP__COLOR_PRINT_FNS(overhead_guest_sys), + HPP__COLOR_PRINT_FNS(overhead_guest_us), + HPP__PRINT_FNS(samples), + HPP__PRINT_FNS(period), + HPP__PRINT_FNS(period_baseline), + HPP__PRINT_FNS(delta), + HPP__PRINT_FNS(ratio), + HPP__PRINT_FNS(wdiff), + HPP__PRINT_FNS(displ), + HPP__PRINT_FNS(formula) }; +LIST_HEAD(perf_hpp__list); + #undef HPP__COLOR_PRINT_FNS #undef HPP__PRINT_FNS void perf_hpp__init(void) { if (symbol_conf.show_cpu_utilization) { - perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; - perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true; + perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); + perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); if (perf_guest) { - perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true; - perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true; + perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS); + perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US); } } if (symbol_conf.show_nr_samples) - perf_hpp__format[PERF_HPP__SAMPLES].cond = true; + perf_hpp__column_enable(PERF_HPP__SAMPLES); if (symbol_conf.show_total_period) - perf_hpp__format[PERF_HPP__PERIOD].cond = true; + perf_hpp__column_enable(PERF_HPP__PERIOD); } -void perf_hpp__column_enable(unsigned col, bool enable) +void perf_hpp__column_register(struct perf_hpp_fmt *format) +{ + list_add_tail(&format->list, &perf_hpp__list); +} + +void perf_hpp__column_enable(unsigned col) { BUG_ON(col >= PERF_HPP__MAX_INDEX); - perf_hpp__format[col].cond = enable; + perf_hpp__column_register(&perf_hpp__format[col]); } static inline void advance_hpp(struct perf_hpp *hpp, int inc) @@ -452,27 +463,25 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, bool color) { const char *sep = symbol_conf.field_sep; + struct perf_hpp_fmt *fmt; char *start = hpp->buf; - int i, ret; + int ret; bool first = true; if (symbol_conf.exclude_other && !he->parent) return 0; - for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { - if (!perf_hpp__format[i].cond) - continue; - + perf_hpp__for_each_format(fmt) { if (!sep || !first) { ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); advance_hpp(hpp, ret); first = false; } - if (color && perf_hpp__format[i].color) - ret = perf_hpp__format[i].color(hpp, he); + if (color && fmt->color) + ret = fmt->color(hpp, he); else - ret = perf_hpp__format[i].entry(hpp, he); + ret = fmt->entry(hpp, he); advance_hpp(hpp, ret); } @@ -504,16 +513,15 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, */ unsigned int hists__sort_list_width(struct hists *hists) { + struct perf_hpp_fmt *fmt; struct sort_entry *se; - int i, ret = 0; + int i = 0, ret = 0; - for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { - if (!perf_hpp__format[i].cond) - continue; + perf_hpp__for_each_format(fmt) { if (i) ret += 2; - ret += perf_hpp__format[i].width(NULL); + ret += fmt->width(NULL); } list_for_each_entry(se, &hist_entry__sort_list, list) diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index ebb4cc107876..166f13df3134 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c @@ -30,6 +30,7 @@ void setup_browser(bool fallback_to_pager) if (fallback_to_pager) setup_pager(); + perf_hpp__column_enable(PERF_HPP__OVERHEAD); perf_hpp__init(); break; } diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index f0ee204f99bb..0eae3b2c32f2 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -335,13 +335,14 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, int max_cols, FILE *fp) { + struct perf_hpp_fmt *fmt; struct sort_entry *se; struct rb_node *nd; size_t ret = 0; unsigned int width; const char *sep = symbol_conf.field_sep; const char *col_width = symbol_conf.col_width_list_str; - int idx, nr_rows = 0; + int nr_rows = 0; char bf[96]; struct perf_hpp dummy_hpp = { .buf = bf, @@ -355,16 +356,14 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, goto print_entries; fprintf(fp, "# "); - for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { - if (!perf_hpp__format[idx].cond) - continue; + perf_hpp__for_each_format(fmt) { if (!first) fprintf(fp, "%s", sep ?: " "); else first = false; - perf_hpp__format[idx].header(&dummy_hpp); + fmt->header(&dummy_hpp); fprintf(fp, "%s", bf); } @@ -400,18 +399,16 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, first = true; fprintf(fp, "# "); - for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { - unsigned int i; - if (!perf_hpp__format[idx].cond) - continue; + perf_hpp__for_each_format(fmt) { + unsigned int i; if (!first) fprintf(fp, "%s", sep ?: " "); else first = false; - width = perf_hpp__format[idx].width(&dummy_hpp); + width = fmt->width(&dummy_hpp); for (i = 0; i < width; i++) fprintf(fp, "."); } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 8b091a51e4a2..a935a60d521c 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -126,13 +126,19 @@ struct perf_hpp { }; struct perf_hpp_fmt { - bool cond; int (*header)(struct perf_hpp *hpp); int (*width)(struct perf_hpp *hpp); int (*color)(struct perf_hpp *hpp, struct hist_entry *he); int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); + + struct list_head list; }; +extern struct list_head perf_hpp__list; + +#define perf_hpp__for_each_format(format) \ + list_for_each_entry(format, &perf_hpp__list, list) + extern struct perf_hpp_fmt perf_hpp__format[]; enum { @@ -155,7 +161,8 @@ enum { }; void perf_hpp__init(void); -void perf_hpp__column_enable(unsigned col, bool enable); +void perf_hpp__column_register(struct perf_hpp_fmt *format); +void perf_hpp__column_enable(unsigned col); int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, bool color); -- cgit v1.2.3-59-g8ed1b From 3843b05d6ef20acbd4b0043e4ab7536602eb10ae Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 21 Nov 2012 13:49:44 +0100 Subject: perf symbols: Ignore ABS symbols when loading data maps When loading symbols in a data mapping, ABS symbols (which has a value of SHN_ABS in its st_shndx) failed at elf_getscn(). And it marks the loading as a failure so already loaded symbols cannot be fixed up. I'm not sure what should be done. Just ignore them for now. :) Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1353502185-26521-19-git-send-email-eranian@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol-elf.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index db0cc92cf2ea..f63557b59c06 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -718,6 +718,17 @@ int dso__load_sym(struct dso *dso, struct map *map, sym.st_value); used_opd = true; } + /* + * When loading symbols in a data mapping, ABS symbols (which + * has a value of SHN_ABS in its st_shndx) failed at + * elf_getscn(). And it marks the loading as a failure so + * already loaded symbols cannot be fixed up. + * + * I'm not sure what should be done. Just ignore them for now. + * - Namhyung Kim + */ + if (sym.st_shndx == SHN_ABS) + continue; sec = elf_getscn(runtime_ss->elf, sym.st_shndx); if (!sec) -- cgit v1.2.3-59-g8ed1b From 2850d9487266a55a18d340c24f5107696deeebb9 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 29 Nov 2012 14:38:40 -0300 Subject: perf hists: Fix typo on hist__entry_add_pair Fix a misplaced underscore. In this case, 'hist_entry' is the name of data structure and we usually put double underscores between data structure and actual function name. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa , Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-8jdq8g6kl6v54hkexrfwsy72@git.kernel.org [ committer note: put it in front of the patch queue where it came from ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 4 ++-- tools/perf/util/sort.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index cb17e2a8c6ed..d2bc05cd1708 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -785,7 +785,7 @@ void hists__match(struct hists *leader, struct hists *other) pair = hists__find_entry(other, pos); if (pair) - hist__entry_add_pair(pos, pair); + hist_entry__add_pair(pos, pair); } } @@ -806,7 +806,7 @@ int hists__link(struct hists *leader, struct hists *other) pair = hists__add_dummy_entry(leader, pos); if (pair == NULL) return -1; - hist__entry_add_pair(pair, pos); + hist_entry__add_pair(pair, pos); } } diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index b4e8c3ba559d..91ae2744e7d5 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -118,7 +118,7 @@ static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he) return NULL; } -static inline void hist__entry_add_pair(struct hist_entry *he, +static inline void hist_entry__add_pair(struct hist_entry *he, struct hist_entry *pair) { list_add_tail(&he->pairs.head, &pair->pairs.node); -- cgit v1.2.3-59-g8ed1b From 5fa9041bbaa7a79a67d568b9c9f947db2f23d091 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 29 Nov 2012 15:38:34 +0900 Subject: perf hists: Link hist entry pairs to leader Current hists__match/link() link a leader to its pair, so if multiple pairs were linked, the leader will lose pointer to previous pairs since it was overwritten. Fix it by making leader the list head. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1354171126-14387-8-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index d2bc05cd1708..82df1b26f0d4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -785,7 +785,7 @@ void hists__match(struct hists *leader, struct hists *other) pair = hists__find_entry(other, pos); if (pair) - hist_entry__add_pair(pos, pair); + hist_entry__add_pair(pair, pos); } } @@ -806,7 +806,7 @@ int hists__link(struct hists *leader, struct hists *other) pair = hists__add_dummy_entry(leader, pos); if (pair == NULL) return -1; - hist_entry__add_pair(pair, pos); + hist_entry__add_pair(pos, pair); } } -- cgit v1.2.3-59-g8ed1b From 2cfda562da7b0b1e0575507ef3efe782d4e218e4 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 29 Nov 2012 15:38:29 +0900 Subject: perf evsel: Set leader evsel's ->leader to itself Currently only non-leader members are set ->leader to the leader evsel of the group and the leader has set NULL. Thus it requires special casing for leader evsels. Set ->leader to itself will remove this. Suggested-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1354171126-14387-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 1 - tools/perf/util/evsel.c | 1 + tools/perf/util/evsel.h | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 705293489e3c..90db2a14e4bb 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -111,7 +111,6 @@ void __perf_evlist__set_leader(struct list_head *list) struct perf_evsel *evsel, *leader; leader = list_entry(list->next, struct perf_evsel, node); - leader->leader = NULL; list_for_each_entry(evsel, list, node) { if (evsel != leader) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 1b16dd1edc8e..7e93418a45d1 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -55,6 +55,7 @@ void perf_evsel__init(struct perf_evsel *evsel, { evsel->idx = idx; evsel->attr = *attr; + evsel->leader = evsel; INIT_LIST_HEAD(&evsel->node); hists__init(&evsel->hists); evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 3d2b8017438c..cbf6d97f0646 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -228,6 +228,6 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) static inline bool perf_evsel__is_group_member(const struct perf_evsel *evsel) { - return evsel->leader != NULL; + return evsel->leader != evsel; } #endif /* __PERF_EVSEL_H */ -- cgit v1.2.3-59-g8ed1b From 823254edc66eb44bf612b1dfa4829afa9840f691 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 29 Nov 2012 15:38:30 +0900 Subject: perf evsel: Convert to _is_group_leader method Convert perf_evsel__is_group_member to perf_evsel__is_group_leader. This is because the most usecases are using negative form to check whether the given evsel is a leader or not and it's IMHO somewhat ambiguous - leader also *is* a member of the group. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1354171126-14387-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 2 +- tools/perf/tests/parse-events.c | 20 ++++++++++---------- tools/perf/util/evlist.c | 4 ++-- tools/perf/util/evsel.c | 6 +++--- tools/perf/util/evsel.h | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index c247faca7127..c12655af2b88 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -153,7 +153,7 @@ retry: } if (!perf_target__has_task(&target) && - !perf_evsel__is_group_member(evsel)) { + perf_evsel__is_group_leader(evsel)) { attr->disabled = 1; attr->enable_on_exec = 1; } diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 32ee478905eb..294ffddfbf42 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -521,7 +521,7 @@ static int test__group1(struct perf_evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); + TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); /* cycles:upp */ evsel = perf_evsel__next(evsel); @@ -557,7 +557,7 @@ static int test__group2(struct perf_evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); + TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); /* cache-references + :u modifier */ evsel = perf_evsel__next(evsel); @@ -583,7 +583,7 @@ static int test__group2(struct perf_evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); + TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); return 0; } @@ -606,7 +606,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); + TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); TEST_ASSERT_VAL("wrong group name", !strcmp(leader->group_name, "group1")); @@ -636,7 +636,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); + TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); TEST_ASSERT_VAL("wrong group name", !strcmp(leader->group_name, "group2")); @@ -663,7 +663,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); + TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); return 0; } @@ -687,7 +687,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); + TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); /* instructions:kp + p */ evsel = perf_evsel__next(evsel); @@ -724,7 +724,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); + TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); /* instructions + G */ evsel = perf_evsel__next(evsel); @@ -751,7 +751,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); + TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); /* instructions:G */ evsel = perf_evsel__next(evsel); @@ -777,7 +777,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); + TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); return 0; } diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 90db2a14e4bb..d0e1e821fe85 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -221,7 +221,7 @@ void perf_evlist__disable(struct perf_evlist *evlist) for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { list_for_each_entry(pos, &evlist->entries, node) { - if (perf_evsel__is_group_member(pos)) + if (!perf_evsel__is_group_leader(pos)) continue; for (thread = 0; thread < evlist->threads->nr; thread++) ioctl(FD(pos, cpu, thread), @@ -237,7 +237,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { list_for_each_entry(pos, &evlist->entries, node) { - if (perf_evsel__is_group_member(pos)) + if (!perf_evsel__is_group_leader(pos)) continue; for (thread = 0; thread < evlist->threads->nr; thread++) ioctl(FD(pos, cpu, thread), diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 7e93418a45d1..bb58b05f905f 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -520,14 +520,14 @@ void perf_evsel__config(struct perf_evsel *evsel, * Disabling only independent events or group leaders, * keeping group members enabled. */ - if (!perf_evsel__is_group_member(evsel)) + if (perf_evsel__is_group_leader(evsel)) attr->disabled = 1; /* * Setting enable_on_exec for independent events and * group leaders for traced executed by perf. */ - if (perf_target__none(&opts->target) && !perf_evsel__is_group_member(evsel)) + if (perf_target__none(&opts->target) && perf_evsel__is_group_leader(evsel)) attr->enable_on_exec = 1; } @@ -708,7 +708,7 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread) struct perf_evsel *leader = evsel->leader; int fd; - if (!perf_evsel__is_group_member(evsel)) + if (perf_evsel__is_group_leader(evsel)) return -1; /* diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index cbf6d97f0646..3f7ff471de2b 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -226,8 +226,8 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) return list_entry(evsel->node.next, struct perf_evsel, node); } -static inline bool perf_evsel__is_group_member(const struct perf_evsel *evsel) +static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) { - return evsel->leader != evsel; + return evsel->leader == evsel; } #endif /* __PERF_EVSEL_H */ -- cgit v1.2.3-59-g8ed1b From fa283ada1606e687641dc2b157d66ef0f9c9aa8a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 28 Nov 2012 14:52:39 +0100 Subject: perf diff: Remove displacement from struct hist_entry_diff Removing displacement from struct hist_entry_diff, because it's not used. Displacement is not used for sorting, so there's no reason to pre-calculate it. Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1354110769-2998-5-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 91ae2744e7d5..a1c0d56b6885 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -55,9 +55,6 @@ struct he_stat { struct hist_entry_diff { bool computed; - /* PERF_HPP__DISPL */ - int displacement; - /* PERF_HPP__DELTA */ double period_ratio_delta; -- cgit v1.2.3-59-g8ed1b From 05472daa4d8ab88a071bfcaa3bb47473e4071848 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 28 Nov 2012 14:52:40 +0100 Subject: perf diff: Change compute methods to work with pair directly Changing compute methods to operate over hist entry and its pair directly. This makes the code more obvious and readable, instead of all time checking for pair being != NULL. Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1354110769-2998-6-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 38 +++++++++++++++++--------------------- tools/perf/ui/hist.c | 40 +++++++++++++++++++++++++--------------- tools/perf/util/hist.h | 7 ++++--- 3 files changed, 46 insertions(+), 39 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 9fbbc01c5ad7..342085a18076 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -146,47 +146,40 @@ static int setup_compute(const struct option *opt, const char *str, return -EINVAL; } -static double get_period_percent(struct hist_entry *he, u64 period) +double perf_diff__period_percent(struct hist_entry *he, u64 period) { u64 total = he->hists->stats.total_period; return (period * 100.0) / total; } -double perf_diff__compute_delta(struct hist_entry *he) +double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair) { - struct hist_entry *pair = hist_entry__next_pair(he); - double new_percent = get_period_percent(he, he->stat.period); - double old_percent = pair ? get_period_percent(pair, pair->stat.period) : 0.0; + double new_percent = perf_diff__period_percent(he, he->stat.period); + double old_percent = perf_diff__period_percent(pair, pair->stat.period); he->diff.period_ratio_delta = new_percent - old_percent; he->diff.computed = true; return he->diff.period_ratio_delta; } -double perf_diff__compute_ratio(struct hist_entry *he) +double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair) { - struct hist_entry *pair = hist_entry__next_pair(he); double new_period = he->stat.period; - double old_period = pair ? pair->stat.period : 0; + double old_period = pair->stat.period; he->diff.computed = true; - he->diff.period_ratio = pair ? (new_period / old_period) : 0; + he->diff.period_ratio = new_period / old_period; return he->diff.period_ratio; } -s64 perf_diff__compute_wdiff(struct hist_entry *he) +s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair) { - struct hist_entry *pair = hist_entry__next_pair(he); u64 new_period = he->stat.period; - u64 old_period = pair ? pair->stat.period : 0; + u64 old_period = pair->stat.period; he->diff.computed = true; - - if (!pair) - he->diff.wdiff = 0; - else - he->diff.wdiff = new_period * compute_wdiff_w2 - - old_period * compute_wdiff_w1; + he->diff.wdiff = new_period * compute_wdiff_w2 - + old_period * compute_wdiff_w1; return he->diff.wdiff; } @@ -385,18 +378,21 @@ static void hists__precompute(struct hists *hists) while (next != NULL) { struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); + struct hist_entry *pair = hist_entry__next_pair(he); next = rb_next(&he->rb_node); + if (!pair) + continue; switch (compute) { case COMPUTE_DELTA: - perf_diff__compute_delta(he); + perf_diff__compute_delta(he, pair); break; case COMPUTE_RATIO: - perf_diff__compute_ratio(he); + perf_diff__compute_ratio(he, pair); break; case COMPUTE_WEIGHTED_DIFF: - perf_diff__compute_wdiff(he); + perf_diff__compute_wdiff(he, pair); break; default: BUG_ON(1); diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 6e639b506829..108e5ed67621 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -268,14 +268,18 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) { + struct hist_entry *pair = hist_entry__next_pair(he); const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; char buf[32] = " "; - double diff; + double diff = 0.0; - if (he->diff.computed) - diff = he->diff.period_ratio_delta; - else - diff = perf_diff__compute_delta(he); + if (pair) { + if (he->diff.computed) + diff = he->diff.period_ratio_delta; + else + diff = perf_diff__compute_delta(he, pair); + } else + diff = perf_diff__period_percent(he, he->stat.period); if (fabs(diff) >= 0.01) scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); @@ -297,14 +301,17 @@ static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused) static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) { + struct hist_entry *pair = hist_entry__next_pair(he); const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; char buf[32] = " "; - double ratio; + double ratio = 0.0; - if (he->diff.computed) - ratio = he->diff.period_ratio; - else - ratio = perf_diff__compute_ratio(he); + if (pair) { + if (he->diff.computed) + ratio = he->diff.period_ratio; + else + ratio = perf_diff__compute_ratio(he, pair); + } if (ratio > 0.0) scnprintf(buf, sizeof(buf), "%+14.6F", ratio); @@ -326,14 +333,17 @@ static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused) static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) { + struct hist_entry *pair = hist_entry__next_pair(he); const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; char buf[32] = " "; - s64 wdiff; + s64 wdiff = 0; - if (he->diff.computed) - wdiff = he->diff.wdiff; - else - wdiff = perf_diff__compute_wdiff(he); + if (pair) { + if (he->diff.computed) + wdiff = he->diff.wdiff; + else + wdiff = perf_diff__compute_wdiff(he, pair); + } if (wdiff != 0) scnprintf(buf, sizeof(buf), "%14ld", wdiff); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index a935a60d521c..235503aac08c 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -226,8 +226,9 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, unsigned int hists__sort_list_width(struct hists *self); -double perf_diff__compute_delta(struct hist_entry *he); -double perf_diff__compute_ratio(struct hist_entry *he); -s64 perf_diff__compute_wdiff(struct hist_entry *he); +double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair); +double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair); +s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair); int perf_diff__formula(char *buf, size_t size, struct hist_entry *he); +double perf_diff__period_percent(struct hist_entry *he, u64 period); #endif /* __PERF_HIST_H */ -- cgit v1.2.3-59-g8ed1b From f4c8bae1920c459b7b9c12363d11e8a588862e42 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 28 Nov 2012 14:52:41 +0100 Subject: perf diff: Change formula methods to work with pair directly Changing formula methods to operate over hist entry and its pair directly. This makes the code more obvious and readable, instead of all time checking for pair being != NULL. Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1354110769-2998-7-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 35 +++++++++++++---------------------- tools/perf/ui/hist.c | 5 ++++- tools/perf/util/hist.h | 3 ++- 3 files changed, 19 insertions(+), 24 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 342085a18076..d869029fb75e 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -184,13 +184,9 @@ s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair) return he->diff.wdiff; } -static int formula_delta(struct hist_entry *he, char *buf, size_t size) +static int formula_delta(struct hist_entry *he, struct hist_entry *pair, + char *buf, size_t size) { - struct hist_entry *pair = hist_entry__next_pair(he); - - if (!pair) - return -1; - return scnprintf(buf, size, "(%" PRIu64 " * 100 / %" PRIu64 ") - " "(%" PRIu64 " * 100 / %" PRIu64 ")", @@ -198,41 +194,36 @@ static int formula_delta(struct hist_entry *he, char *buf, size_t size) pair->stat.period, pair->hists->stats.total_period); } -static int formula_ratio(struct hist_entry *he, char *buf, size_t size) +static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, + char *buf, size_t size) { - struct hist_entry *pair = hist_entry__next_pair(he); double new_period = he->stat.period; - double old_period = pair ? pair->stat.period : 0; - - if (!pair) - return -1; + double old_period = pair->stat.period; return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); } -static int formula_wdiff(struct hist_entry *he, char *buf, size_t size) +static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair, + char *buf, size_t size) { - struct hist_entry *pair = hist_entry__next_pair(he); u64 new_period = he->stat.period; - u64 old_period = pair ? pair->stat.period : 0; - - if (!pair) - return -1; + u64 old_period = pair->stat.period; return scnprintf(buf, size, "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); } -int perf_diff__formula(char *buf, size_t size, struct hist_entry *he) +int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair, + char *buf, size_t size) { switch (compute) { case COMPUTE_DELTA: - return formula_delta(he, buf, size); + return formula_delta(he, pair, buf, size); case COMPUTE_RATIO: - return formula_ratio(he, buf, size); + return formula_ratio(he, pair, buf, size); case COMPUTE_WEIGHTED_DIFF: - return formula_wdiff(he, buf, size); + return formula_wdiff(he, pair, buf, size); default: BUG_ON(1); } diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 108e5ed67621..1785bab7adfd 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -389,10 +389,13 @@ static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused) static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) { + struct hist_entry *pair = hist_entry__next_pair(he); const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; char buf[96] = " "; - perf_diff__formula(buf, sizeof(buf), he); + if (pair) + perf_diff__formula(he, pair, buf, sizeof(buf)); + return scnprintf(hpp->buf, hpp->size, fmt, buf); } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 235503aac08c..c1b2fade8e70 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -229,6 +229,7 @@ unsigned int hists__sort_list_width(struct hists *self); double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair); double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair); s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair); -int perf_diff__formula(char *buf, size_t size, struct hist_entry *he); +int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair, + char *buf, size_t size); double perf_diff__period_percent(struct hist_entry *he, u64 period); #endif /* __PERF_HIST_H */ -- cgit v1.2.3-59-g8ed1b From 044c4f8fbab513af399ff8ce7a2af2d303d85849 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 29 Nov 2012 16:51:01 -0300 Subject: perf tools: Fix TUI helpline output In commit e2f4351 "perf ui/helpline: Introduce ui_helpline__vshow()" the test for the browser used made ui_helpline__vshow() to be called only for the GTK browser. The TUI one then was not used and vfprintf(stderr, ...) was used instead, making the TUI scroll the screen instead of just printing on the last line. Fix it by doing the proper check, that is to call ui_helpline__vshow to be called for both the TUI and GTK browsers. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-iad0nw09x4orhmn0uzz4ljx3@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 391c9a9e946f..399e74c34c1a 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -23,7 +23,7 @@ int eprintf(int level, const char *fmt, ...) if (verbose >= level) { va_start(args, fmt); - if (use_browser > 1) + if (use_browser >= 1) ui_helpline__vshow(fmt, args); else ret = vfprintf(stderr, fmt, args); -- cgit v1.2.3-59-g8ed1b From db6d0bb86164497f6c9ef46020cf1881953f4b08 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 6 Dec 2012 14:22:28 +0100 Subject: perf diff: Remove displacement output option It seems not very useful, because it's possible and event more convenient to lookup related symbol by name. Also the output value for both 'baseline' and 'new' data is quite apparent from diff output. And above all it complicates hist code factoring ;) Ditching out PERF_HPP__DISPL column with related output functions. Suggested-by: Arnaldo Carvalho de Melo Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Ingo Molnar Cc: Namhyung Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/20121206132228.GB1080@krava.brq.redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-diff.txt | 4 ---- tools/perf/builtin-diff.c | 29 +++++++---------------------- tools/perf/ui/hist.c | 25 ------------------------- tools/perf/util/hist.h | 1 - 4 files changed, 7 insertions(+), 52 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 194f37d635df..5b3123d5721f 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt @@ -22,10 +22,6 @@ specified perf.data files. OPTIONS ------- --M:: ---displacement:: - Show position displacement relative to baseline. - -D:: --dump-raw-trace:: Dump raw trace in ASCII. diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index d869029fb75e..b2e7d39f099b 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -23,7 +23,6 @@ static char const *input_old = "perf.data.old", *input_new = "perf.data"; static char diff__default_sort_order[] = "dso,symbol"; static bool force; -static bool show_displacement; static bool show_period; static bool show_formula; static bool show_baseline_only; @@ -296,9 +295,8 @@ static void insert_hist_entry_by_name(struct rb_root *root, rb_insert_color(&he->rb_node, root); } -static void hists__name_resort(struct hists *self, bool sort) +static void hists__name_resort(struct hists *self) { - unsigned long position = 1; struct rb_root tmp = RB_ROOT; struct rb_node *next = rb_first(&self->entries); @@ -306,16 +304,12 @@ static void hists__name_resort(struct hists *self, bool sort) struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); next = rb_next(&n->rb_node); - n->position = position++; - if (sort) { - rb_erase(&n->rb_node, &self->entries); - insert_hist_entry_by_name(&tmp, n); - } + rb_erase(&n->rb_node, &self->entries); + insert_hist_entry_by_name(&tmp, n); } - if (sort) - self->entries = tmp; + self->entries = tmp; } static struct perf_evsel *evsel_match(struct perf_evsel *evsel, @@ -339,12 +333,8 @@ static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) hists__output_resort(hists); - /* - * The hists__name_resort only sets possition - * if name is false. - */ - if (name || ((!name) && show_displacement)) - hists__name_resort(hists, name); + if (name) + hists__name_resort(hists); } } @@ -549,8 +539,6 @@ static const char * const diff_usage[] = { static const struct option options[] = { OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), - OPT_BOOLEAN('M', "displacement", &show_displacement, - "Show position displacement relative to baseline"), OPT_BOOLEAN('b', "baseline-only", &show_baseline_only, "Show only items with match in baseline"), OPT_CALLBACK('c', "compute", &compute, @@ -585,7 +573,7 @@ static const struct option options[] = { static void ui_init(void) { /* - * Display baseline/delta/ratio/displacement/ + * Display baseline/delta/ratio * formula/periods columns. */ perf_hpp__column_enable(PERF_HPP__BASELINE); @@ -604,9 +592,6 @@ static void ui_init(void) BUG_ON(1); }; - if (show_displacement) - perf_hpp__column_enable(PERF_HPP__DISPL); - if (show_formula) perf_hpp__column_enable(PERF_HPP__FORMULA); diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 1785bab7adfd..1889c12ca81f 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -351,30 +351,6 @@ static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) return scnprintf(hpp->buf, hpp->size, fmt, buf); } -static int hpp__header_displ(struct perf_hpp *hpp) -{ - return scnprintf(hpp->buf, hpp->size, "Displ."); -} - -static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused) -{ - return 6; -} - -static int hpp__entry_displ(struct perf_hpp *hpp, - struct hist_entry *he) -{ - struct hist_entry *pair = hist_entry__next_pair(he); - long displacement = pair ? pair->position - he->position : 0; - const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s"; - char buf[32] = " "; - - if (displacement) - scnprintf(buf, sizeof(buf), "%+4ld", displacement); - - return scnprintf(hpp->buf, hpp->size, fmt, buf); -} - static int hpp__header_formula(struct perf_hpp *hpp) { const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; @@ -427,7 +403,6 @@ struct perf_hpp_fmt perf_hpp__format[] = { HPP__PRINT_FNS(delta), HPP__PRINT_FNS(ratio), HPP__PRINT_FNS(wdiff), - HPP__PRINT_FNS(displ), HPP__PRINT_FNS(formula) }; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index c1b2fade8e70..5b3b0075be64 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -154,7 +154,6 @@ enum { PERF_HPP__DELTA, PERF_HPP__RATIO, PERF_HPP__WEIGHTED_DIFF, - PERF_HPP__DISPL, PERF_HPP__FORMULA, PERF_HPP__MAX_INDEX -- cgit v1.2.3-59-g8ed1b From 417c2ff6806fd9183cb36682dcf32c4d068aba5e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 7 Dec 2012 09:53:58 -0300 Subject: perf symbols: Generalize filter in __fprintf_buildid methods We had that 'with_hits' filter to show just the build ids for DSOs that had samples, make that generic so that we can use it in the upcoming buildid-cache --missing feature, to show just the build ids that are not in the cache. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-9nfesdfpnx7zp96yn3tmfbx0@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-buildid-list.c | 7 ++++++- tools/perf/util/dso.c | 4 ++-- tools/perf/util/dso.h | 2 +- tools/perf/util/machine.h | 8 ++++---- tools/perf/util/session.c | 6 +++--- tools/perf/util/session.h | 4 ++-- tools/perf/util/symbol.c | 12 ++++++------ 7 files changed, 24 insertions(+), 19 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 4c770d252fd2..e74366a13218 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -44,6 +44,11 @@ static int filename__fprintf_build_id(const char *name, FILE *fp) return fprintf(fp, "%s\n", sbuild_id); } +static bool dso__skip_buildid(struct dso *dso, int with_hits) +{ + return with_hits && !dso->hit; +} + static int perf_session__list_build_ids(bool force, bool with_hits) { struct perf_session *session; @@ -66,7 +71,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits) if (with_hits || session->fd_pipe) perf_session__process_events(session, &build_id__mark_dso_hit_ops); - perf_session__fprintf_dsos_buildid(session, stdout, with_hits); + perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits); perf_session__delete(session); out: return 0; diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index be437850edc8..6f7d5a9d6b05 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -539,13 +539,13 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name) } size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, - bool with_hits) + bool (skip)(struct dso *dso, int parm), int parm) { struct dso *pos; size_t ret = 0; list_for_each_entry(pos, head, node) { - if (with_hits && !pos->hit) + if (skip && skip(pos, parm)) continue; ret += dso__fprintf_buildid(pos, fp); ret += fprintf(fp, " %s\n", pos->long_name); diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index e03276940b99..450199ab51b5 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -138,7 +138,7 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name); bool __dsos__read_build_ids(struct list_head *head, bool with_hits); size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, - bool with_hits); + bool (skip)(struct dso *dso, int parm), int parm); size_t __dsos__fprintf(struct list_head *head, FILE *fp); size_t dso__fprintf_buildid(struct dso *dso, FILE *fp); diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index b7cde7467d55..646ad13005d3 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -129,11 +129,11 @@ int machine__load_kallsyms(struct machine *machine, const char *filename, int machine__load_vmlinux_path(struct machine *machine, enum map_type type, symbol_filter_t filter); -size_t machine__fprintf_dsos_buildid(struct machine *machine, - FILE *fp, bool with_hits); +size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, + bool (skip)(struct dso *dso, int parm), int parm); size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); -size_t machines__fprintf_dsos_buildid(struct rb_root *machines, - FILE *fp, bool with_hits); +size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, + bool (skip)(struct dso *dso, int parm), int parm); void machine__destroy_kernel_maps(struct machine *machine); int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index aa5e58255cba..8d04dfbc205c 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1552,10 +1552,10 @@ size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) } size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, - bool with_hits) + bool (skip)(struct dso *dso, int parm), int parm) { - size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); - return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); + size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, skip, parm); + return ret + machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm); } size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index c18fabdff19b..8c2302504199 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -115,8 +115,8 @@ size_t perf_session__fprintf(struct perf_session *self, FILE *fp); size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); -size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, - FILE *fp, bool with_hits); +size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp, + bool (fn)(struct dso *dso, int parm), int parm); size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 295f8d4feedf..e5ba9840ac22 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1315,21 +1315,21 @@ size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) } size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, - bool with_hits) + bool (skip)(struct dso *dso, int parm), int parm) { - return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) + - __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits); + return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) + + __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm); } -size_t machines__fprintf_dsos_buildid(struct rb_root *machines, - FILE *fp, bool with_hits) +size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, + bool (skip)(struct dso *dso, int parm), int parm) { struct rb_node *nd; size_t ret = 0; for (nd = rb_first(machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); - ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); + ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); } return ret; } -- cgit v1.2.3-59-g8ed1b From 3f067dcab711c2df7eefcfc5b3aa9a0e2b5f7d42 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 7 Dec 2012 17:39:39 -0300 Subject: perf machine: Move more machine methods to machine.c Mechanical, no functional changes. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-9ib6qtqge1jmms2luwu4udbx@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 742 ++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/machine.h | 3 +- tools/perf/util/session.c | 210 ------------- tools/perf/util/symbol.c | 522 +------------------------------- tools/perf/util/symbol.h | 4 + tools/perf/util/thread.c | 20 +- tools/perf/util/thread.h | 1 + 7 files changed, 756 insertions(+), 746 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 1f09d0581e6b..71fa90391fe4 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1,10 +1,15 @@ +#include "callchain.h" #include "debug.h" #include "event.h" +#include "evsel.h" +#include "hist.h" #include "machine.h" #include "map.h" +#include "sort.h" #include "strlist.h" #include "thread.h" #include +#include "unwind.h" int machine__init(struct machine *machine, const char *root_dir, pid_t pid) { @@ -48,6 +53,29 @@ static void dsos__delete(struct list_head *dsos) } } +void machine__delete_dead_threads(struct machine *machine) +{ + struct thread *n, *t; + + list_for_each_entry_safe(t, n, &machine->dead_threads, node) { + list_del(&t->node); + thread__delete(t); + } +} + +void machine__delete_threads(struct machine *machine) +{ + struct rb_node *nd = rb_first(&machine->threads); + + while (nd) { + struct thread *t = rb_entry(nd, struct thread, rb_node); + + rb_erase(&t->rb_node, &machine->threads); + nd = rb_next(nd); + thread__delete(t); + } +} + void machine__exit(struct machine *machine) { map_groups__exit(&machine->kmaps); @@ -264,6 +292,534 @@ int machine__process_lost_event(struct machine *machine __maybe_unused, return 0; } +struct map *machine__new_module(struct machine *machine, u64 start, + const char *filename) +{ + struct map *map; + struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); + + if (dso == NULL) + return NULL; + + map = map__new2(start, dso, MAP__FUNCTION); + if (map == NULL) + return NULL; + + if (machine__is_host(machine)) + dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; + else + dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; + map_groups__insert(&machine->kmaps, map); + return map; +} + +size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) +{ + struct rb_node *nd; + size_t ret = 0; + + for (nd = rb_first(machines); nd; nd = rb_next(nd)) { + struct machine *pos = rb_entry(nd, struct machine, rb_node); + ret += __dsos__fprintf(&pos->kernel_dsos, fp); + ret += __dsos__fprintf(&pos->user_dsos, fp); + } + + return ret; +} + +size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, + bool (skip)(struct dso *dso, int parm), int parm) +{ + return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) + + __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm); +} + +size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, + bool (skip)(struct dso *dso, int parm), int parm) +{ + struct rb_node *nd; + size_t ret = 0; + + for (nd = rb_first(machines); nd; nd = rb_next(nd)) { + struct machine *pos = rb_entry(nd, struct machine, rb_node); + ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); + } + return ret; +} + +size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) +{ + int i; + size_t printed = 0; + struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; + + if (kdso->has_build_id) { + char filename[PATH_MAX]; + if (dso__build_id_filename(kdso, filename, sizeof(filename))) + printed += fprintf(fp, "[0] %s\n", filename); + } + + for (i = 0; i < vmlinux_path__nr_entries; ++i) + printed += fprintf(fp, "[%d] %s\n", + i + kdso->has_build_id, vmlinux_path[i]); + + return printed; +} + +size_t machine__fprintf(struct machine *machine, FILE *fp) +{ + size_t ret = 0; + struct rb_node *nd; + + for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { + struct thread *pos = rb_entry(nd, struct thread, rb_node); + + ret += thread__fprintf(pos, fp); + } + + return ret; +} + +static struct dso *machine__get_kernel(struct machine *machine) +{ + const char *vmlinux_name = NULL; + struct dso *kernel; + + if (machine__is_host(machine)) { + vmlinux_name = symbol_conf.vmlinux_name; + if (!vmlinux_name) + vmlinux_name = "[kernel.kallsyms]"; + + kernel = dso__kernel_findnew(machine, vmlinux_name, + "[kernel]", + DSO_TYPE_KERNEL); + } else { + char bf[PATH_MAX]; + + if (machine__is_default_guest(machine)) + vmlinux_name = symbol_conf.default_guest_vmlinux_name; + if (!vmlinux_name) + vmlinux_name = machine__mmap_name(machine, bf, + sizeof(bf)); + + kernel = dso__kernel_findnew(machine, vmlinux_name, + "[guest.kernel]", + DSO_TYPE_GUEST_KERNEL); + } + + if (kernel != NULL && (!kernel->has_build_id)) + dso__read_running_kernel_build_id(kernel, machine); + + return kernel; +} + +struct process_args { + u64 start; +}; + +static int symbol__in_kernel(void *arg, const char *name, + char type __maybe_unused, u64 start) +{ + struct process_args *args = arg; + + if (strchr(name, '[')) + return 0; + + args->start = start; + return 1; +} + +/* Figure out the start address of kernel map from /proc/kallsyms */ +static u64 machine__get_kernel_start_addr(struct machine *machine) +{ + const char *filename; + char path[PATH_MAX]; + struct process_args args; + + if (machine__is_host(machine)) { + filename = "/proc/kallsyms"; + } else { + if (machine__is_default_guest(machine)) + filename = (char *)symbol_conf.default_guest_kallsyms; + else { + sprintf(path, "%s/proc/kallsyms", machine->root_dir); + filename = path; + } + } + + if (symbol__restricted_filename(filename, "/proc/kallsyms")) + return 0; + + if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) + return 0; + + return args.start; +} + +int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) +{ + enum map_type type; + u64 start = machine__get_kernel_start_addr(machine); + + for (type = 0; type < MAP__NR_TYPES; ++type) { + struct kmap *kmap; + + machine->vmlinux_maps[type] = map__new2(start, kernel, type); + if (machine->vmlinux_maps[type] == NULL) + return -1; + + machine->vmlinux_maps[type]->map_ip = + machine->vmlinux_maps[type]->unmap_ip = + identity__map_ip; + kmap = map__kmap(machine->vmlinux_maps[type]); + kmap->kmaps = &machine->kmaps; + map_groups__insert(&machine->kmaps, + machine->vmlinux_maps[type]); + } + + return 0; +} + +void machine__destroy_kernel_maps(struct machine *machine) +{ + enum map_type type; + + for (type = 0; type < MAP__NR_TYPES; ++type) { + struct kmap *kmap; + + if (machine->vmlinux_maps[type] == NULL) + continue; + + kmap = map__kmap(machine->vmlinux_maps[type]); + map_groups__remove(&machine->kmaps, + machine->vmlinux_maps[type]); + if (kmap->ref_reloc_sym) { + /* + * ref_reloc_sym is shared among all maps, so free just + * on one of them. + */ + if (type == MAP__FUNCTION) { + free((char *)kmap->ref_reloc_sym->name); + kmap->ref_reloc_sym->name = NULL; + free(kmap->ref_reloc_sym); + } + kmap->ref_reloc_sym = NULL; + } + + map__delete(machine->vmlinux_maps[type]); + machine->vmlinux_maps[type] = NULL; + } +} + +int machines__create_guest_kernel_maps(struct rb_root *machines) +{ + int ret = 0; + struct dirent **namelist = NULL; + int i, items = 0; + char path[PATH_MAX]; + pid_t pid; + char *endp; + + if (symbol_conf.default_guest_vmlinux_name || + symbol_conf.default_guest_modules || + symbol_conf.default_guest_kallsyms) { + machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); + } + + if (symbol_conf.guestmount) { + items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); + if (items <= 0) + return -ENOENT; + for (i = 0; i < items; i++) { + if (!isdigit(namelist[i]->d_name[0])) { + /* Filter out . and .. */ + continue; + } + pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10); + if ((*endp != '\0') || + (endp == namelist[i]->d_name) || + (errno == ERANGE)) { + pr_debug("invalid directory (%s). Skipping.\n", + namelist[i]->d_name); + continue; + } + sprintf(path, "%s/%s/proc/kallsyms", + symbol_conf.guestmount, + namelist[i]->d_name); + ret = access(path, R_OK); + if (ret) { + pr_debug("Can't access file %s\n", path); + goto failure; + } + machines__create_kernel_maps(machines, pid); + } +failure: + free(namelist); + } + + return ret; +} + +void machines__destroy_guest_kernel_maps(struct rb_root *machines) +{ + struct rb_node *next = rb_first(machines); + + while (next) { + struct machine *pos = rb_entry(next, struct machine, rb_node); + + next = rb_next(&pos->rb_node); + rb_erase(&pos->rb_node, machines); + machine__delete(pos); + } +} + +int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) +{ + struct machine *machine = machines__findnew(machines, pid); + + if (machine == NULL) + return -1; + + return machine__create_kernel_maps(machine); +} + +int machine__load_kallsyms(struct machine *machine, const char *filename, + enum map_type type, symbol_filter_t filter) +{ + struct map *map = machine->vmlinux_maps[type]; + int ret = dso__load_kallsyms(map->dso, filename, map, filter); + + if (ret > 0) { + dso__set_loaded(map->dso, type); + /* + * Since /proc/kallsyms will have multiple sessions for the + * kernel, with modules between them, fixup the end of all + * sections. + */ + __map_groups__fixup_end(&machine->kmaps, type); + } + + return ret; +} + +int machine__load_vmlinux_path(struct machine *machine, enum map_type type, + symbol_filter_t filter) +{ + struct map *map = machine->vmlinux_maps[type]; + int ret = dso__load_vmlinux_path(map->dso, map, filter); + + if (ret > 0) { + dso__set_loaded(map->dso, type); + map__reloc_vmlinux(map); + } + + return ret; +} + +static void map_groups__fixup_end(struct map_groups *mg) +{ + int i; + for (i = 0; i < MAP__NR_TYPES; ++i) + __map_groups__fixup_end(mg, i); +} + +static char *get_kernel_version(const char *root_dir) +{ + char version[PATH_MAX]; + FILE *file; + char *name, *tmp; + const char *prefix = "Linux version "; + + sprintf(version, "%s/proc/version", root_dir); + file = fopen(version, "r"); + if (!file) + return NULL; + + version[0] = '\0'; + tmp = fgets(version, sizeof(version), file); + fclose(file); + + name = strstr(version, prefix); + if (!name) + return NULL; + name += strlen(prefix); + tmp = strchr(name, ' '); + if (tmp) + *tmp = '\0'; + + return strdup(name); +} + +static int map_groups__set_modules_path_dir(struct map_groups *mg, + const char *dir_name) +{ + struct dirent *dent; + DIR *dir = opendir(dir_name); + int ret = 0; + + if (!dir) { + pr_debug("%s: cannot open %s dir\n", __func__, dir_name); + return -1; + } + + while ((dent = readdir(dir)) != NULL) { + char path[PATH_MAX]; + struct stat st; + + /*sshfs might return bad dent->d_type, so we have to stat*/ + snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); + if (stat(path, &st)) + continue; + + if (S_ISDIR(st.st_mode)) { + if (!strcmp(dent->d_name, ".") || + !strcmp(dent->d_name, "..")) + continue; + + ret = map_groups__set_modules_path_dir(mg, path); + if (ret < 0) + goto out; + } else { + char *dot = strrchr(dent->d_name, '.'), + dso_name[PATH_MAX]; + struct map *map; + char *long_name; + + if (dot == NULL || strcmp(dot, ".ko")) + continue; + snprintf(dso_name, sizeof(dso_name), "[%.*s]", + (int)(dot - dent->d_name), dent->d_name); + + strxfrchar(dso_name, '-', '_'); + map = map_groups__find_by_name(mg, MAP__FUNCTION, + dso_name); + if (map == NULL) + continue; + + long_name = strdup(path); + if (long_name == NULL) { + ret = -1; + goto out; + } + dso__set_long_name(map->dso, long_name); + map->dso->lname_alloc = 1; + dso__kernel_module_get_build_id(map->dso, ""); + } + } + +out: + closedir(dir); + return ret; +} + +static int machine__set_modules_path(struct machine *machine) +{ + char *version; + char modules_path[PATH_MAX]; + + version = get_kernel_version(machine->root_dir); + if (!version) + return -1; + + snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", + machine->root_dir, version); + free(version); + + return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); +} + +static int machine__create_modules(struct machine *machine) +{ + char *line = NULL; + size_t n; + FILE *file; + struct map *map; + const char *modules; + char path[PATH_MAX]; + + if (machine__is_default_guest(machine)) + modules = symbol_conf.default_guest_modules; + else { + sprintf(path, "%s/proc/modules", machine->root_dir); + modules = path; + } + + if (symbol__restricted_filename(path, "/proc/modules")) + return -1; + + file = fopen(modules, "r"); + if (file == NULL) + return -1; + + while (!feof(file)) { + char name[PATH_MAX]; + u64 start; + char *sep; + int line_len; + + line_len = getline(&line, &n, file); + if (line_len < 0) + break; + + if (!line) + goto out_failure; + + line[--line_len] = '\0'; /* \n */ + + sep = strrchr(line, 'x'); + if (sep == NULL) + continue; + + hex2u64(sep + 1, &start); + + sep = strchr(line, ' '); + if (sep == NULL) + continue; + + *sep = '\0'; + + snprintf(name, sizeof(name), "[%s]", line); + map = machine__new_module(machine, start, name); + if (map == NULL) + goto out_delete_line; + dso__kernel_module_get_build_id(map->dso, machine->root_dir); + } + + free(line); + fclose(file); + + return machine__set_modules_path(machine); + +out_delete_line: + free(line); +out_failure: + return -1; +} + +int machine__create_kernel_maps(struct machine *machine) +{ + struct dso *kernel = machine__get_kernel(machine); + + if (kernel == NULL || + __machine__create_kernel_maps(machine, kernel) < 0) + return -1; + + if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { + if (machine__is_host(machine)) + pr_debug("Problems creating module maps, " + "continuing anyway...\n"); + else + pr_debug("Problems creating module maps for guest %d, " + "continuing anyway...\n", machine->pid); + } + + /* + * Now that we have all the maps created, just set the ->end of them: + */ + map_groups__fixup_end(&machine->kmaps); + return 0; +} + static void machine__set_kernel_mmap_len(struct machine *machine, union perf_event *event) { @@ -462,3 +1018,189 @@ int machine__process_event(struct machine *machine, union perf_event *event) return ret; } + +void machine__remove_thread(struct machine *machine, struct thread *th) +{ + machine->last_match = NULL; + rb_erase(&th->rb_node, &machine->threads); + /* + * We may have references to this thread, for instance in some hist_entry + * instances, so just move them to a separate list. + */ + list_add_tail(&th->node, &machine->dead_threads); +} + +static bool symbol__match_parent_regex(struct symbol *sym) +{ + if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) + return 1; + + return 0; +} + +static const u8 cpumodes[] = { + PERF_RECORD_MISC_USER, + PERF_RECORD_MISC_KERNEL, + PERF_RECORD_MISC_GUEST_USER, + PERF_RECORD_MISC_GUEST_KERNEL +}; +#define NCPUMODES (sizeof(cpumodes)/sizeof(u8)) + +static void ip__resolve_ams(struct machine *machine, struct thread *thread, + struct addr_map_symbol *ams, + u64 ip) +{ + struct addr_location al; + size_t i; + u8 m; + + memset(&al, 0, sizeof(al)); + + for (i = 0; i < NCPUMODES; i++) { + m = cpumodes[i]; + /* + * We cannot use the header.misc hint to determine whether a + * branch stack address is user, kernel, guest, hypervisor. + * Branches may straddle the kernel/user/hypervisor boundaries. + * Thus, we have to try consecutively until we find a match + * or else, the symbol is unknown + */ + thread__find_addr_location(thread, machine, m, MAP__FUNCTION, + ip, &al, NULL); + if (al.sym) + goto found; + } +found: + ams->addr = ip; + ams->al_addr = al.addr; + ams->sym = al.sym; + ams->map = al.map; +} + +struct branch_info *machine__resolve_bstack(struct machine *machine, + struct thread *thr, + struct branch_stack *bs) +{ + struct branch_info *bi; + unsigned int i; + + bi = calloc(bs->nr, sizeof(struct branch_info)); + if (!bi) + return NULL; + + for (i = 0; i < bs->nr; i++) { + ip__resolve_ams(machine, thr, &bi[i].to, bs->entries[i].to); + ip__resolve_ams(machine, thr, &bi[i].from, bs->entries[i].from); + bi[i].flags = bs->entries[i].flags; + } + return bi; +} + +static int machine__resolve_callchain_sample(struct machine *machine, + struct thread *thread, + struct ip_callchain *chain, + struct symbol **parent) + +{ + u8 cpumode = PERF_RECORD_MISC_USER; + unsigned int i; + int err; + + callchain_cursor_reset(&callchain_cursor); + + if (chain->nr > PERF_MAX_STACK_DEPTH) { + pr_warning("corrupted callchain. skipping...\n"); + return 0; + } + + for (i = 0; i < chain->nr; i++) { + u64 ip; + struct addr_location al; + + if (callchain_param.order == ORDER_CALLEE) + ip = chain->ips[i]; + else + ip = chain->ips[chain->nr - i - 1]; + + if (ip >= PERF_CONTEXT_MAX) { + switch (ip) { + case PERF_CONTEXT_HV: + cpumode = PERF_RECORD_MISC_HYPERVISOR; + break; + case PERF_CONTEXT_KERNEL: + cpumode = PERF_RECORD_MISC_KERNEL; + break; + case PERF_CONTEXT_USER: + cpumode = PERF_RECORD_MISC_USER; + break; + default: + pr_debug("invalid callchain context: " + "%"PRId64"\n", (s64) ip); + /* + * It seems the callchain is corrupted. + * Discard all. + */ + callchain_cursor_reset(&callchain_cursor); + return 0; + } + continue; + } + + al.filtered = false; + thread__find_addr_location(thread, machine, cpumode, + MAP__FUNCTION, ip, &al, NULL); + if (al.sym != NULL) { + if (sort__has_parent && !*parent && + symbol__match_parent_regex(al.sym)) + *parent = al.sym; + if (!symbol_conf.use_callchain) + break; + } + + err = callchain_cursor_append(&callchain_cursor, + ip, al.map, al.sym); + if (err) + return err; + } + + return 0; +} + +static int unwind_entry(struct unwind_entry *entry, void *arg) +{ + struct callchain_cursor *cursor = arg; + return callchain_cursor_append(cursor, entry->ip, + entry->map, entry->sym); +} + +int machine__resolve_callchain(struct machine *machine, + struct perf_evsel *evsel, + struct thread *thread, + struct perf_sample *sample, + struct symbol **parent) + +{ + int ret; + + callchain_cursor_reset(&callchain_cursor); + + ret = machine__resolve_callchain_sample(machine, thread, + sample->callchain, parent); + if (ret) + return ret; + + /* Can we do dwarf post unwind? */ + if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && + (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) + return 0; + + /* Bail out if nothing was captured. */ + if ((!sample->user_regs.regs) || + (!sample->user_stack.size)) + return 0; + + return unwind__get_entries(unwind_entry, &callchain_cursor, machine, + thread, evsel->attr.sample_regs_user, + sample); + +} diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 646ad13005d3..e11236878ec1 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -61,9 +61,10 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size); int machine__init(struct machine *machine, const char *root_dir, pid_t pid); void machine__exit(struct machine *machine); +void machine__delete_dead_threads(struct machine *machine); +void machine__delete_threads(struct machine *machine); void machine__delete(struct machine *machine); - struct branch_info *machine__resolve_bstack(struct machine *machine, struct thread *thread, struct branch_stack *bs); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 8d04dfbc205c..76d6e257b8a4 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -16,7 +16,6 @@ #include "cpumap.h" #include "event-parse.h" #include "perf_regs.h" -#include "unwind.h" #include "vdso.h" static int perf_session__open(struct perf_session *self, bool force) @@ -162,34 +161,11 @@ out_delete: return NULL; } -static void machine__delete_dead_threads(struct machine *machine) -{ - struct thread *n, *t; - - list_for_each_entry_safe(t, n, &machine->dead_threads, node) { - list_del(&t->node); - thread__delete(t); - } -} - static void perf_session__delete_dead_threads(struct perf_session *session) { machine__delete_dead_threads(&session->host_machine); } -static void machine__delete_threads(struct machine *self) -{ - struct rb_node *nd = rb_first(&self->threads); - - while (nd) { - struct thread *t = rb_entry(nd, struct thread, rb_node); - - rb_erase(&t->rb_node, &self->threads); - nd = rb_next(nd); - thread__delete(t); - } -} - static void perf_session__delete_threads(struct perf_session *session) { machine__delete_threads(&session->host_machine); @@ -223,192 +199,6 @@ void perf_session__delete(struct perf_session *self) vdso__exit(); } -void machine__remove_thread(struct machine *self, struct thread *th) -{ - self->last_match = NULL; - rb_erase(&th->rb_node, &self->threads); - /* - * We may have references to this thread, for instance in some hist_entry - * instances, so just move them to a separate list. - */ - list_add_tail(&th->node, &self->dead_threads); -} - -static bool symbol__match_parent_regex(struct symbol *sym) -{ - if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) - return 1; - - return 0; -} - -static const u8 cpumodes[] = { - PERF_RECORD_MISC_USER, - PERF_RECORD_MISC_KERNEL, - PERF_RECORD_MISC_GUEST_USER, - PERF_RECORD_MISC_GUEST_KERNEL -}; -#define NCPUMODES (sizeof(cpumodes)/sizeof(u8)) - -static void ip__resolve_ams(struct machine *self, struct thread *thread, - struct addr_map_symbol *ams, - u64 ip) -{ - struct addr_location al; - size_t i; - u8 m; - - memset(&al, 0, sizeof(al)); - - for (i = 0; i < NCPUMODES; i++) { - m = cpumodes[i]; - /* - * We cannot use the header.misc hint to determine whether a - * branch stack address is user, kernel, guest, hypervisor. - * Branches may straddle the kernel/user/hypervisor boundaries. - * Thus, we have to try consecutively until we find a match - * or else, the symbol is unknown - */ - thread__find_addr_location(thread, self, m, MAP__FUNCTION, - ip, &al, NULL); - if (al.sym) - goto found; - } -found: - ams->addr = ip; - ams->al_addr = al.addr; - ams->sym = al.sym; - ams->map = al.map; -} - -struct branch_info *machine__resolve_bstack(struct machine *self, - struct thread *thr, - struct branch_stack *bs) -{ - struct branch_info *bi; - unsigned int i; - - bi = calloc(bs->nr, sizeof(struct branch_info)); - if (!bi) - return NULL; - - for (i = 0; i < bs->nr; i++) { - ip__resolve_ams(self, thr, &bi[i].to, bs->entries[i].to); - ip__resolve_ams(self, thr, &bi[i].from, bs->entries[i].from); - bi[i].flags = bs->entries[i].flags; - } - return bi; -} - -static int machine__resolve_callchain_sample(struct machine *machine, - struct thread *thread, - struct ip_callchain *chain, - struct symbol **parent) - -{ - u8 cpumode = PERF_RECORD_MISC_USER; - unsigned int i; - int err; - - callchain_cursor_reset(&callchain_cursor); - - if (chain->nr > PERF_MAX_STACK_DEPTH) { - pr_warning("corrupted callchain. skipping...\n"); - return 0; - } - - for (i = 0; i < chain->nr; i++) { - u64 ip; - struct addr_location al; - - if (callchain_param.order == ORDER_CALLEE) - ip = chain->ips[i]; - else - ip = chain->ips[chain->nr - i - 1]; - - if (ip >= PERF_CONTEXT_MAX) { - switch (ip) { - case PERF_CONTEXT_HV: - cpumode = PERF_RECORD_MISC_HYPERVISOR; - break; - case PERF_CONTEXT_KERNEL: - cpumode = PERF_RECORD_MISC_KERNEL; - break; - case PERF_CONTEXT_USER: - cpumode = PERF_RECORD_MISC_USER; - break; - default: - pr_debug("invalid callchain context: " - "%"PRId64"\n", (s64) ip); - /* - * It seems the callchain is corrupted. - * Discard all. - */ - callchain_cursor_reset(&callchain_cursor); - return 0; - } - continue; - } - - al.filtered = false; - thread__find_addr_location(thread, machine, cpumode, - MAP__FUNCTION, ip, &al, NULL); - if (al.sym != NULL) { - if (sort__has_parent && !*parent && - symbol__match_parent_regex(al.sym)) - *parent = al.sym; - if (!symbol_conf.use_callchain) - break; - } - - err = callchain_cursor_append(&callchain_cursor, - ip, al.map, al.sym); - if (err) - return err; - } - - return 0; -} - -static int unwind_entry(struct unwind_entry *entry, void *arg) -{ - struct callchain_cursor *cursor = arg; - return callchain_cursor_append(cursor, entry->ip, - entry->map, entry->sym); -} - -int machine__resolve_callchain(struct machine *machine, - struct perf_evsel *evsel, - struct thread *thread, - struct perf_sample *sample, - struct symbol **parent) - -{ - int ret; - - callchain_cursor_reset(&callchain_cursor); - - ret = machine__resolve_callchain_sample(machine, thread, - sample->callchain, parent); - if (ret) - return ret; - - /* Can we do dwarf post unwind? */ - if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && - (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) - return 0; - - /* Bail out if nothing was captured. */ - if ((!sample->user_regs.regs) || - (!sample->user_stack.size)) - return 0; - - return unwind__get_entries(unwind_entry, &callchain_cursor, machine, - thread, evsel->attr.sample_regs_user, - sample); - -} - static int process_event_synth_tracing_data_stub(union perf_event *event __maybe_unused, struct perf_session *session diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e5ba9840ac22..2960284d6ae1 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -28,8 +28,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, symbol_filter_t filter); static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, symbol_filter_t filter); -static int vmlinux_path__nr_entries; -static char **vmlinux_path; +int vmlinux_path__nr_entries; +char **vmlinux_path; struct symbol_conf symbol_conf = { .exclude_other = true, @@ -202,13 +202,6 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) curr->end = ~0ULL; } -static void map_groups__fixup_end(struct map_groups *mg) -{ - int i; - for (i = 0; i < MAP__NR_TYPES; ++i) - __map_groups__fixup_end(mg, i); -} - struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) { size_t namelen = strlen(name) + 1; @@ -652,8 +645,8 @@ discard_symbol: rb_erase(&pos->rb_node, root); return count + moved; } -static bool symbol__restricted_filename(const char *filename, - const char *restricted_filename) +bool symbol__restricted_filename(const char *filename, + const char *restricted_filename) { bool restricted = false; @@ -887,200 +880,6 @@ struct map *map_groups__find_by_name(struct map_groups *mg, return NULL; } -static int map_groups__set_modules_path_dir(struct map_groups *mg, - const char *dir_name) -{ - struct dirent *dent; - DIR *dir = opendir(dir_name); - int ret = 0; - - if (!dir) { - pr_debug("%s: cannot open %s dir\n", __func__, dir_name); - return -1; - } - - while ((dent = readdir(dir)) != NULL) { - char path[PATH_MAX]; - struct stat st; - - /*sshfs might return bad dent->d_type, so we have to stat*/ - snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); - if (stat(path, &st)) - continue; - - if (S_ISDIR(st.st_mode)) { - if (!strcmp(dent->d_name, ".") || - !strcmp(dent->d_name, "..")) - continue; - - ret = map_groups__set_modules_path_dir(mg, path); - if (ret < 0) - goto out; - } else { - char *dot = strrchr(dent->d_name, '.'), - dso_name[PATH_MAX]; - struct map *map; - char *long_name; - - if (dot == NULL || strcmp(dot, ".ko")) - continue; - snprintf(dso_name, sizeof(dso_name), "[%.*s]", - (int)(dot - dent->d_name), dent->d_name); - - strxfrchar(dso_name, '-', '_'); - map = map_groups__find_by_name(mg, MAP__FUNCTION, - dso_name); - if (map == NULL) - continue; - - long_name = strdup(path); - if (long_name == NULL) { - ret = -1; - goto out; - } - dso__set_long_name(map->dso, long_name); - map->dso->lname_alloc = 1; - dso__kernel_module_get_build_id(map->dso, ""); - } - } - -out: - closedir(dir); - return ret; -} - -static char *get_kernel_version(const char *root_dir) -{ - char version[PATH_MAX]; - FILE *file; - char *name, *tmp; - const char *prefix = "Linux version "; - - sprintf(version, "%s/proc/version", root_dir); - file = fopen(version, "r"); - if (!file) - return NULL; - - version[0] = '\0'; - tmp = fgets(version, sizeof(version), file); - fclose(file); - - name = strstr(version, prefix); - if (!name) - return NULL; - name += strlen(prefix); - tmp = strchr(name, ' '); - if (tmp) - *tmp = '\0'; - - return strdup(name); -} - -static int machine__set_modules_path(struct machine *machine) -{ - char *version; - char modules_path[PATH_MAX]; - - version = get_kernel_version(machine->root_dir); - if (!version) - return -1; - - snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", - machine->root_dir, version); - free(version); - - return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); -} - -struct map *machine__new_module(struct machine *machine, u64 start, - const char *filename) -{ - struct map *map; - struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); - - if (dso == NULL) - return NULL; - - map = map__new2(start, dso, MAP__FUNCTION); - if (map == NULL) - return NULL; - - if (machine__is_host(machine)) - dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; - else - dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; - map_groups__insert(&machine->kmaps, map); - return map; -} - -static int machine__create_modules(struct machine *machine) -{ - char *line = NULL; - size_t n; - FILE *file; - struct map *map; - const char *modules; - char path[PATH_MAX]; - - if (machine__is_default_guest(machine)) - modules = symbol_conf.default_guest_modules; - else { - sprintf(path, "%s/proc/modules", machine->root_dir); - modules = path; - } - - if (symbol__restricted_filename(path, "/proc/modules")) - return -1; - - file = fopen(modules, "r"); - if (file == NULL) - return -1; - - while (!feof(file)) { - char name[PATH_MAX]; - u64 start; - char *sep; - int line_len; - - line_len = getline(&line, &n, file); - if (line_len < 0) - break; - - if (!line) - goto out_failure; - - line[--line_len] = '\0'; /* \n */ - - sep = strrchr(line, 'x'); - if (sep == NULL) - continue; - - hex2u64(sep + 1, &start); - - sep = strchr(line, ' '); - if (sep == NULL) - continue; - - *sep = '\0'; - - snprintf(name, sizeof(name), "[%s]", line); - map = machine__new_module(machine, start, name); - if (map == NULL) - goto out_delete_line; - dso__kernel_module_get_build_id(map->dso, machine->root_dir); - } - - free(line); - fclose(file); - - return machine__set_modules_path(machine); - -out_delete_line: - free(line); -out_failure: - return -1; -} - int dso__load_vmlinux(struct dso *dso, struct map *map, const char *vmlinux, symbol_filter_t filter) { @@ -1300,195 +1099,6 @@ out_try_fixup: return err; } -size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) -{ - struct rb_node *nd; - size_t ret = 0; - - for (nd = rb_first(machines); nd; nd = rb_next(nd)) { - struct machine *pos = rb_entry(nd, struct machine, rb_node); - ret += __dsos__fprintf(&pos->kernel_dsos, fp); - ret += __dsos__fprintf(&pos->user_dsos, fp); - } - - return ret; -} - -size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, - bool (skip)(struct dso *dso, int parm), int parm) -{ - return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) + - __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm); -} - -size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, - bool (skip)(struct dso *dso, int parm), int parm) -{ - struct rb_node *nd; - size_t ret = 0; - - for (nd = rb_first(machines); nd; nd = rb_next(nd)) { - struct machine *pos = rb_entry(nd, struct machine, rb_node); - ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); - } - return ret; -} - -static struct dso *machine__get_kernel(struct machine *machine) -{ - const char *vmlinux_name = NULL; - struct dso *kernel; - - if (machine__is_host(machine)) { - vmlinux_name = symbol_conf.vmlinux_name; - if (!vmlinux_name) - vmlinux_name = "[kernel.kallsyms]"; - - kernel = dso__kernel_findnew(machine, vmlinux_name, - "[kernel]", - DSO_TYPE_KERNEL); - } else { - char bf[PATH_MAX]; - - if (machine__is_default_guest(machine)) - vmlinux_name = symbol_conf.default_guest_vmlinux_name; - if (!vmlinux_name) - vmlinux_name = machine__mmap_name(machine, bf, - sizeof(bf)); - - kernel = dso__kernel_findnew(machine, vmlinux_name, - "[guest.kernel]", - DSO_TYPE_GUEST_KERNEL); - } - - if (kernel != NULL && (!kernel->has_build_id)) - dso__read_running_kernel_build_id(kernel, machine); - - return kernel; -} - -struct process_args { - u64 start; -}; - -static int symbol__in_kernel(void *arg, const char *name, - char type __maybe_unused, u64 start) -{ - struct process_args *args = arg; - - if (strchr(name, '[')) - return 0; - - args->start = start; - return 1; -} - -/* Figure out the start address of kernel map from /proc/kallsyms */ -static u64 machine__get_kernel_start_addr(struct machine *machine) -{ - const char *filename; - char path[PATH_MAX]; - struct process_args args; - - if (machine__is_host(machine)) { - filename = "/proc/kallsyms"; - } else { - if (machine__is_default_guest(machine)) - filename = (char *)symbol_conf.default_guest_kallsyms; - else { - sprintf(path, "%s/proc/kallsyms", machine->root_dir); - filename = path; - } - } - - if (symbol__restricted_filename(filename, "/proc/kallsyms")) - return 0; - - if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) - return 0; - - return args.start; -} - -int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) -{ - enum map_type type; - u64 start = machine__get_kernel_start_addr(machine); - - for (type = 0; type < MAP__NR_TYPES; ++type) { - struct kmap *kmap; - - machine->vmlinux_maps[type] = map__new2(start, kernel, type); - if (machine->vmlinux_maps[type] == NULL) - return -1; - - machine->vmlinux_maps[type]->map_ip = - machine->vmlinux_maps[type]->unmap_ip = - identity__map_ip; - kmap = map__kmap(machine->vmlinux_maps[type]); - kmap->kmaps = &machine->kmaps; - map_groups__insert(&machine->kmaps, - machine->vmlinux_maps[type]); - } - - return 0; -} - -void machine__destroy_kernel_maps(struct machine *machine) -{ - enum map_type type; - - for (type = 0; type < MAP__NR_TYPES; ++type) { - struct kmap *kmap; - - if (machine->vmlinux_maps[type] == NULL) - continue; - - kmap = map__kmap(machine->vmlinux_maps[type]); - map_groups__remove(&machine->kmaps, - machine->vmlinux_maps[type]); - if (kmap->ref_reloc_sym) { - /* - * ref_reloc_sym is shared among all maps, so free just - * on one of them. - */ - if (type == MAP__FUNCTION) { - free((char *)kmap->ref_reloc_sym->name); - kmap->ref_reloc_sym->name = NULL; - free(kmap->ref_reloc_sym); - } - kmap->ref_reloc_sym = NULL; - } - - map__delete(machine->vmlinux_maps[type]); - machine->vmlinux_maps[type] = NULL; - } -} - -int machine__create_kernel_maps(struct machine *machine) -{ - struct dso *kernel = machine__get_kernel(machine); - - if (kernel == NULL || - __machine__create_kernel_maps(machine, kernel) < 0) - return -1; - - if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { - if (machine__is_host(machine)) - pr_debug("Problems creating module maps, " - "continuing anyway...\n"); - else - pr_debug("Problems creating module maps for guest %d, " - "continuing anyway...\n", machine->pid); - } - - /* - * Now that we have all the maps created, just set the ->end of them: - */ - map_groups__fixup_end(&machine->kmaps); - return 0; -} - static void vmlinux_path__exit(void) { while (--vmlinux_path__nr_entries >= 0) { @@ -1549,25 +1159,6 @@ out_fail: return -1; } -size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) -{ - int i; - size_t printed = 0; - struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; - - if (kdso->has_build_id) { - char filename[PATH_MAX]; - if (dso__build_id_filename(kdso, filename, sizeof(filename))) - printed += fprintf(fp, "[0] %s\n", filename); - } - - for (i = 0; i < vmlinux_path__nr_entries; ++i) - printed += fprintf(fp, "[%d] %s\n", - i + kdso->has_build_id, vmlinux_path[i]); - - return printed; -} - static int setup_list(struct strlist **list, const char *list_str, const char *list_name) { @@ -1671,108 +1262,3 @@ void symbol__exit(void) symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; symbol_conf.initialized = false; } - -int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) -{ - struct machine *machine = machines__findnew(machines, pid); - - if (machine == NULL) - return -1; - - return machine__create_kernel_maps(machine); -} - -int machines__create_guest_kernel_maps(struct rb_root *machines) -{ - int ret = 0; - struct dirent **namelist = NULL; - int i, items = 0; - char path[PATH_MAX]; - pid_t pid; - char *endp; - - if (symbol_conf.default_guest_vmlinux_name || - symbol_conf.default_guest_modules || - symbol_conf.default_guest_kallsyms) { - machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); - } - - if (symbol_conf.guestmount) { - items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); - if (items <= 0) - return -ENOENT; - for (i = 0; i < items; i++) { - if (!isdigit(namelist[i]->d_name[0])) { - /* Filter out . and .. */ - continue; - } - pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10); - if ((*endp != '\0') || - (endp == namelist[i]->d_name) || - (errno == ERANGE)) { - pr_debug("invalid directory (%s). Skipping.\n", - namelist[i]->d_name); - continue; - } - sprintf(path, "%s/%s/proc/kallsyms", - symbol_conf.guestmount, - namelist[i]->d_name); - ret = access(path, R_OK); - if (ret) { - pr_debug("Can't access file %s\n", path); - goto failure; - } - machines__create_kernel_maps(machines, pid); - } -failure: - free(namelist); - } - - return ret; -} - -void machines__destroy_guest_kernel_maps(struct rb_root *machines) -{ - struct rb_node *next = rb_first(machines); - - while (next) { - struct machine *pos = rb_entry(next, struct machine, rb_node); - - next = rb_next(&pos->rb_node); - rb_erase(&pos->rb_node, machines); - machine__delete(pos); - } -} - -int machine__load_kallsyms(struct machine *machine, const char *filename, - enum map_type type, symbol_filter_t filter) -{ - struct map *map = machine->vmlinux_maps[type]; - int ret = dso__load_kallsyms(map->dso, filename, map, filter); - - if (ret > 0) { - dso__set_loaded(map->dso, type); - /* - * Since /proc/kallsyms will have multiple sessions for the - * kernel, with modules between them, fixup the end of all - * sections. - */ - __map_groups__fixup_end(&machine->kmaps, type); - } - - return ret; -} - -int machine__load_vmlinux_path(struct machine *machine, enum map_type type, - symbol_filter_t filter) -{ - struct map *map = machine->vmlinux_maps[type]; - int ret = dso__load_vmlinux_path(map->dso, map, filter); - - if (ret > 0) { - dso__set_loaded(map->dso, type); - map__reloc_vmlinux(map); - } - - return ret; -} diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index de68f98b236d..ec7b2405c377 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -120,6 +120,8 @@ struct symbol_conf { }; extern struct symbol_conf symbol_conf; +extern int vmlinux_path__nr_entries; +extern char **vmlinux_path; static inline void *symbol__priv(struct symbol *sym) { @@ -223,6 +225,8 @@ size_t symbol__fprintf_symname_offs(const struct symbol *sym, size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); size_t symbol__fprintf(struct symbol *sym, FILE *fp); bool symbol_type__is_a(char symbol_type, enum map_type map_type); +bool symbol__restricted_filename(const char *filename, + const char *restricted_filename); int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, struct symsrc *runtime_ss, symbol_filter_t filter, diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index df59623ac763..632e40e5ceca 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -54,10 +54,10 @@ int thread__comm_len(struct thread *self) return self->comm_len; } -static size_t thread__fprintf(struct thread *self, FILE *fp) +size_t thread__fprintf(struct thread *thread, FILE *fp) { - return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + - map_groups__fprintf(&self->mg, verbose, fp); + return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) + + map_groups__fprintf(&thread->mg, verbose, fp); } void thread__insert_map(struct thread *self, struct map *map) @@ -84,17 +84,3 @@ int thread__fork(struct thread *self, struct thread *parent) return -ENOMEM; return 0; } - -size_t machine__fprintf(struct machine *machine, FILE *fp) -{ - size_t ret = 0; - struct rb_node *nd; - - for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { - struct thread *pos = rb_entry(nd, struct thread, rb_node); - - ret += thread__fprintf(pos, fp); - } - - return ret; -} diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index f2fa17caa7d5..5ad266403098 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -30,6 +30,7 @@ int thread__set_comm(struct thread *self, const char *comm); int thread__comm_len(struct thread *self); void thread__insert_map(struct thread *self, struct map *map); int thread__fork(struct thread *self, struct thread *parent); +size_t thread__fprintf(struct thread *thread, FILE *fp); static inline struct map *thread__find_map(struct thread *self, enum map_type type, u64 addr) -- cgit v1.2.3-59-g8ed1b From 7be5ebe8767eaa482e18f566de5f56c1519abf59 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 10 Dec 2012 14:53:43 -0300 Subject: perf evsel: Update sample_size when setting sample_type bits We use evsel->sample_size to detect underflows in perf_evsel__parse_sample, but we were failing to update it after perf_evsel__init(), i.e. when we decide, after creating an evsel, that we want some extra field bit set. Fix it by introducing methods to set a bit that will take care of correctly adjusting evsel->sample_size. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-2ny5pzsing0dcth7hws48x9c@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 2 +- tools/perf/builtin-top.c | 11 ++++++----- tools/perf/tests/perf-record.c | 6 +++--- tools/perf/util/evlist.c | 2 +- tools/perf/util/evsel.c | 45 ++++++++++++++++++++++++++++++------------ tools/perf/util/evsel.h | 11 +++++++++++ 6 files changed, 54 insertions(+), 23 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f3151d3c70ce..0be6605db9ea 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -286,7 +286,7 @@ try_again: */ opts->sample_id_all_missing = true; if (!opts->sample_time && !opts->raw_samples && !time_needed) - attr->sample_type &= ~PERF_SAMPLE_TIME; + perf_evsel__reset_sample_bit(pos, TIME); goto retry_sample_id; } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 987e1b8a9c2e..31a7c51aac76 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -901,24 +901,25 @@ static void perf_top__start_counters(struct perf_top *top) list_for_each_entry(counter, &evlist->entries, node) { struct perf_event_attr *attr = &counter->attr; - attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; + perf_evsel__set_sample_bit(counter, IP); + perf_evsel__set_sample_bit(counter, TID); if (top->freq) { - attr->sample_type |= PERF_SAMPLE_PERIOD; + perf_evsel__set_sample_bit(counter, PERIOD); attr->freq = 1; attr->sample_freq = top->freq; } if (evlist->nr_entries > 1) { - attr->sample_type |= PERF_SAMPLE_ID; + perf_evsel__set_sample_bit(counter, ID); attr->read_format |= PERF_FORMAT_ID; } if (perf_target__has_cpu(&top->target)) - attr->sample_type |= PERF_SAMPLE_CPU; + perf_evsel__set_sample_bit(counter, CPU); if (symbol_conf.use_callchain) - attr->sample_type |= PERF_SAMPLE_CALLCHAIN; + perf_evsel__set_sample_bit(counter, CALLCHAIN); attr->mmap = 1; attr->comm = 1; diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 70e0d4421df8..5902772492b6 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -103,9 +103,9 @@ int test__PERF_RECORD(void) * Config the evsels, setting attr->comm on the first one, etc. */ evsel = perf_evlist__first(evlist); - evsel->attr.sample_type |= PERF_SAMPLE_CPU; - evsel->attr.sample_type |= PERF_SAMPLE_TID; - evsel->attr.sample_type |= PERF_SAMPLE_TIME; + perf_evsel__set_sample_bit(evsel, CPU); + perf_evsel__set_sample_bit(evsel, TID); + perf_evsel__set_sample_bit(evsel, TIME); perf_evlist__config_attrs(evlist, &opts); err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index d0e1e821fe85..265565942ae5 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -61,7 +61,7 @@ void perf_evlist__config_attrs(struct perf_evlist *evlist, perf_evsel__config(evsel, opts); if (evlist->nr_entries > 1) - evsel->attr.sample_type |= PERF_SAMPLE_ID; + perf_evsel__set_sample_bit(evsel, ID); } } diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index bb58b05f905f..fc80f5a32fa6 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -50,6 +50,24 @@ void hists__init(struct hists *hists) pthread_mutex_init(&hists->lock, NULL); } +void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, + enum perf_event_sample_format bit) +{ + if (!(evsel->attr.sample_type & bit)) { + evsel->attr.sample_type |= bit; + evsel->sample_size += sizeof(u64); + } +} + +void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, + enum perf_event_sample_format bit) +{ + if (evsel->attr.sample_type & bit) { + evsel->attr.sample_type &= ~bit; + evsel->sample_size -= sizeof(u64); + } +} + void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr, int idx) { @@ -445,7 +463,8 @@ void perf_evsel__config(struct perf_evsel *evsel, PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID; - attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; + perf_evsel__set_sample_bit(evsel, IP); + perf_evsel__set_sample_bit(evsel, TID); /* * We default some events to a 1 default interval. But keep @@ -454,7 +473,7 @@ void perf_evsel__config(struct perf_evsel *evsel, if (!attr->sample_period || (opts->user_freq != UINT_MAX && opts->user_interval != ULLONG_MAX)) { if (opts->freq) { - attr->sample_type |= PERF_SAMPLE_PERIOD; + perf_evsel__set_sample_bit(evsel, PERIOD); attr->freq = 1; attr->sample_freq = opts->freq; } else { @@ -469,16 +488,16 @@ void perf_evsel__config(struct perf_evsel *evsel, attr->inherit_stat = 1; if (opts->sample_address) { - attr->sample_type |= PERF_SAMPLE_ADDR; + perf_evsel__set_sample_bit(evsel, ADDR); attr->mmap_data = track; } if (opts->call_graph) { - attr->sample_type |= PERF_SAMPLE_CALLCHAIN; + perf_evsel__set_sample_bit(evsel, CALLCHAIN); if (opts->call_graph == CALLCHAIN_DWARF) { - attr->sample_type |= PERF_SAMPLE_REGS_USER | - PERF_SAMPLE_STACK_USER; + perf_evsel__set_sample_bit(evsel, REGS_USER); + perf_evsel__set_sample_bit(evsel, STACK_USER); attr->sample_regs_user = PERF_REGS_MASK; attr->sample_stack_user = opts->stack_dump_size; attr->exclude_callchain_user = 1; @@ -486,20 +505,20 @@ void perf_evsel__config(struct perf_evsel *evsel, } if (perf_target__has_cpu(&opts->target)) - attr->sample_type |= PERF_SAMPLE_CPU; + perf_evsel__set_sample_bit(evsel, CPU); if (opts->period) - attr->sample_type |= PERF_SAMPLE_PERIOD; + perf_evsel__set_sample_bit(evsel, PERIOD); if (!opts->sample_id_all_missing && (opts->sample_time || !opts->no_inherit || perf_target__has_cpu(&opts->target))) - attr->sample_type |= PERF_SAMPLE_TIME; + perf_evsel__set_sample_bit(evsel, TIME); if (opts->raw_samples) { - attr->sample_type |= PERF_SAMPLE_TIME; - attr->sample_type |= PERF_SAMPLE_RAW; - attr->sample_type |= PERF_SAMPLE_CPU; + perf_evsel__set_sample_bit(evsel, TIME); + perf_evsel__set_sample_bit(evsel, RAW); + perf_evsel__set_sample_bit(evsel, CPU); } if (opts->no_delay) { @@ -507,7 +526,7 @@ void perf_evsel__config(struct perf_evsel *evsel, attr->wakeup_events = 1; } if (opts->branch_stack) { - attr->sample_type |= PERF_SAMPLE_BRANCH_STACK; + perf_evsel__set_sample_bit(evsel, BRANCH_STACK); attr->branch_sample_type = opts->branch_stack; } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 3f7ff471de2b..739853969243 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -118,6 +118,17 @@ void perf_evsel__free_fd(struct perf_evsel *evsel); void perf_evsel__free_id(struct perf_evsel *evsel); void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); +void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, + enum perf_event_sample_format bit); +void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, + enum perf_event_sample_format bit); + +#define perf_evsel__set_sample_bit(evsel, bit) \ + __perf_evsel__set_sample_bit(evsel, PERF_SAMPLE_##bit) + +#define perf_evsel__reset_sample_bit(evsel, bit) \ + __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit) + int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, const char *filter); -- cgit v1.2.3-59-g8ed1b From 7a5a5ca5fe3df8636c96b49591c23baf7c415dd4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 10 Dec 2012 15:21:30 -0300 Subject: perf evsel: Introduce method to request IDs be used When mmaping multiple events we need to find the right evsel that matches an event in the ring buffer. For that we need to set the PERF_FORMAT_ID bit in perf_event_attr.read_format so that when we read the event fds we get that id to then hash it and be able later to use perf_evlist__id2evsel to find the right evsel. We also need to set the PERF_SAMPLE_ID bit in perf_event_attr.sample_type to ask for that id to be stashed in each sample, so that we can demux it. So add a perf_evsel__set_sample_id() method to do those two things in one operation. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-1z4xcmbud30lamklfe80oopu@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 6 ++---- tools/perf/tests/mmap-basic.c | 3 +-- tools/perf/util/evsel.c | 6 ++++++ tools/perf/util/evsel.h | 2 ++ 4 files changed, 11 insertions(+), 6 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 31a7c51aac76..a30647487ba3 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -910,10 +910,8 @@ static void perf_top__start_counters(struct perf_top *top) attr->sample_freq = top->freq; } - if (evlist->nr_entries > 1) { - perf_evsel__set_sample_bit(counter, ID); - attr->read_format |= PERF_FORMAT_ID; - } + if (evlist->nr_entries > 1) + perf_evsel__set_sample_id(counter); if (perf_target__has_cpu(&top->target)) perf_evsel__set_sample_bit(counter, CPU); diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 4743b6d7a09a..cdd50755af51 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -70,8 +70,7 @@ int test__basic_mmap(void) } evsels[i]->attr.wakeup_events = 1; - evsels[i]->attr.read_format |= PERF_FORMAT_ID; - perf_evsel__set_sample_bit(evsels[i], ID); + perf_evsel__set_sample_id(evsels[i]); perf_evlist__add(evlist, evsels[i]); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index fc80f5a32fa6..9dde7e933be9 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -68,6 +68,12 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, } } +void perf_evsel__set_sample_id(struct perf_evsel *evsel) +{ + perf_evsel__set_sample_bit(evsel, ID); + evsel->attr.read_format |= PERF_FORMAT_ID; +} + void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr, int idx) { diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 739853969243..5c089775064f 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -129,6 +129,8 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, #define perf_evsel__reset_sample_bit(evsel, bit) \ __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit) +void perf_evsel__set_sample_id(struct perf_evsel *evsel); + int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, const char *filter); -- cgit v1.2.3-59-g8ed1b From 3a5afaec593954a399967155db47f72cb8828a6a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 10 Dec 2012 15:29:12 -0300 Subject: perf evsel: No need to always ask for PERF_FORMAT_ID in read_format Instead make perf_evlist__confir_attrs use perf_evsel__set_sample_id() when having more than one event, that way only if we have multiple events we'll ask to have the event ids returned when we read its file descriptors. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-xuho5hrrxy2ky0cjpr80hyfp@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/attr/base-record | 2 +- tools/perf/tests/attr/test-record-group | 2 ++ tools/perf/tests/attr/test-record-group1 | 2 ++ tools/perf/util/evlist.c | 2 +- tools/perf/util/evsel.c | 3 +-- 5 files changed, 7 insertions(+), 4 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record index f1485d8e6a0b..f9d04643109e 100644 --- a/tools/perf/tests/attr/base-record +++ b/tools/perf/tests/attr/base-record @@ -7,7 +7,7 @@ size=96 config=0 sample_period=4000 sample_type=263 -read_format=7 +read_format=3 disabled=1 inherit=1 pinned=0 diff --git a/tools/perf/tests/attr/test-record-group b/tools/perf/tests/attr/test-record-group index a6599e9a19d3..0df34cab3e42 100644 --- a/tools/perf/tests/attr/test-record-group +++ b/tools/perf/tests/attr/test-record-group @@ -6,12 +6,14 @@ args = --group -e cycles,instructions kill >/dev/null 2>&1 fd=1 group_fd=-1 sample_type=327 +read_format=7 [event-2:base-record] fd=2 group_fd=1 config=1 sample_type=327 +read_format=7 mmap=0 comm=0 enable_on_exec=0 diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1 index 5a8359da38af..18bd926ff6cb 100644 --- a/tools/perf/tests/attr/test-record-group1 +++ b/tools/perf/tests/attr/test-record-group1 @@ -6,6 +6,7 @@ args = -e '{cycles,instructions}' kill >/tmp/krava 2>&1 fd=1 group_fd=-1 sample_type=327 +read_format=7 [event-2:base-record] fd=2 @@ -13,6 +14,7 @@ group_fd=1 type=0 config=1 sample_type=327 +read_format=7 mmap=0 comm=0 enable_on_exec=0 diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 265565942ae5..5a0878d3a038 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -61,7 +61,7 @@ void perf_evlist__config_attrs(struct perf_evlist *evlist, perf_evsel__config(evsel, opts); if (evlist->nr_entries > 1) - perf_evsel__set_sample_bit(evsel, ID); + perf_evsel__set_sample_id(evsel); } } diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 9dde7e933be9..e62d3aef9cd6 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -466,8 +466,7 @@ void perf_evsel__config(struct perf_evsel *evsel, attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; attr->inherit = !opts->no_inherit; attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | - PERF_FORMAT_TOTAL_TIME_RUNNING | - PERF_FORMAT_ID; + PERF_FORMAT_TOTAL_TIME_RUNNING; perf_evsel__set_sample_bit(evsel, IP); perf_evsel__set_sample_bit(evsel, TID); -- cgit v1.2.3-59-g8ed1b From 62b807f64948f55776b1cc57298966d915b1a402 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 10 Dec 2012 16:04:40 -0300 Subject: perf evsel: No need to always ask for PERF_FORMAT_TOTAL_TIME_{ENABLED,RUNNING} This is needed, so far, just in 'perf stat', to scale counters, so don't unconditionally ask for them in the perf_evsel__config() method. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-ujpujgscq2f2oodxuso5nobc@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/attr/base-record | 2 +- tools/perf/tests/attr/test-record-group | 4 ++-- tools/perf/tests/attr/test-record-group1 | 4 ++-- tools/perf/util/evsel.c | 2 -- 4 files changed, 5 insertions(+), 7 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record index f9d04643109e..5bc3880f7be5 100644 --- a/tools/perf/tests/attr/base-record +++ b/tools/perf/tests/attr/base-record @@ -7,7 +7,7 @@ size=96 config=0 sample_period=4000 sample_type=263 -read_format=3 +read_format=0 disabled=1 inherit=1 pinned=0 diff --git a/tools/perf/tests/attr/test-record-group b/tools/perf/tests/attr/test-record-group index 0df34cab3e42..57739cacdb2a 100644 --- a/tools/perf/tests/attr/test-record-group +++ b/tools/perf/tests/attr/test-record-group @@ -6,14 +6,14 @@ args = --group -e cycles,instructions kill >/dev/null 2>&1 fd=1 group_fd=-1 sample_type=327 -read_format=7 +read_format=4 [event-2:base-record] fd=2 group_fd=1 config=1 sample_type=327 -read_format=7 +read_format=4 mmap=0 comm=0 enable_on_exec=0 diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1 index 18bd926ff6cb..4d688a13fd2f 100644 --- a/tools/perf/tests/attr/test-record-group1 +++ b/tools/perf/tests/attr/test-record-group1 @@ -6,7 +6,7 @@ args = -e '{cycles,instructions}' kill >/tmp/krava 2>&1 fd=1 group_fd=-1 sample_type=327 -read_format=7 +read_format=4 [event-2:base-record] fd=2 @@ -14,7 +14,7 @@ group_fd=1 type=0 config=1 sample_type=327 -read_format=7 +read_format=4 mmap=0 comm=0 enable_on_exec=0 diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index e62d3aef9cd6..2492d329a5f5 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -465,8 +465,6 @@ void perf_evsel__config(struct perf_evsel *evsel, attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; attr->inherit = !opts->no_inherit; - attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | - PERF_FORMAT_TOTAL_TIME_RUNNING; perf_evsel__set_sample_bit(evsel, IP); perf_evsel__set_sample_bit(evsel, TID); -- cgit v1.2.3-59-g8ed1b From f77a951826b44b763e4d9fbd2479b6132d2bd7fc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 10 Dec 2012 16:41:31 -0300 Subject: perf evlist: Set the leader in the perf_evlist__config method Since we need to ensure the leader is set before configuring the evsel perf_event_attrs. Reducing the boilerplate needed by tools, helping, for instance, 'perf trace', that wasn't setting the leader. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-22shm0ptkch2kgl7rtqlligx@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 9 +-------- tools/perf/builtin-trace.c | 2 +- tools/perf/tests/perf-record.c | 2 +- tools/perf/util/evlist.c | 10 ++++++++-- tools/perf/util/evlist.h | 4 ++-- 5 files changed, 13 insertions(+), 14 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0be6605db9ea..fc4f08044632 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -230,14 +230,7 @@ static int perf_record__open(struct perf_record *rec) struct perf_record_opts *opts = &rec->opts; int rc = 0; - /* - * Set the evsel leader links before we configure attributes, - * since some might depend on this info. - */ - if (opts->group) - perf_evlist__set_leader(evlist); - - perf_evlist__config_attrs(evlist, opts); + perf_evlist__config(evlist, opts); list_for_each_entry(pos, &evlist->entries, node) { struct perf_event_attr *attr = &pos->attr; diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 7932ffa29889..d222d7fc7e96 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -455,7 +455,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) goto out_delete_evlist; } - perf_evlist__config_attrs(evlist, &trace->opts); + perf_evlist__config(evlist, &trace->opts); signal(SIGCHLD, sig_handler); signal(SIGINT, sig_handler); diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 5902772492b6..6ea66cf6791b 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -106,7 +106,7 @@ int test__PERF_RECORD(void) perf_evsel__set_sample_bit(evsel, CPU); perf_evsel__set_sample_bit(evsel, TID); perf_evsel__set_sample_bit(evsel, TIME); - perf_evlist__config_attrs(evlist, &opts); + perf_evlist__config(evlist, &opts); err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); if (err < 0) { diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 5a0878d3a038..dc8aee97a488 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -49,10 +49,16 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, return evlist; } -void perf_evlist__config_attrs(struct perf_evlist *evlist, - struct perf_record_opts *opts) +void perf_evlist__config(struct perf_evlist *evlist, + struct perf_record_opts *opts) { struct perf_evsel *evsel; + /* + * Set the evsel leader links before we configure attributes, + * since some might depend on this info. + */ + if (opts->group) + perf_evlist__set_leader(evlist); if (evlist->cpus->map[0] < 0) opts->no_inherit = true; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 56003f779e60..457e2350d21d 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -76,8 +76,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); int perf_evlist__open(struct perf_evlist *evlist); -void perf_evlist__config_attrs(struct perf_evlist *evlist, - struct perf_record_opts *opts); +void perf_evlist__config(struct perf_evlist *evlist, + struct perf_record_opts *opts); int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct perf_record_opts *opts, -- cgit v1.2.3-59-g8ed1b From 0698aeddcfe0c2514af1d012082665a3bb55d01b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 10 Dec 2012 18:17:08 -0300 Subject: perf evsel: Adopt fprintf routine from 'perf evlist' So that we can print all the details when debugging other tools, when we have just evlists and evsels, not a perf.data file. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-mktq5fy2h5z7jyeqvvf5mbc8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-evlist.c | 81 ++------------------------------------------- tools/perf/util/evsel.c | 77 ++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/evsel.h | 8 +++++ 3 files changed, 87 insertions(+), 79 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index c20f1dcfb7e2..1312a5e03ec7 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -15,39 +15,6 @@ #include "util/parse-options.h" #include "util/session.h" -struct perf_attr_details { - bool freq; - bool verbose; -}; - -static int comma_printf(bool *first, const char *fmt, ...) -{ - va_list args; - int ret = 0; - - if (!*first) { - ret += printf(","); - } else { - ret += printf(":"); - *first = false; - } - - va_start(args, fmt); - ret += vprintf(fmt, args); - va_end(args); - return ret; -} - -static int __if_print(bool *first, const char *field, u64 value) -{ - if (value == 0) - return 0; - - return comma_printf(first, " %s: %" PRIu64, field, value); -} - -#define if_print(field) __if_print(&first, #field, pos->attr.field) - static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) { struct perf_session *session; @@ -57,52 +24,8 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details if (session == NULL) return -ENOMEM; - list_for_each_entry(pos, &session->evlist->entries, node) { - bool first = true; - - printf("%s", perf_evsel__name(pos)); - - if (details->verbose || details->freq) { - comma_printf(&first, " sample_freq=%" PRIu64, - (u64)pos->attr.sample_freq); - } - - if (details->verbose) { - if_print(type); - if_print(config); - if_print(config1); - if_print(config2); - if_print(size); - if_print(sample_type); - if_print(read_format); - if_print(disabled); - if_print(inherit); - if_print(pinned); - if_print(exclusive); - if_print(exclude_user); - if_print(exclude_kernel); - if_print(exclude_hv); - if_print(exclude_idle); - if_print(mmap); - if_print(comm); - if_print(freq); - if_print(inherit_stat); - if_print(enable_on_exec); - if_print(task); - if_print(watermark); - if_print(precise_ip); - if_print(mmap_data); - if_print(sample_id_all); - if_print(exclude_host); - if_print(exclude_guest); - if_print(__reserved_1); - if_print(wakeup_events); - if_print(bp_type); - if_print(branch_sample_type); - } - - putchar('\n'); - } + list_for_each_entry(pos, &session->evlist->entries, node) + perf_evsel__fprintf(pos, details, stdout); perf_session__delete(session); return 0; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 2492d329a5f5..643df4b06b84 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1228,3 +1228,80 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, return 0; } + +static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + if (!*first) { + ret += fprintf(fp, ","); + } else { + ret += fprintf(fp, ":"); + *first = false; + } + + va_start(args, fmt); + ret += vfprintf(fp, fmt, args); + va_end(args); + return ret; +} + +static int __if_fprintf(FILE *fp, bool *first, const char *field, u64 value) +{ + if (value == 0) + return 0; + + return comma_fprintf(fp, first, " %s: %" PRIu64, field, value); +} + +#define if_print(field) printed += __if_fprintf(fp, &first, #field, evsel->attr.field) + +int perf_evsel__fprintf(struct perf_evsel *evsel, + struct perf_attr_details *details, FILE *fp) +{ + bool first = true; + int printed = fprintf(fp, "%s", perf_evsel__name(evsel)); + + if (details->verbose || details->freq) { + printed += comma_fprintf(fp, &first, " sample_freq=%" PRIu64, + (u64)evsel->attr.sample_freq); + } + + if (details->verbose) { + if_print(type); + if_print(config); + if_print(config1); + if_print(config2); + if_print(size); + if_print(sample_type); + if_print(read_format); + if_print(disabled); + if_print(inherit); + if_print(pinned); + if_print(exclusive); + if_print(exclude_user); + if_print(exclude_kernel); + if_print(exclude_hv); + if_print(exclude_idle); + if_print(mmap); + if_print(comm); + if_print(freq); + if_print(inherit_stat); + if_print(enable_on_exec); + if_print(task); + if_print(watermark); + if_print(precise_ip); + if_print(mmap_data); + if_print(sample_id_all); + if_print(exclude_host); + if_print(exclude_guest); + if_print(__reserved_1); + if_print(wakeup_events); + if_print(bp_type); + if_print(branch_sample_type); + } + + fputc('\n', fp); + return ++printed; +} diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 5c089775064f..9cb8a0215711 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -243,4 +243,12 @@ static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) { return evsel->leader == evsel; } + +struct perf_attr_details { + bool freq; + bool verbose; +}; + +int perf_evsel__fprintf(struct perf_evsel *evsel, + struct perf_attr_details *details, FILE *fp); #endif /* __PERF_EVSEL_H */ -- cgit v1.2.3-59-g8ed1b From c79a439338f3a021f5a5ff6ea165b0d19d2eb0aa Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Dec 2012 10:54:12 -0300 Subject: perf evsel: Decode read_format and sample_type in perf_evsel__fprintf Before those fields showed just a number, now it decodes each bit: [root@sandy linux]# perf evlist -v cycles: sample_freq=4000, size: 96, sample_type: IP|TID|TIME|CPU|PERIOD, read_format: TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING|ID, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, sample_id_all: 1, exclude_guest: 1 Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-64ezdtiijolgti08ae3phxyj@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 643df4b06b84..7a2a3dc3ff03 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1257,6 +1257,53 @@ static int __if_fprintf(FILE *fp, bool *first, const char *field, u64 value) #define if_print(field) printed += __if_fprintf(fp, &first, #field, evsel->attr.field) +struct bit_names { + int bit; + const char *name; +}; + +static int bits__fprintf(FILE *fp, const char *field, u64 value, + struct bit_names *bits, bool *first) +{ + int i = 0, printed = comma_fprintf(fp, first, " %s: ", field); + bool first_bit = true; + + do { + if (value & bits[i].bit) { + printed += fprintf(fp, "%s%s", first_bit ? "" : "|", bits[i].name); + first_bit = false; + } + } while (bits[++i].name != NULL); + + return printed; +} + +static int sample_type__fprintf(FILE *fp, bool *first, u64 value) +{ +#define bit_name(n) { PERF_SAMPLE_##n, #n } + struct bit_names bits[] = { + bit_name(IP), bit_name(TID), bit_name(TIME), bit_name(ADDR), + bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), + bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), + bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), + { .name = NULL, } + }; +#undef bit_name + return bits__fprintf(fp, "sample_type", value, bits, first); +} + +static int read_format__fprintf(FILE *fp, bool *first, u64 value) +{ +#define bit_name(n) { PERF_FORMAT_##n, #n } + struct bit_names bits[] = { + bit_name(TOTAL_TIME_ENABLED), bit_name(TOTAL_TIME_RUNNING), + bit_name(ID), bit_name(GROUP), + { .name = NULL, } + }; +#undef bit_name + return bits__fprintf(fp, "read_format", value, bits, first); +} + int perf_evsel__fprintf(struct perf_evsel *evsel, struct perf_attr_details *details, FILE *fp) { @@ -1274,8 +1321,9 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, if_print(config1); if_print(config2); if_print(size); - if_print(sample_type); - if_print(read_format); + printed += sample_type__fprintf(fp, &first, evsel->attr.sample_type); + if (evsel->attr.read_format) + printed += read_format__fprintf(fp, &first, evsel->attr.read_format); if_print(disabled); if_print(inherit); if_print(pinned); -- cgit v1.2.3-59-g8ed1b From 75d9a10854db6aab2400cd6a844c392107be4c64 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Dec 2012 16:46:05 -0300 Subject: perf record: Export the callchain parsing routine and help Will be used by perf top, that will first setup the symbol system to deal with callchains and then call these routines to ask the kernel for callchains. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-jg0dh8rmlx7x11e7u7mnasvd@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 11 ++++++----- tools/perf/util/callchain.h | 5 +++++ 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d035040efe1d..028de726b832 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -868,7 +868,8 @@ static int get_stack_size(char *str, unsigned long *_size) } #endif /* LIBUNWIND_SUPPORT */ -static int parse_callchain_opt(const struct option *opt, const char *arg, int unset) +int record_parse_callchain_opt(const struct option *opt, + const char *arg, int unset) { struct perf_record_opts *opts = opt->value; char *tok, *name, *saveptr = NULL; @@ -973,9 +974,9 @@ static struct perf_record record = { #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " #ifdef LIBUNWIND_SUPPORT -static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; +const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; #else -static const char callchain_help[] = CALLCHAIN_HELP "[fp]"; +const char record_callchain_help[] = CALLCHAIN_HELP "[fp]"; #endif /* @@ -1020,8 +1021,8 @@ const struct option record_options[] = { OPT_BOOLEAN(0, "group", &record.opts.group, "put the counters into a counter group"), OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts, - "mode[,dump_size]", callchain_help, - &parse_callchain_opt, "fp"), + "mode[,dump_size]", record_callchain_help, + &record_parse_callchain_opt, "fp"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index eb340571e7d6..3ee9f67d5af0 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -143,4 +143,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor) cursor->curr = cursor->curr->next; cursor->pos++; } + +struct option; + +int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); +extern const char record_callchain_help[]; #endif /* __PERF_CALLCHAIN_H */ -- cgit v1.2.3-59-g8ed1b From 2376c67a7bbc7849b806688ba2efb8520c21c458 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Dec 2012 16:48:41 -0300 Subject: perf top: Use perf_evlist__config() Using struct perf_record_opts to specify how to configure the evsel perf_event_attrs. This gets top closer to record in the way it sets up evsels, with the aim of sharing more and more to the point that both will be a single utility. In this direction top now uses the same callchain option parsing as record and that brings DWARF callchains to top, something that was already available for record. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-u03o0bsrqcjgskciso3pvsjr@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-top.txt | 2 +- tools/perf/builtin-top.c | 204 +++++++++++----------------------- tools/perf/util/top.c | 22 ++-- tools/perf/util/top.h | 8 +- 4 files changed, 79 insertions(+), 157 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 5b80d84d6b4a..a414bc95fd52 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt @@ -60,7 +60,7 @@ Default is to monitor all CPUS. -i:: --inherit:: - Child tasks inherit counters, only makes sens with -p option. + Child tasks do not inherit counters. -k :: --vmlinux=:: diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a30647487ba3..b7d2ea62dbc6 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -596,7 +596,7 @@ static void *display_thread_tui(void *arg) * via --uid. */ list_for_each_entry(pos, &top->evlist->entries, node) - pos->hists.uid_filter_str = top->target.uid_str; + pos->hists.uid_filter_str = top->record_opts.target.uid_str; perf_evlist__tui_browse_hists(top->evlist, help, &hbt, &top->session->header.env); @@ -894,34 +894,13 @@ static void perf_top__start_counters(struct perf_top *top) { struct perf_evsel *counter; struct perf_evlist *evlist = top->evlist; + struct perf_record_opts *opts = &top->record_opts; - if (top->group) - perf_evlist__set_leader(evlist); + perf_evlist__config(evlist, opts); list_for_each_entry(counter, &evlist->entries, node) { struct perf_event_attr *attr = &counter->attr; - perf_evsel__set_sample_bit(counter, IP); - perf_evsel__set_sample_bit(counter, TID); - - if (top->freq) { - perf_evsel__set_sample_bit(counter, PERIOD); - attr->freq = 1; - attr->sample_freq = top->freq; - } - - if (evlist->nr_entries > 1) - perf_evsel__set_sample_id(counter); - - if (perf_target__has_cpu(&top->target)) - perf_evsel__set_sample_bit(counter, CPU); - - if (symbol_conf.use_callchain) - perf_evsel__set_sample_bit(counter, CALLCHAIN); - - attr->mmap = 1; - attr->comm = 1; - attr->inherit = top->inherit; fallback_missing_features: if (top->exclude_guest_missing) attr->exclude_guest = attr->exclude_host = 0; @@ -995,7 +974,7 @@ try_again: } } - if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) { + if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { ui__error("Failed to mmap with %d (%s)\n", errno, strerror(errno)); goto out_err; @@ -1015,7 +994,7 @@ static int perf_top__setup_sample_type(struct perf_top *top) ui__error("Selected -g but \"sym\" not present in --sort/-s."); return -EINVAL; } - } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) { + } else if (callchain_param.mode != CHAIN_NONE) { if (callchain_register_param(&callchain_param) < 0) { ui__error("Can't register callchain params.\n"); return -EINVAL; @@ -1027,6 +1006,7 @@ static int perf_top__setup_sample_type(struct perf_top *top) static int __cmd_top(struct perf_top *top) { + struct perf_record_opts *opts = &top->record_opts; pthread_t thread; int ret; /* @@ -1041,7 +1021,7 @@ static int __cmd_top(struct perf_top *top) if (ret) goto out_delete; - if (perf_target__has_task(&top->target)) + if (perf_target__has_task(&opts->target)) perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, perf_event__process, &top->session->host_machine); @@ -1052,6 +1032,17 @@ static int __cmd_top(struct perf_top *top) top->session->evlist = top->evlist; perf_session__set_id_hdr_size(top->session); + /* + * When perf is starting the traced process, all the events (apart from + * group members) have enable_on_exec=1 set, so don't spoil it by + * prematurely enabling them. + * + * XXX 'top' still doesn't start workloads like record, trace, but should, + * so leave the check here. + */ + if (!perf_target__none(&opts->target)) + perf_evlist__enable(top->evlist); + /* Wait for a minimal set of events before starting the snapshot */ poll(top->evlist->pollfd, top->evlist->nr_fds, 100); @@ -1092,116 +1083,56 @@ out_delete: static int parse_callchain_opt(const struct option *opt, const char *arg, int unset) { - struct perf_top *top = (struct perf_top *)opt->value; - char *tok, *tok2; - char *endptr; - /* * --no-call-graph */ - if (unset) { - top->dont_use_callchains = true; + if (unset) return 0; - } symbol_conf.use_callchain = true; - if (!arg) - return 0; - - tok = strtok((char *)arg, ","); - if (!tok) - return -1; - - /* get the output mode */ - if (!strncmp(tok, "graph", strlen(arg))) - callchain_param.mode = CHAIN_GRAPH_ABS; - - else if (!strncmp(tok, "flat", strlen(arg))) - callchain_param.mode = CHAIN_FLAT; - - else if (!strncmp(tok, "fractal", strlen(arg))) - callchain_param.mode = CHAIN_GRAPH_REL; - - else if (!strncmp(tok, "none", strlen(arg))) { - callchain_param.mode = CHAIN_NONE; - symbol_conf.use_callchain = false; - - return 0; - } else - return -1; - - /* get the min percentage */ - tok = strtok(NULL, ","); - if (!tok) - goto setup; - - callchain_param.min_percent = strtod(tok, &endptr); - if (tok == endptr) - return -1; - - /* get the print limit */ - tok2 = strtok(NULL, ","); - if (!tok2) - goto setup; - - if (tok2[0] != 'c') { - callchain_param.print_limit = strtod(tok2, &endptr); - tok2 = strtok(NULL, ","); - if (!tok2) - goto setup; - } - - /* get the call chain order */ - if (!strcmp(tok2, "caller")) - callchain_param.order = ORDER_CALLER; - else if (!strcmp(tok2, "callee")) - callchain_param.order = ORDER_CALLEE; - else - return -1; -setup: - if (callchain_register_param(&callchain_param) < 0) { - fprintf(stderr, "Can't register callchain params\n"); - return -1; - } - return 0; + return record_parse_callchain_opt(opt, arg, unset); } int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) { - struct perf_evsel *pos; int status; char errbuf[BUFSIZ]; struct perf_top top = { .count_filter = 5, .delay_secs = 2, - .freq = 4000, /* 4 KHz */ - .mmap_pages = 128, - .sym_pcnt_filter = 5, - .target = { - .uses_mmap = true, + .record_opts = { + .mmap_pages = UINT_MAX, + .user_freq = UINT_MAX, + .user_interval = ULLONG_MAX, + .freq = 4000, /* 4 KHz */ + .target = { + .uses_mmap = true, + }, }, + .sym_pcnt_filter = 5, }; - char callchain_default_opt[] = "fractal,0.5,callee"; + struct perf_record_opts *opts = &top.record_opts; + struct perf_target *target = &opts->target; const struct option options[] = { OPT_CALLBACK('e', "event", &top.evlist, "event", "event selector. use 'perf list' to list available events", parse_events_option), - OPT_INTEGER('c', "count", &top.default_interval, - "event period to sample"), - OPT_STRING('p', "pid", &top.target.pid, "pid", + OPT_U64('c', "count", &opts->user_interval, "event period to sample"), + OPT_STRING('p', "pid", &target->pid, "pid", "profile events on existing process id"), - OPT_STRING('t', "tid", &top.target.tid, "tid", + OPT_STRING('t', "tid", &target->tid, "tid", "profile events on existing thread id"), - OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide, + OPT_BOOLEAN('a', "all-cpus", &target->system_wide, "system-wide collection from all CPUs"), - OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu", + OPT_STRING('C', "cpu", &target->cpu_list, "cpu", "list of cpus to monitor"), OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, "hide kernel symbols"), - OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"), + OPT_UINTEGER('m', "mmap-pages", &opts->mmap_pages, + "number of mmap data pages"), OPT_INTEGER('r', "realtime", &top.realtime_prio, "collect data with this RT SCHED_FIFO priority"), OPT_INTEGER('d', "delay", &top.delay_secs, @@ -1210,16 +1141,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) "dump the symbol table used for profiling"), OPT_INTEGER('f', "count-filter", &top.count_filter, "only display functions with more events than this"), - OPT_BOOLEAN('g', "group", &top.group, + OPT_BOOLEAN('g', "group", &opts->group, "put the counters into a counter group"), - OPT_BOOLEAN('i', "inherit", &top.inherit, - "child tasks inherit counters"), + OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit, + "child tasks do not inherit counters"), OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", "symbol to annotate"), - OPT_BOOLEAN('z', "zero", &top.zero, - "zero history across updates"), - OPT_INTEGER('F', "freq", &top.freq, - "profile at this frequency"), + OPT_BOOLEAN('z', "zero", &top.zero, "zero history across updates"), + OPT_UINTEGER('F', "freq", &opts->user_freq, "profile at this frequency"), OPT_INTEGER('E', "entries", &top.print_entries, "display this many functions"), OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, @@ -1232,10 +1161,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) "sort by key(s): pid, comm, dso, symbol, parent"), OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, "Show a column with the number of samples"), - OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order", - "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " - "Default: fractal,0.5,callee", &parse_callchain_opt, - callchain_default_opt), + OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, + "mode[,dump_size]", record_callchain_help, + &parse_callchain_opt, "fp"), OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, "Show a column with the sum of periods"), OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", @@ -1250,7 +1178,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) "Display raw encoding of assembly instructions (default)"), OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), - OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"), + OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), OPT_END() }; const char * const top_usage[] = { @@ -1280,27 +1208,27 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) setup_browser(false); - status = perf_target__validate(&top.target); + status = perf_target__validate(target); if (status) { - perf_target__strerror(&top.target, status, errbuf, BUFSIZ); + perf_target__strerror(target, status, errbuf, BUFSIZ); ui__warning("%s", errbuf); } - status = perf_target__parse_uid(&top.target); + status = perf_target__parse_uid(target); if (status) { int saved_errno = errno; - perf_target__strerror(&top.target, status, errbuf, BUFSIZ); + perf_target__strerror(target, status, errbuf, BUFSIZ); ui__error("%s", errbuf); status = -saved_errno; goto out_delete_evlist; } - if (perf_target__none(&top.target)) - top.target.system_wide = true; + if (perf_target__none(target)) + target->system_wide = true; - if (perf_evlist__create_maps(top.evlist, &top.target) < 0) + if (perf_evlist__create_maps(top.evlist, target) < 0) usage_with_options(top_usage, options); if (!top.evlist->nr_entries && @@ -1314,24 +1242,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) if (top.delay_secs < 1) top.delay_secs = 1; + if (opts->user_interval != ULLONG_MAX) + opts->default_interval = opts->user_interval; + if (opts->user_freq != UINT_MAX) + opts->freq = opts->user_freq; + /* * User specified count overrides default frequency. */ - if (top.default_interval) - top.freq = 0; - else if (top.freq) { - top.default_interval = top.freq; + if (opts->default_interval) + opts->freq = 0; + else if (opts->freq) { + opts->default_interval = opts->freq; } else { ui__error("frequency and count are zero, aborting\n"); - exit(EXIT_FAILURE); - } - - list_for_each_entry(pos, &top.evlist->entries, node) { - /* - * Fill in the ones not specifically initialized via -c: - */ - if (!pos->attr.sample_period) - pos->attr.sample_period = top.default_interval; + status = -EINVAL; + goto out_delete_evlist; } top.sym_evsel = perf_evlist__first(top.evlist); diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index 884dde9b9bc1..54d37a4753c5 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c @@ -26,6 +26,8 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) float samples_per_sec = top->samples / top->delay_secs; float ksamples_per_sec = top->kernel_samples / top->delay_secs; float esamples_percent = (100.0 * top->exact_samples) / top->samples; + struct perf_record_opts *opts = &top->record_opts; + struct perf_target *target = &opts->target; size_t ret = 0; if (!perf_guest) { @@ -61,31 +63,31 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) struct perf_evsel *first = perf_evlist__first(top->evlist); ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", (uint64_t)first->attr.sample_period, - top->freq ? "Hz" : ""); + opts->freq ? "Hz" : ""); } ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel)); ret += SNPRINTF(bf + ret, size - ret, "], "); - if (top->target.pid) + if (target->pid) ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", - top->target.pid); - else if (top->target.tid) + target->pid); + else if (target->tid) ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", - top->target.tid); - else if (top->target.uid_str != NULL) + target->tid); + else if (target->uid_str != NULL) ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", - top->target.uid_str); + target->uid_str); else ret += SNPRINTF(bf + ret, size - ret, " (all"); - if (top->target.cpu_list) + if (target->cpu_list) ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", top->evlist->cpus->nr > 1 ? "s" : "", - top->target.cpu_list); + target->cpu_list); else { - if (top->target.tid) + if (target->tid) ret += SNPRINTF(bf + ret, size - ret, ")"); else ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 86ff1b15059b..927c229c2d9a 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -14,7 +14,7 @@ struct perf_session; struct perf_top { struct perf_tool tool; struct perf_evlist *evlist; - struct perf_target target; + struct perf_record_opts record_opts; /* * Symbols will be added here in perf_event__process_sample and will * get out after decayed. @@ -24,15 +24,11 @@ struct perf_top { u64 exact_samples; u64 guest_us_samples, guest_kernel_samples; int print_entries, count_filter, delay_secs; - int freq; bool hide_kernel_symbols, hide_user_symbols, zero; bool use_tui, use_stdio; bool sort_has_symbols; - bool dont_use_callchains; bool kptr_restrict_warned; bool vmlinux_warned; - bool inherit; - bool group; bool sample_id_all_missing; bool exclude_guest_missing; bool dump_symtab; @@ -40,8 +36,6 @@ struct perf_top { struct perf_evsel *sym_evsel; struct perf_session *session; struct winsize winsize; - unsigned int mmap_pages; - int default_interval; int realtime_prio; int sym_pcnt_filter; const char *sym_filter; -- cgit v1.2.3-59-g8ed1b From 9afcf930b1fa1158b0878afeba3eff299300dc65 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 10 Dec 2012 17:29:54 +0900 Subject: perf hists: Exchange order of comparing items when collapsing hists When comparing entries for collapsing put the given entry first, and then the iterated entry. This is not the case of hist_entry__cmp() when called if given sort keys don't require collapsing. So change the order for the sake of consistency. It will be required for matching and/or linking multiple hist entries. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1355128197-18193-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 2 +- tools/perf/util/hist.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index b2e7d39f099b..4dda6f4dc618 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -285,7 +285,7 @@ static void insert_hist_entry_by_name(struct rb_root *root, while (*p != NULL) { parent = *p; iter = rb_entry(parent, struct hist_entry, rb_node); - if (hist_entry__cmp(he, iter) < 0) + if (hist_entry__cmp(iter, he) < 0) p = &(*p)->rb_left; else p = &(*p)->rb_right; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 82df1b26f0d4..3a9ccd09835d 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -285,7 +285,13 @@ static struct hist_entry *add_hist_entry(struct hists *hists, parent = *p; he = rb_entry(parent, struct hist_entry, rb_node_in); - cmp = hist_entry__cmp(entry, he); + /* + * Make sure that it receives arguments in a same order as + * hist_entry__collapse() so that we can use an appropriate + * function when searching an entry regardless which sort + * keys were used. + */ + cmp = hist_entry__cmp(he, entry); if (!cmp) { he_stat__add_period(&he->stat, period); @@ -729,7 +735,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, parent = *p; he = rb_entry(parent, struct hist_entry, rb_node); - cmp = hist_entry__cmp(pair, he); + cmp = hist_entry__cmp(he, pair); if (!cmp) goto out; @@ -759,7 +765,7 @@ static struct hist_entry *hists__find_entry(struct hists *hists, while (n) { struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); - int64_t cmp = hist_entry__cmp(he, iter); + int64_t cmp = hist_entry__cmp(iter, he); if (cmp < 0) n = n->rb_left; -- cgit v1.2.3-59-g8ed1b From ce74f60eab3cc8b7a3b0cb9c29ec9b1e1abac7d2 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 10 Dec 2012 17:29:55 +0900 Subject: perf hists: Link hist entries before inserting to an output tree For matching and/or linking hist entries, they need to be sorted by given sort keys. However current hists__match/link did this on the output trees, so that the entries in the output tree need to be resort before doing it. This looks not so good since we have trees for collecting or collapsing entries before passing them to an output tree and they're already sorted by the given sort keys. Since we don't need to print anything at the time of matching/linking, we can use these internal trees directly instead of bothering with double resort on the output tree. Its only user - at the time of this writing - perf diff can be easily converted to use the internal tree and can save some lines too by getting rid of unnecessary resorting codes. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1355128197-18193-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 65 +++++++++++++---------------------------------- tools/perf/util/hist.c | 49 ++++++++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 60 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 4dda6f4dc618..8b896f5eded0 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -275,43 +275,6 @@ static struct perf_tool tool = { .ordering_requires_timestamps = true, }; -static void insert_hist_entry_by_name(struct rb_root *root, - struct hist_entry *he) -{ - struct rb_node **p = &root->rb_node; - struct rb_node *parent = NULL; - struct hist_entry *iter; - - while (*p != NULL) { - parent = *p; - iter = rb_entry(parent, struct hist_entry, rb_node); - if (hist_entry__cmp(iter, he) < 0) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - rb_link_node(&he->rb_node, parent, p); - rb_insert_color(&he->rb_node, root); -} - -static void hists__name_resort(struct hists *self) -{ - struct rb_root tmp = RB_ROOT; - struct rb_node *next = rb_first(&self->entries); - - while (next != NULL) { - struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); - - next = rb_next(&n->rb_node); - - rb_erase(&n->rb_node, &self->entries); - insert_hist_entry_by_name(&tmp, n); - } - - self->entries = tmp; -} - static struct perf_evsel *evsel_match(struct perf_evsel *evsel, struct perf_evlist *evlist) { @@ -324,30 +287,34 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel, return NULL; } -static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) +static void perf_evlist__collapse_resort(struct perf_evlist *evlist) { struct perf_evsel *evsel; list_for_each_entry(evsel, &evlist->entries, node) { struct hists *hists = &evsel->hists; - hists__output_resort(hists); - - if (name) - hists__name_resort(hists); + hists__collapse_resort(hists); } } static void hists__baseline_only(struct hists *hists) { - struct rb_node *next = rb_first(&hists->entries); + struct rb_root *root; + struct rb_node *next; + + if (sort__need_collapse) + root = &hists->entries_collapsed; + else + root = hists->entries_in; + next = rb_first(root); while (next != NULL) { - struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); + struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in); - next = rb_next(&he->rb_node); + next = rb_next(&he->rb_node_in); if (!hist_entry__next_pair(he)) { - rb_erase(&he->rb_node, &hists->entries); + rb_erase(&he->rb_node_in, root); hist_entry__free(he); } } @@ -471,6 +438,8 @@ static void hists__process(struct hists *old, struct hists *new) else hists__link(new, old); + hists__output_resort(new); + if (sort_compute) { hists__precompute(new); hists__compute_resort(new); @@ -505,8 +474,8 @@ static int __cmd_diff(void) evlist_old = older->evlist; evlist_new = newer->evlist; - perf_evlist__resort_hists(evlist_old, true); - perf_evlist__resort_hists(evlist_new, false); + perf_evlist__collapse_resort(evlist_old); + perf_evlist__collapse_resort(evlist_new); list_for_each_entry(evsel, &evlist_new->entries, node) { struct perf_evsel *evsel_old; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 3a9ccd09835d..8ff3c2f8a5dd 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -726,16 +726,24 @@ void hists__inc_nr_events(struct hists *hists, u32 type) static struct hist_entry *hists__add_dummy_entry(struct hists *hists, struct hist_entry *pair) { - struct rb_node **p = &hists->entries.rb_node; + struct rb_root *root; + struct rb_node **p; struct rb_node *parent = NULL; struct hist_entry *he; int cmp; + if (sort__need_collapse) + root = &hists->entries_collapsed; + else + root = hists->entries_in; + + p = &root->rb_node; + while (*p != NULL) { parent = *p; - he = rb_entry(parent, struct hist_entry, rb_node); + he = rb_entry(parent, struct hist_entry, rb_node_in); - cmp = hist_entry__cmp(he, pair); + cmp = hist_entry__collapse(he, pair); if (!cmp) goto out; @@ -750,8 +758,8 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, if (he) { memset(&he->stat, 0, sizeof(he->stat)); he->hists = hists; - rb_link_node(&he->rb_node, parent, p); - rb_insert_color(&he->rb_node, &hists->entries); + rb_link_node(&he->rb_node_in, parent, p); + rb_insert_color(&he->rb_node_in, root); hists__inc_nr_entries(hists, he); } out: @@ -761,11 +769,16 @@ out: static struct hist_entry *hists__find_entry(struct hists *hists, struct hist_entry *he) { - struct rb_node *n = hists->entries.rb_node; + struct rb_node *n; + + if (sort__need_collapse) + n = hists->entries_collapsed.rb_node; + else + n = hists->entries_in->rb_node; while (n) { - struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); - int64_t cmp = hist_entry__cmp(iter, he); + struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in); + int64_t cmp = hist_entry__collapse(iter, he); if (cmp < 0) n = n->rb_left; @@ -783,11 +796,17 @@ static struct hist_entry *hists__find_entry(struct hists *hists, */ void hists__match(struct hists *leader, struct hists *other) { + struct rb_root *root; struct rb_node *nd; struct hist_entry *pos, *pair; - for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) { - pos = rb_entry(nd, struct hist_entry, rb_node); + if (sort__need_collapse) + root = &leader->entries_collapsed; + else + root = leader->entries_in; + + for (nd = rb_first(root); nd; nd = rb_next(nd)) { + pos = rb_entry(nd, struct hist_entry, rb_node_in); pair = hists__find_entry(other, pos); if (pair) @@ -802,11 +821,17 @@ void hists__match(struct hists *leader, struct hists *other) */ int hists__link(struct hists *leader, struct hists *other) { + struct rb_root *root; struct rb_node *nd; struct hist_entry *pos, *pair; - for (nd = rb_first(&other->entries); nd; nd = rb_next(nd)) { - pos = rb_entry(nd, struct hist_entry, rb_node); + if (sort__need_collapse) + root = &other->entries_collapsed; + else + root = other->entries_in; + + for (nd = rb_first(root); nd; nd = rb_next(nd)) { + pos = rb_entry(nd, struct hist_entry, rb_node_in); if (!hist_entry__has_pairs(pos)) { pair = hists__add_dummy_entry(leader, pos); -- cgit v1.2.3-59-g8ed1b From 66f97ed3ac44c24958171bbc5cc04896147752b7 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 10 Dec 2012 17:29:56 +0900 Subject: perf diff: Use internal rb tree for compute resort There's no reason to run hists_compute_resort() using output tree. Convert it to use internal tree so that it can remove unnecessary _output_resort. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1355128197-18193-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 31 +++++++++++++++++++++---------- tools/perf/util/hist.c | 2 +- tools/perf/util/hist.h | 1 + 3 files changed, 23 insertions(+), 11 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 8b896f5eded0..4af0b580b046 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -414,19 +414,30 @@ static void insert_hist_entry_by_compute(struct rb_root *root, static void hists__compute_resort(struct hists *hists) { - struct rb_root tmp = RB_ROOT; - struct rb_node *next = rb_first(&hists->entries); + struct rb_root *root; + struct rb_node *next; + + if (sort__need_collapse) + root = &hists->entries_collapsed; + else + root = hists->entries_in; + + hists->entries = RB_ROOT; + next = rb_first(root); + + hists->nr_entries = 0; + hists->stats.total_period = 0; + hists__reset_col_len(hists); while (next != NULL) { - struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); + struct hist_entry *he; - next = rb_next(&he->rb_node); + he = rb_entry(next, struct hist_entry, rb_node_in); + next = rb_next(&he->rb_node_in); - rb_erase(&he->rb_node, &hists->entries); - insert_hist_entry_by_compute(&tmp, he, compute); + insert_hist_entry_by_compute(&hists->entries, he, compute); + hists__inc_nr_entries(hists, he); } - - hists->entries = tmp; } static void hists__process(struct hists *old, struct hists *new) @@ -438,11 +449,11 @@ static void hists__process(struct hists *old, struct hists *new) else hists__link(new, old); - hists__output_resort(new); - if (sort_compute) { hists__precompute(new); hists__compute_resort(new); + } else { + hists__output_resort(new); } hists__fprintf(new, true, 0, 0, stdout); diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 8ff3c2f8a5dd..37179af74409 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -251,7 +251,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) return he; } -static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) +void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) { if (!h->filtered) { hists__calc_col_len(hists, h); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 5b3b0075be64..d3664abea6d6 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -96,6 +96,7 @@ void hists__decay_entries_threaded(struct hists *hists, bool zap_user, bool zap_kernel); void hists__output_recalc_col_len(struct hists *hists, int max_rows); +void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); void hists__inc_nr_events(struct hists *self, u32 type); size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); -- cgit v1.2.3-59-g8ed1b From 594ac61ad3be9c80c738a9fe3bb95c05d8d1bae1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 13 Dec 2012 13:13:07 -0300 Subject: perf evsel: Do missing feature fallbacks in just one place Instead of doing it in stat, top, record or any other tool that opens event descriptors. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-vr8hzph83d5t2mdlkf565h84@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 36 ------------------------------------ tools/perf/builtin-stat.c | 30 +++--------------------------- tools/perf/builtin-top.c | 20 -------------------- tools/perf/perf.h | 2 -- tools/perf/util/evsel.c | 31 ++++++++++++++++++++++++++++--- tools/perf/util/top.h | 2 -- 6 files changed, 31 insertions(+), 90 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 028de726b832..a4b97269cfc6 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -234,25 +234,6 @@ static int perf_record__open(struct perf_record *rec) list_for_each_entry(pos, &evlist->entries, node) { struct perf_event_attr *attr = &pos->attr; - /* - * Check if parse_single_tracepoint_event has already asked for - * PERF_SAMPLE_TIME. - * - * XXX this is kludgy but short term fix for problems introduced by - * eac23d1c that broke 'perf script' by having different sample_types - * when using multiple tracepoint events when we use a perf binary - * that tries to use sample_id_all on an older kernel. - * - * We need to move counter creation to perf_session, support - * different sample_types, etc. - */ - bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; - -fallback_missing_features: - if (opts->exclude_guest_missing) - attr->exclude_guest = attr->exclude_host = 0; -retry_sample_id: - attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; try_again: if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { int err = errno; @@ -266,23 +247,6 @@ try_again: " an out-of-range profile CPU?\n"); rc = -err; goto out; - } else if (err == EINVAL) { - if (!opts->exclude_guest_missing && - (attr->exclude_guest || attr->exclude_host)) { - pr_debug("Old kernel, cannot exclude " - "guest or host samples.\n"); - opts->exclude_guest_missing = true; - goto fallback_missing_features; - } else if (!opts->sample_id_all_missing) { - /* - * Old kernel, no attr->sample_id_type_all field - */ - opts->sample_id_all_missing = true; - if (!opts->sample_time && !opts->raw_samples && !time_needed) - perf_evsel__reset_sample_bit(pos, TIME); - - goto retry_sample_id; - } } /* diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index c12655af2b88..ef067c193f93 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -132,8 +132,6 @@ static struct stats walltime_nsecs_stats; static int create_perf_stat_counter(struct perf_evsel *evsel) { struct perf_event_attr *attr = &evsel->attr; - bool exclude_guest_missing = false; - int ret; if (scale) attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | @@ -141,16 +139,8 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) attr->inherit = !no_inherit; -retry: - if (exclude_guest_missing) - evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; - - if (perf_target__has_cpu(&target)) { - ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); - if (ret) - goto check_ret; - return 0; - } + if (perf_target__has_cpu(&target)) + return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); if (!perf_target__has_task(&target) && perf_evsel__is_group_leader(evsel)) { @@ -158,21 +148,7 @@ retry: attr->enable_on_exec = 1; } - ret = perf_evsel__open_per_thread(evsel, evsel_list->threads); - if (!ret) - return 0; - /* fall through */ -check_ret: - if (ret && errno == EINVAL) { - if (!exclude_guest_missing && - (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { - pr_debug("Old kernel, cannot exclude " - "guest or host samples.\n"); - exclude_guest_missing = true; - goto retry; - } - } - return ret; + return perf_evsel__open_per_thread(evsel, evsel_list->threads); } /* diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index b7d2ea62dbc6..74fca619fc4e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -900,12 +900,6 @@ static void perf_top__start_counters(struct perf_top *top) list_for_each_entry(counter, &evlist->entries, node) { struct perf_event_attr *attr = &counter->attr; - -fallback_missing_features: - if (top->exclude_guest_missing) - attr->exclude_guest = attr->exclude_host = 0; -retry_sample_id: - attr->sample_id_all = top->sample_id_all_missing ? 0 : 1; try_again: if (perf_evsel__open(counter, top->evlist->cpus, top->evlist->threads) < 0) { @@ -914,20 +908,6 @@ try_again: if (err == EPERM || err == EACCES) { ui__error_paranoid(); goto out_err; - } else if (err == EINVAL) { - if (!top->exclude_guest_missing && - (attr->exclude_guest || attr->exclude_host)) { - pr_debug("Old kernel, cannot exclude " - "guest or host samples.\n"); - top->exclude_guest_missing = true; - goto fallback_missing_features; - } else if (!top->sample_id_all_missing) { - /* - * Old kernel, no attr->sample_id_type_all field - */ - top->sample_id_all_missing = true; - goto retry_sample_id; - } } /* * If it's cycles then fall back to hrtimer diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 2c340e7da458..7622f15bcfb7 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -237,8 +237,6 @@ struct perf_record_opts { bool raw_samples; bool sample_address; bool sample_time; - bool sample_id_all_missing; - bool exclude_guest_missing; bool period; unsigned int freq; unsigned int mmap_pages; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 7a2a3dc3ff03..ee6ee3f45c2a 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -22,6 +22,11 @@ #include #include "perf_regs.h" +static struct { + bool sample_id_all; + bool exclude_guest; +} perf_missing_features; + #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) static int __perf_evsel__sample_size(u64 sample_type) @@ -463,7 +468,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_event_attr *attr = &evsel->attr; int track = !evsel->idx; /* only the first counter needs these */ - attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; + attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; attr->inherit = !opts->no_inherit; perf_evsel__set_sample_bit(evsel, IP); @@ -513,7 +518,7 @@ void perf_evsel__config(struct perf_evsel *evsel, if (opts->period) perf_evsel__set_sample_bit(evsel, PERIOD); - if (!opts->sample_id_all_missing && + if (!perf_missing_features.sample_id_all && (opts->sample_time || !opts->no_inherit || perf_target__has_cpu(&opts->target))) perf_evsel__set_sample_bit(evsel, TIME); @@ -761,6 +766,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, pid = evsel->cgrp->fd; } +fallback_missing_features: + if (perf_missing_features.exclude_guest) + evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; +retry_sample_id: + if (perf_missing_features.sample_id_all) + evsel->attr.sample_id_all = 0; + for (cpu = 0; cpu < cpus->nr; cpu++) { for (thread = 0; thread < threads->nr; thread++) { @@ -777,13 +789,26 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, group_fd, flags); if (FD(evsel, cpu, thread) < 0) { err = -errno; - goto out_close; + goto try_fallback; } } } return 0; +try_fallback: + if (err != -EINVAL || cpu > 0 || thread > 0) + goto out_close; + + if (!perf_missing_features.exclude_guest && + (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { + perf_missing_features.exclude_guest = true; + goto fallback_missing_features; + } else if (!perf_missing_features.sample_id_all) { + perf_missing_features.sample_id_all = true; + goto retry_sample_id; + } + out_close: do { while (--thread >= 0) { diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 927c229c2d9a..7ebf357dc9e1 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -29,8 +29,6 @@ struct perf_top { bool sort_has_symbols; bool kptr_restrict_warned; bool vmlinux_warned; - bool sample_id_all_missing; - bool exclude_guest_missing; bool dump_symtab; struct hist_entry *sym_filter_entry; struct perf_evsel *sym_evsel; -- cgit v1.2.3-59-g8ed1b From c0a54341c0e89333ef201fc3f3001176962f6121 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 13 Dec 2012 14:16:30 -0300 Subject: perf evsel: Introduce event fallback method The only fallback right now is for HW cpu-cycles -> SW cpu-clock, that was done in the same way in both 'top' and 'record'. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-58l1mgibh9oa9m0pd3fasxa5@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 23 +++-------------------- tools/perf/builtin-top.c | 20 +++----------------- tools/perf/util/evsel.c | 28 ++++++++++++++++++++++++++++ tools/perf/util/evsel.h | 3 +++ 4 files changed, 37 insertions(+), 37 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index a4b97269cfc6..b8d0a39b484e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -224,6 +224,7 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, static int perf_record__open(struct perf_record *rec) { + char msg[128]; struct perf_evsel *pos; struct perf_evlist *evlist = rec->evlist; struct perf_session *session = rec->session; @@ -249,27 +250,9 @@ try_again: goto out; } - /* - * If it's cycles then fall back to hrtimer - * based cpu-clock-tick sw counter, which - * is always available even if no PMU support. - * - * PPC returns ENXIO until 2.6.37 (behavior changed - * with commit b0a873e). - */ - if ((err == ENOENT || err == ENXIO) - && attr->type == PERF_TYPE_HARDWARE - && attr->config == PERF_COUNT_HW_CPU_CYCLES) { - + if (perf_evsel__fallback(pos, err, msg, sizeof(msg))) { if (verbose) - ui__warning("The cycles event is not supported, " - "trying to fall back to cpu-clock-ticks\n"); - attr->type = PERF_TYPE_SOFTWARE; - attr->config = PERF_COUNT_SW_CPU_CLOCK; - if (pos->name) { - free(pos->name); - pos->name = NULL; - } + ui__warning("%s\n", msg); goto try_again; } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 74fca619fc4e..8d41d0b58956 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -892,6 +892,7 @@ static void perf_top__mmap_read(struct perf_top *top) static void perf_top__start_counters(struct perf_top *top) { + char msg[128]; struct perf_evsel *counter; struct perf_evlist *evlist = top->evlist; struct perf_record_opts *opts = &top->record_opts; @@ -909,25 +910,10 @@ try_again: ui__error_paranoid(); goto out_err; } - /* - * If it's cycles then fall back to hrtimer - * based cpu-clock-tick sw counter, which - * is always available even if no PMU support: - */ - if ((err == ENOENT || err == ENXIO) && - (attr->type == PERF_TYPE_HARDWARE) && - (attr->config == PERF_COUNT_HW_CPU_CYCLES)) { + if (perf_evsel__fallback(counter, err, msg, sizeof(msg))) { if (verbose) - ui__warning("Cycles event not supported,\n" - "trying to fall back to cpu-clock-ticks\n"); - - attr->type = PERF_TYPE_SOFTWARE; - attr->config = PERF_COUNT_SW_CPU_CLOCK; - if (counter->name) { - free(counter->name); - counter->name = NULL; - } + ui__warning("%s\n", msg); goto try_again; } diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ee6ee3f45c2a..0c88e5c12dab 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1378,3 +1378,31 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, fputc('\n', fp); return ++printed; } + +bool perf_evsel__fallback(struct perf_evsel *evsel, int err, + char *msg, size_t msgsize) +{ + if ((err == ENOENT || err == ENXIO) && + evsel->attr.type == PERF_TYPE_HARDWARE && + evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) { + /* + * If it's cycles then fall back to hrtimer based + * cpu-clock-tick sw counter, which is always available even if + * no PMU support. + * + * PPC returns ENXIO until 2.6.37 (behavior changed with commit + * b0a873e). + */ + scnprintf(msg, msgsize, "%s", +"The cycles event is not supported, trying to fall back to cpu-clock-ticks"); + + evsel->attr.type = PERF_TYPE_SOFTWARE; + evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; + + free(evsel->name); + evsel->name = NULL; + return true; + } + + return false; +} diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 9cb8a0215711..26d8cfd86e0a 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -251,4 +251,7 @@ struct perf_attr_details { int perf_evsel__fprintf(struct perf_evsel *evsel, struct perf_attr_details *details, FILE *fp); + +bool perf_evsel__fallback(struct perf_evsel *evsel, int err, + char *msg, size_t msgsize); #endif /* __PERF_EVSEL_H */ -- cgit v1.2.3-59-g8ed1b From 56e52e85366717481cde16b3480f015c7eb32ba3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 13 Dec 2012 15:10:58 -0300 Subject: perf evsel: Introduce perf_evsel__open_strerror method That consolidates the error messages in 'record', 'stat' and 'top', that now get a consistent set of messages and allow other tools to use the new method to report problems using whatever UI toolkit. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-1cudb7wl996kz7ilz83ctvhr@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 54 +++++---------------------------------------- tools/perf/builtin-stat.c | 16 +++++--------- tools/perf/builtin-top.c | 34 +++++----------------------- tools/perf/ui/util.c | 11 --------- tools/perf/util/debug.h | 1 - tools/perf/util/evsel.c | 49 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/evsel.h | 3 +++ 7 files changed, 68 insertions(+), 100 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index b8d0a39b484e..de60dd4ee5d3 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -224,7 +224,7 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, static int perf_record__open(struct perf_record *rec) { - char msg[128]; + char msg[512]; struct perf_evsel *pos; struct perf_evlist *evlist = rec->evlist; struct perf_session *session = rec->session; @@ -234,60 +234,18 @@ static int perf_record__open(struct perf_record *rec) perf_evlist__config(evlist, opts); list_for_each_entry(pos, &evlist->entries, node) { - struct perf_event_attr *attr = &pos->attr; try_again: if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { - int err = errno; - - if (err == EPERM || err == EACCES) { - ui__error_paranoid(); - rc = -err; - goto out; - } else if (err == ENODEV && opts->target.cpu_list) { - pr_err("No such device - did you specify" - " an out-of-range profile CPU?\n"); - rc = -err; - goto out; - } - - if (perf_evsel__fallback(pos, err, msg, sizeof(msg))) { + if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { if (verbose) ui__warning("%s\n", msg); goto try_again; } - if (err == ENOENT) { - ui__error("The %s event is not supported.\n", - perf_evsel__name(pos)); - rc = -err; - goto out; - } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) { - ui__error("\'precise\' request may not be supported. " - "Try removing 'p' modifier\n"); - rc = -err; - goto out; - } - - printf("\n"); - error("sys_perf_event_open() syscall returned with %d " - "(%s) for event %s. /bin/dmesg may provide " - "additional information.\n", - err, strerror(err), perf_evsel__name(pos)); - -#if defined(__i386__) || defined(__x86_64__) - if (attr->type == PERF_TYPE_HARDWARE && - err == EOPNOTSUPP) { - pr_err("No hardware sampling interrupt available." - " No APIC? If so then you can boot the kernel" - " with the \"lapic\" boot parameter to" - " force-enable it.\n"); - rc = -err; - goto out; - } -#endif - - pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); - rc = -err; + rc = -errno; + perf_evsel__open_strerror(pos, &opts->target, + errno, msg, sizeof(msg)); + ui__error("%s\n", msg); goto out; } } diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index ef067c193f93..1c2ac148a7d5 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -247,6 +247,7 @@ static int read_counter(struct perf_evsel *counter) static int __run_perf_stat(int argc __maybe_unused, const char **argv) { + char msg[512]; unsigned long long t0, t1; struct perf_evsel *counter; int status = 0; @@ -324,20 +325,13 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv) continue; } - if (errno == EPERM || errno == EACCES) { - error("You may not have permission to collect %sstats.\n" - "\t Consider tweaking" - " /proc/sys/kernel/perf_event_paranoid or running as root.", - target.system_wide ? "system-wide " : ""); - } else { - error("open_counter returned with %d (%s). " - "/bin/dmesg may provide additional information.\n", - errno, strerror(errno)); - } + perf_evsel__open_strerror(counter, &target, + errno, msg, sizeof(msg)); + ui__error("%s\n", msg); + if (child_pid != -1) kill(child_pid, SIGTERM); - pr_err("Not all events could be opened.\n"); return -1; } counter->supported = true; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 8d41d0b58956..f5fd260f7b20 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -892,7 +892,7 @@ static void perf_top__mmap_read(struct perf_top *top) static void perf_top__start_counters(struct perf_top *top) { - char msg[128]; + char msg[512]; struct perf_evsel *counter; struct perf_evlist *evlist = top->evlist; struct perf_record_opts *opts = &top->record_opts; @@ -900,42 +900,18 @@ static void perf_top__start_counters(struct perf_top *top) perf_evlist__config(evlist, opts); list_for_each_entry(counter, &evlist->entries, node) { - struct perf_event_attr *attr = &counter->attr; try_again: if (perf_evsel__open(counter, top->evlist->cpus, top->evlist->threads) < 0) { - int err = errno; - - if (err == EPERM || err == EACCES) { - ui__error_paranoid(); - goto out_err; - } - - if (perf_evsel__fallback(counter, err, msg, sizeof(msg))) { + if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) { if (verbose) ui__warning("%s\n", msg); goto try_again; } - if (err == ENOENT) { - ui__error("The %s event is not supported.\n", - perf_evsel__name(counter)); - goto out_err; - } else if (err == EMFILE) { - ui__error("Too many events are opened.\n" - "Try again after reducing the number of events\n"); - goto out_err; - } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) { - ui__error("\'precise\' request may not be supported. " - "Try removing 'p' modifier\n"); - goto out_err; - } - - ui__error("The sys_perf_event_open() syscall " - "returned with %d (%s). /bin/dmesg " - "may provide additional information.\n" - "No CONFIG_PERF_EVENTS=y kernel support " - "configured?\n", err, strerror(err)); + perf_evsel__open_strerror(counter, &opts->target, + errno, msg, sizeof(msg)); + ui__error("%s\n", msg); goto out_err; } } diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c index 3014a7cd5271..e3e0a963d03a 100644 --- a/tools/perf/ui/util.c +++ b/tools/perf/ui/util.c @@ -52,17 +52,6 @@ int ui__warning(const char *format, ...) return ret; } -int ui__error_paranoid(void) -{ - return ui__error("Permission error - are you root?\n" - "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" - " -1 - Not paranoid at all\n" - " 0 - Disallow raw tracepoint access for unpriv\n" - " 1 - Disallow cpu events for unpriv\n" - " 2 - Disallow kernel profiling for unpriv\n"); -} - - /** * perf_error__register - Register error logging functions * @eops: The pointer to error logging function struct diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 6e2667fb8211..efbd98805ad0 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -16,6 +16,5 @@ void trace_event(union perf_event *event); int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); -int ui__error_paranoid(void); #endif /* __PERF_DEBUG_H */ diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 0c88e5c12dab..e45332d08a58 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1406,3 +1406,52 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, return false; } + +int perf_evsel__open_strerror(struct perf_evsel *evsel, + struct perf_target *target, + int err, char *msg, size_t size) +{ + switch (err) { + case EPERM: + case EACCES: + return scnprintf(msg, size, "%s", + "You may not have permission to collect %sstats.\n" + "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" + " -1 - Not paranoid at all\n" + " 0 - Disallow raw tracepoint access for unpriv\n" + " 1 - Disallow cpu events for unpriv\n" + " 2 - Disallow kernel profiling for unpriv", + target->system_wide ? "system-wide " : ""); + case ENOENT: + return scnprintf(msg, size, "The %s event is not supported.", + perf_evsel__name(evsel)); + case EMFILE: + return scnprintf(msg, size, "%s", + "Too many events are opened.\n" + "Try again after reducing the number of events."); + case ENODEV: + if (target->cpu_list) + return scnprintf(msg, size, "%s", + "No such device - did you specify an out-of-range profile CPU?\n"); + break; + case EOPNOTSUPP: + if (evsel->attr.precise_ip) + return scnprintf(msg, size, "%s", + "\'precise\' request may not be supported. Try removing 'p' modifier."); +#if defined(__i386__) || defined(__x86_64__) + if (evsel->attr.type == PERF_TYPE_HARDWARE) + return scnprintf(msg, size, "%s", + "No hardware sampling interrupt available.\n" + "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it."); +#endif + break; + default: + break; + } + + return scnprintf(msg, size, + "The sys_perf_event_open() syscall returned with %d (%s) for event (%s). \n" + "/bin/dmesg may provide additional information.\n" + "No CONFIG_PERF_EVENTS=y kernel support configured?\n", + err, strerror(err), perf_evsel__name(evsel)); +} diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 26d8cfd86e0a..c68d1b82e843 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -254,4 +254,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, bool perf_evsel__fallback(struct perf_evsel *evsel, int err, char *msg, size_t msgsize); +int perf_evsel__open_strerror(struct perf_evsel *evsel, + struct perf_target *target, + int err, char *msg, size_t size); #endif /* __PERF_EVSEL_H */ -- cgit v1.2.3-59-g8ed1b From 0c6332e9d8b8f38a9d5f0cdd66c5575e76ad8995 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 13 Dec 2012 16:43:04 -0300 Subject: perf python: Fix breakage introduced by the test_attr infrastructure The test_attr infrastructure hooks on the sys_perf_event_open call, checking if a variable is set and if so calling a function to intercept calls and do the checking. But both the variable and the function aren't on objects that are linked on the python binding, breaking it: # perf test -v 15 15: Try 'use perf' in python, checking link problems : --- start --- Traceback (most recent call last): File "", line 1, in ImportError: /home/acme/git/build/perf//python/perf.so: undefined symbol: test_attr__enabled ---- end ---- Try 'use perf' in python, checking link problems: FAILED! # Fix it by moving the variable to one of the linked object files and providing a stub for the function in the python.o object, that is only linked in the python binding. Now 'perf test' is happy again: # perf test 15 15: Try 'use perf' in python, checking link problems : Ok # Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-0rsca2kn44b38rgdpr3tz6n5@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/attr.c | 2 -- tools/perf/util/python.c | 9 +++++++++ tools/perf/util/util.c | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c index 25638a986257..05b5acbabe5d 100644 --- a/tools/perf/tests/attr.c +++ b/tools/perf/tests/attr.c @@ -33,8 +33,6 @@ extern int verbose; -bool test_attr__enabled; - static char *dir; void test_attr__init(void) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index a2657fd96837..925e0c3e6d91 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -1045,3 +1045,12 @@ error: if (PyErr_Occurred()) PyErr_SetString(PyExc_ImportError, "perf: Init failed!"); } + +/* + * Dummy, to avoid dragging all the test_attr infrastructure in the python + * binding. + */ +void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu, + int fd, int group_fd, unsigned long flags) +{ +} diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 5906e8426cc7..252b889ac8c2 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -12,6 +12,8 @@ */ unsigned int page_size; +bool test_attr__enabled; + bool perf_host = true; bool perf_guest = false; -- cgit v1.2.3-59-g8ed1b From 0bd3f0840bf4bc900b4beb8e792ad499b43dad3b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 17 Dec 2012 14:08:36 +0100 Subject: perf tools: Add missing closedir in multi tracepoint processing We don't close 'events' directory when reading multiple tracepoint events. Adding missing closedir. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1355749718-4355-2-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 2d8d53bec17e..d64ff299a3b3 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -408,6 +408,7 @@ static int add_tracepoint_multi(struct list_head **list, int *idx, ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name); } + closedir(evt_dir); return ret; } -- cgit v1.2.3-59-g8ed1b From f35488f97b4b49cb76d87bb7e8da9e93fc70b4e9 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 17 Dec 2012 14:08:37 +0100 Subject: perf tools: Add support for wildcard in tracepoint system name Adding support for wildcards '*?" in the tracepoint system part. It's now possible to open all available tracepoints like: # perf stat -e '*:*' ls You might need to increase limit for open files via ulimit. If ftrace events tracepoints are configured in, the record command fails on above event selection because of them. The stat command disables counters that fails to open, the record command fails completely. We probably want to be smarter here. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1355749718-4355-3-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 51 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d64ff299a3b3..626c120f00da 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -380,8 +380,8 @@ static int add_tracepoint(struct list_head **listp, int *idx, return 0; } -static int add_tracepoint_multi(struct list_head **list, int *idx, - char *sys_name, char *evt_name) +static int add_tracepoint_multi_event(struct list_head **list, int *idx, + char *sys_name, char *evt_name) { char evt_path[MAXPATHLEN]; struct dirent *evt_ent; @@ -412,6 +412,46 @@ static int add_tracepoint_multi(struct list_head **list, int *idx, return ret; } +static int add_tracepoint_event(struct list_head **list, int *idx, + char *sys_name, char *evt_name) +{ + return strpbrk(evt_name, "*?") ? + add_tracepoint_multi_event(list, idx, sys_name, evt_name) : + add_tracepoint(list, idx, sys_name, evt_name); +} + +static int add_tracepoint_multi_sys(struct list_head **list, int *idx, + char *sys_name, char *evt_name) +{ + struct dirent *events_ent; + DIR *events_dir; + int ret = 0; + + events_dir = opendir(tracing_events_path); + if (!events_dir) { + perror("Can't open event dir"); + return -1; + } + + while (!ret && (events_ent = readdir(events_dir))) { + if (!strcmp(events_ent->d_name, ".") + || !strcmp(events_ent->d_name, "..") + || !strcmp(events_ent->d_name, "enable") + || !strcmp(events_ent->d_name, "header_event") + || !strcmp(events_ent->d_name, "header_page")) + continue; + + if (!strglobmatch(events_ent->d_name, sys_name)) + continue; + + ret = add_tracepoint_event(list, idx, events_ent->d_name, + evt_name); + } + + closedir(events_dir); + return ret; +} + int parse_events_add_tracepoint(struct list_head **list, int *idx, char *sys, char *event) { @@ -421,9 +461,10 @@ int parse_events_add_tracepoint(struct list_head **list, int *idx, if (ret) return ret; - return strpbrk(event, "*?") ? - add_tracepoint_multi(list, idx, sys, event) : - add_tracepoint(list, idx, sys, event); + if (strpbrk(sys, "*?")) + return add_tracepoint_multi_sys(list, idx, sys, event); + else + return add_tracepoint_event(list, idx, sys, event); } static int -- cgit v1.2.3-59-g8ed1b From 5323f60c7578e9ddc92d1ca8a2d7b08284624cd1 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 17 Dec 2012 15:38:54 +0900 Subject: perf header: Ensure read/write finished successfully Use readn instead of read and check return value of do_write. Signed-off-by: Namhyung Kim Suggested-by: Arnaldo Carvalho de Melo Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1355726345-29553-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 63 +++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 27 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index b7da4634a047..bb578d2d10f9 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -148,7 +148,7 @@ static char *do_read_string(int fd, struct perf_header *ph) u32 len; char *buf; - sz = read(fd, &len, sizeof(len)); + sz = readn(fd, &len, sizeof(len)); if (sz < (ssize_t)sizeof(len)) return NULL; @@ -159,7 +159,7 @@ static char *do_read_string(int fd, struct perf_header *ph) if (!buf) return NULL; - ret = read(fd, buf, len); + ret = readn(fd, buf, len); if (ret == (ssize_t)len) { /* * strings are padded by zeroes @@ -1051,16 +1051,25 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused, struct perf_pmu *pmu = NULL; off_t offset = lseek(fd, 0, SEEK_CUR); __u32 pmu_num = 0; + int ret; /* write real pmu_num later */ - do_write(fd, &pmu_num, sizeof(pmu_num)); + ret = do_write(fd, &pmu_num, sizeof(pmu_num)); + if (ret < 0) + return ret; while ((pmu = perf_pmu__scan(pmu))) { if (!pmu->name) continue; pmu_num++; - do_write(fd, &pmu->type, sizeof(pmu->type)); - do_write_string(fd, pmu->name); + + ret = do_write(fd, &pmu->type, sizeof(pmu->type)); + if (ret < 0) + return ret; + + ret = do_write_string(fd, pmu->name); + if (ret < 0) + return ret; } if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) { @@ -1209,14 +1218,14 @@ read_event_desc(struct perf_header *ph, int fd) size_t msz; /* number of events */ - ret = read(fd, &nre, sizeof(nre)); + ret = readn(fd, &nre, sizeof(nre)); if (ret != (ssize_t)sizeof(nre)) goto error; if (ph->needs_swap) nre = bswap_32(nre); - ret = read(fd, &sz, sizeof(sz)); + ret = readn(fd, &sz, sizeof(sz)); if (ret != (ssize_t)sizeof(sz)) goto error; @@ -1244,7 +1253,7 @@ read_event_desc(struct perf_header *ph, int fd) * must read entire on-file attr struct to * sync up with layout. */ - ret = read(fd, buf, sz); + ret = readn(fd, buf, sz); if (ret != (ssize_t)sz) goto error; @@ -1253,7 +1262,7 @@ read_event_desc(struct perf_header *ph, int fd) memcpy(&evsel->attr, buf, msz); - ret = read(fd, &nr, sizeof(nr)); + ret = readn(fd, &nr, sizeof(nr)); if (ret != (ssize_t)sizeof(nr)) goto error; @@ -1274,7 +1283,7 @@ read_event_desc(struct perf_header *ph, int fd) evsel->id = id; for (j = 0 ; j < nr; j++) { - ret = read(fd, id, sizeof(*id)); + ret = readn(fd, id, sizeof(*id)); if (ret != (ssize_t)sizeof(*id)) goto error; if (ph->needs_swap) @@ -1506,14 +1515,14 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, while (offset < limit) { ssize_t len; - if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) + if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) return -1; if (header->needs_swap) perf_event_header__bswap(&old_bev.header); len = old_bev.header.size - sizeof(old_bev); - if (read(input, filename, len) != len) + if (readn(input, filename, len) != len) return -1; bev.header = old_bev.header; @@ -1548,14 +1557,14 @@ static int perf_header__read_build_ids(struct perf_header *header, while (offset < limit) { ssize_t len; - if (read(input, &bev, sizeof(bev)) != sizeof(bev)) + if (readn(input, &bev, sizeof(bev)) != sizeof(bev)) goto out; if (header->needs_swap) perf_event_header__bswap(&bev.header); len = bev.header.size - sizeof(bev); - if (read(input, filename, len) != len) + if (readn(input, filename, len) != len) goto out; /* * The a1645ce1 changeset: @@ -1641,7 +1650,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused, size_t ret; u32 nr; - ret = read(fd, &nr, sizeof(nr)); + ret = readn(fd, &nr, sizeof(nr)); if (ret != sizeof(nr)) return -1; @@ -1650,7 +1659,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused, ph->env.nr_cpus_online = nr; - ret = read(fd, &nr, sizeof(nr)); + ret = readn(fd, &nr, sizeof(nr)); if (ret != sizeof(nr)) return -1; @@ -1684,7 +1693,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused, uint64_t mem; size_t ret; - ret = read(fd, &mem, sizeof(mem)); + ret = readn(fd, &mem, sizeof(mem)); if (ret != sizeof(mem)) return -1; @@ -1756,7 +1765,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused, u32 nr, i; struct strbuf sb; - ret = read(fd, &nr, sizeof(nr)); + ret = readn(fd, &nr, sizeof(nr)); if (ret != sizeof(nr)) return -1; @@ -1792,7 +1801,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused char *str; struct strbuf sb; - ret = read(fd, &nr, sizeof(nr)); + ret = readn(fd, &nr, sizeof(nr)); if (ret != sizeof(nr)) return -1; @@ -1813,7 +1822,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused } ph->env.sibling_cores = strbuf_detach(&sb, NULL); - ret = read(fd, &nr, sizeof(nr)); + ret = readn(fd, &nr, sizeof(nr)); if (ret != sizeof(nr)) return -1; @@ -1850,7 +1859,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse struct strbuf sb; /* nr nodes */ - ret = read(fd, &nr, sizeof(nr)); + ret = readn(fd, &nr, sizeof(nr)); if (ret != sizeof(nr)) goto error; @@ -1862,15 +1871,15 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse for (i = 0; i < nr; i++) { /* node number */ - ret = read(fd, &node, sizeof(node)); + ret = readn(fd, &node, sizeof(node)); if (ret != sizeof(node)) goto error; - ret = read(fd, &mem_total, sizeof(u64)); + ret = readn(fd, &mem_total, sizeof(u64)); if (ret != sizeof(u64)) goto error; - ret = read(fd, &mem_free, sizeof(u64)); + ret = readn(fd, &mem_free, sizeof(u64)); if (ret != sizeof(u64)) goto error; @@ -1909,7 +1918,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused u32 type; struct strbuf sb; - ret = read(fd, &pmu_num, sizeof(pmu_num)); + ret = readn(fd, &pmu_num, sizeof(pmu_num)); if (ret != sizeof(pmu_num)) return -1; @@ -1925,7 +1934,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused strbuf_init(&sb, 128); while (pmu_num) { - if (read(fd, &type, sizeof(type)) != sizeof(type)) + if (readn(fd, &type, sizeof(type)) != sizeof(type)) goto error; if (ph->needs_swap) type = bswap_32(type); @@ -2912,7 +2921,7 @@ int perf_event__process_tracing_data(union perf_event *event, session->repipe); padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; - if (read(session->fd, buf, padding) < 0) + if (readn(session->fd, buf, padding) < 0) die("reading input file"); if (session->repipe) { int retw = write(STDOUT_FILENO, buf, padding); -- cgit v1.2.3-59-g8ed1b From 7e383de42565ecb2cf641fff11946f9bc45e8235 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Dec 2012 15:49:27 -0300 Subject: perf record: Don't pass host machine to guest synthesizer We were calling perf_session__process_machines(), that would first pass the struct machine associated with the host to the provided callback, perf_event__synthesize_guest_os() that would test if it was the host and if so wouldn't do anything. Ditch this contraption, just call directly machines__process with the list of guests. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-x65vsxgzg4dvo3zqohtrrb9o@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 11 ++++------- tools/perf/util/session.h | 9 --------- 2 files changed, 4 insertions(+), 16 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index de60dd4ee5d3..69e28950a328 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -328,10 +328,6 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) { int err; struct perf_tool *tool = data; - - if (machine__is_host(machine)) - return; - /* *As for guest kernel when processing subcommand record&report, *we arrange module mmap prior to guest kernel mmap and trigger @@ -574,9 +570,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" "Check /proc/modules permission or run as root.\n"); - if (perf_guest) - perf_session__process_machines(session, tool, - perf_event__synthesize_guest_os); + if (perf_guest) { + machines__process(&session->machines, + perf_event__synthesize_guest_os, tool); + } if (!opts->target.system_wide) err = perf_event__synthesize_thread_map(tool, evsel_list->threads, diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 8c2302504199..426ca0c3c5b6 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -101,15 +101,6 @@ struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t p return machines__findnew(&self->machines, pid); } -static inline -void perf_session__process_machines(struct perf_session *self, - struct perf_tool *tool, - machine__process_t process) -{ - process(&self->host_machine, tool); - return machines__process(&self->machines, process, tool); -} - struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); size_t perf_session__fprintf(struct perf_session *self, FILE *fp); -- cgit v1.2.3-59-g8ed1b From 52168eea32cc01377b31c1ca9a759eae06830ea0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Dec 2012 16:02:17 -0300 Subject: perf hists: Rename hists__fprintf_nr_events to events_stats__fprintf As this function deals exclusively with hists->stats. Preparatory patch for removing the by now needless session->hists, that should be just session->stats. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-be0o8si9f1z40cwoa534f7me@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/stdio/hist.c | 6 +++--- tools/perf/util/hist.h | 2 +- tools/perf/util/session.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 0eae3b2c32f2..f9798298e3e0 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -459,7 +459,7 @@ out: return ret; } -size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) +size_t events_stats__fprintf(struct events_stats *stats, FILE *fp) { int i; size_t ret = 0; @@ -467,7 +467,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { const char *name; - if (hists->stats.nr_events[i] == 0) + if (stats->nr_events[i] == 0) continue; name = perf_event__name(i); @@ -475,7 +475,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) continue; ret += fprintf(fp, "%16s events: %10d\n", name, - hists->stats.nr_events[i]); + stats->nr_events[i]); } return ret; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index d3664abea6d6..cb6533b2977a 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -98,7 +98,7 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows); void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); void hists__inc_nr_events(struct hists *self, u32 type); -size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); +size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, int max_cols, FILE *fp); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 76d6e257b8a4..6e8dd2abcf0b 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1353,11 +1353,11 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) struct perf_evsel *pos; size_t ret = fprintf(fp, "Aggregated stats:\n"); - ret += hists__fprintf_nr_events(&session->hists, fp); + ret += events_stats__fprintf(&session->hists.stats, fp); list_for_each_entry(pos, &session->evlist->entries, node) { ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); - ret += hists__fprintf_nr_events(&pos->hists, fp); + ret += events_stats__fprintf(&pos->hists.stats, fp); } return ret; -- cgit v1.2.3-59-g8ed1b From 28a6b6aa54878a6a239e901698b3fc111bbcc54f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Dec 2012 16:24:46 -0300 Subject: perf session: There is no need for a per session hists instance It was being used just for its stats member, so ditch session->hists and use just what is needed, session->stats. This completes the move support multiple events in the hists layer, the last user of session->hists was 'perf diff' but Jiri Olsa has fixed that some time ago. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-pimk92kek8kcp4dmb1jakoro@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-sched.c | 6 +++--- tools/perf/builtin-top.c | 4 ++-- tools/perf/util/hist.c | 9 +++++++-- tools/perf/util/hist.h | 1 + tools/perf/util/session.c | 41 ++++++++++++++++++++--------------------- tools/perf/util/session.h | 6 +----- 6 files changed, 34 insertions(+), 33 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index cc28b85dabd5..138229439a93 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1475,9 +1475,9 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy, goto out_delete; } - sched->nr_events = session->hists.stats.nr_events[0]; - sched->nr_lost_events = session->hists.stats.total_lost; - sched->nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; + sched->nr_events = session->stats.nr_events[0]; + sched->nr_lost_events = session->stats.total_lost; + sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST]; } if (destroy) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index f5fd260f7b20..996b10c702ba 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -728,7 +728,7 @@ static void perf_event__process_sample(struct perf_tool *tool, if (!machine) { pr_err("%u unprocessable samples recorded.\n", - top->session->hists.stats.nr_unprocessable_samples++); + top->session->stats.nr_unprocessable_samples++); return; } @@ -878,7 +878,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) hists__inc_nr_events(&evsel->hists, event->header.type); machine__process_event(machine, event); } else - ++session->hists.stats.nr_unknown_events; + ++session->stats.nr_unknown_events; } } diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 37179af74409..965ebf948f2f 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -717,10 +717,15 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize) return symbol__annotate(he->ms.sym, he->ms.map, privsize); } +void events_stats__inc(struct events_stats *stats, u32 type) +{ + ++stats->nr_events[0]; + ++stats->nr_events[type]; +} + void hists__inc_nr_events(struct hists *hists, u32 type) { - ++hists->stats.nr_events[0]; - ++hists->stats.nr_events[type]; + events_stats__inc(&hists->stats, type); } static struct hist_entry *hists__add_dummy_entry(struct hists *hists, diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index cb6533b2977a..38624686ee9a 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -98,6 +98,7 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows); void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); void hists__inc_nr_events(struct hists *self, u32 type); +void events_stats__inc(struct events_stats *stats, u32 type); size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 6e8dd2abcf0b..b0bcc328d1fb 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -133,7 +133,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, INIT_LIST_HEAD(&self->ordered_samples.sample_cache); INIT_LIST_HEAD(&self->ordered_samples.to_free); machine__init(&self->host_machine, "", HOST_KERNEL_ID); - hists__init(&self->hists); if (mode == O_RDONLY) { if (perf_session__open(self, force) < 0) @@ -863,11 +862,11 @@ static int perf_session_deliver_event(struct perf_session *session, case PERF_RECORD_SAMPLE: dump_sample(evsel, event, sample); if (evsel == NULL) { - ++session->hists.stats.nr_unknown_id; + ++session->stats.nr_unknown_id; return 0; } if (machine == NULL) { - ++session->hists.stats.nr_unprocessable_samples; + ++session->stats.nr_unprocessable_samples; return 0; } return tool->sample(tool, event, sample, evsel, machine); @@ -881,7 +880,7 @@ static int perf_session_deliver_event(struct perf_session *session, return tool->exit(tool, event, sample, machine); case PERF_RECORD_LOST: if (tool->lost == perf_event__process_lost) - session->hists.stats.total_lost += event->lost.lost; + session->stats.total_lost += event->lost.lost; return tool->lost(tool, event, sample, machine); case PERF_RECORD_READ: return tool->read(tool, event, sample, evsel, machine); @@ -890,7 +889,7 @@ static int perf_session_deliver_event(struct perf_session *session, case PERF_RECORD_UNTHROTTLE: return tool->unthrottle(tool, event, sample, machine); default: - ++session->hists.stats.nr_unknown_events; + ++session->stats.nr_unknown_events; return -1; } } @@ -904,8 +903,8 @@ static int perf_session__preprocess_sample(struct perf_session *session, if (!ip_callchain__valid(sample->callchain, event)) { pr_debug("call-chain problem with event, skipping it.\n"); - ++session->hists.stats.nr_invalid_chains; - session->hists.stats.total_invalid_chains += sample->period; + ++session->stats.nr_invalid_chains; + session->stats.total_invalid_chains += sample->period; return -EINVAL; } return 0; @@ -963,7 +962,7 @@ static int perf_session__process_event(struct perf_session *session, if (event->header.type >= PERF_RECORD_HEADER_MAX) return -EINVAL; - hists__inc_nr_events(&session->hists, event->header.type); + events_stats__inc(&session->stats, event->header.type); if (event->header.type >= PERF_RECORD_USER_TYPE_START) return perf_session__process_user_event(session, event, tool, file_offset); @@ -1018,39 +1017,39 @@ static void perf_session__warn_about_errors(const struct perf_session *session, const struct perf_tool *tool) { if (tool->lost == perf_event__process_lost && - session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { + session->stats.nr_events[PERF_RECORD_LOST] != 0) { ui__warning("Processed %d events and lost %d chunks!\n\n" "Check IO/CPU overload!\n\n", - session->hists.stats.nr_events[0], - session->hists.stats.nr_events[PERF_RECORD_LOST]); + session->stats.nr_events[0], + session->stats.nr_events[PERF_RECORD_LOST]); } - if (session->hists.stats.nr_unknown_events != 0) { + if (session->stats.nr_unknown_events != 0) { ui__warning("Found %u unknown events!\n\n" "Is this an older tool processing a perf.data " "file generated by a more recent tool?\n\n" "If that is not the case, consider " "reporting to linux-kernel@vger.kernel.org.\n\n", - session->hists.stats.nr_unknown_events); + session->stats.nr_unknown_events); } - if (session->hists.stats.nr_unknown_id != 0) { + if (session->stats.nr_unknown_id != 0) { ui__warning("%u samples with id not present in the header\n", - session->hists.stats.nr_unknown_id); + session->stats.nr_unknown_id); } - if (session->hists.stats.nr_invalid_chains != 0) { + if (session->stats.nr_invalid_chains != 0) { ui__warning("Found invalid callchains!\n\n" "%u out of %u events were discarded for this reason.\n\n" "Consider reporting to linux-kernel@vger.kernel.org.\n\n", - session->hists.stats.nr_invalid_chains, - session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); + session->stats.nr_invalid_chains, + session->stats.nr_events[PERF_RECORD_SAMPLE]); } - if (session->hists.stats.nr_unprocessable_samples != 0) { + if (session->stats.nr_unprocessable_samples != 0) { ui__warning("%u unprocessable samples recorded.\n" "Do you have a KVM guest running and not using 'perf kvm'?\n", - session->hists.stats.nr_unprocessable_samples); + session->stats.nr_unprocessable_samples); } } @@ -1353,7 +1352,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) struct perf_evsel *pos; size_t ret = fprintf(fp, "Aggregated stats:\n"); - ret += events_stats__fprintf(&session->hists.stats, fp); + ret += events_stats__fprintf(&session->stats, fp); list_for_each_entry(pos, &session->evlist->entries, node) { ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 426ca0c3c5b6..57066cb867a6 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -34,11 +34,7 @@ struct perf_session { struct rb_root machines; struct perf_evlist *evlist; struct pevent *pevent; - /* - * FIXME: Need to split this up further, we need global - * stats + per event stats. - */ - struct hists hists; + struct events_stats stats; int fd; bool fd_pipe; bool repipe; -- cgit v1.2.3-59-g8ed1b From 876650e6c3209861a8949111140d805b3440951f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Dec 2012 19:15:48 -0300 Subject: perf machine: Introduce struct machines That consolidates the grouping of host + guests, isolating a bit more of functionality now centered on 'perf_session' that can be used independently in tools that don't need a 'perf_session' instance, but needs to have all the thread/map/symbol machinery. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-c700rsiphpmzv8klogojpfut@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 4 +-- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-top.c | 4 +-- tools/perf/tests/hists_link.c | 17 +++++------- tools/perf/util/header.c | 12 ++++---- tools/perf/util/machine.c | 64 ++++++++++++++++++++++++++++--------------- tools/perf/util/machine.h | 32 ++++++++++++++-------- tools/perf/util/session.c | 30 ++++++++------------ tools/perf/util/session.h | 11 ++------ 9 files changed, 95 insertions(+), 81 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 69e28950a328..a0b2427b509d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -571,8 +571,8 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) "Check /proc/modules permission or run as root.\n"); if (perf_guest) { - machines__process(&session->machines, - perf_event__synthesize_guest_os, tool); + machines__process_guests(&session->machines, + perf_event__synthesize_guest_os, tool); } if (!opts->target.system_wide) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 5134acf1c39a..13cdf61c4f82 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -372,7 +372,7 @@ static int __cmd_report(struct perf_report *rep) if (ret) goto out_delete; - kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION]; + kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION]; kernel_kmap = map__kmap(kernel_map); if (kernel_map == NULL || (kernel_map->dso->hit && diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 996b10c702ba..e0ecebdde3fe 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -966,10 +966,10 @@ static int __cmd_top(struct perf_top *top) if (perf_target__has_task(&opts->target)) perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, perf_event__process, - &top->session->host_machine); + &top->session->machines.host); else perf_event__synthesize_threads(&top->tool, perf_event__process, - &top->session->host_machine); + &top->session->machines.host); perf_top__start_counters(top); top->session->evlist = top->evlist; perf_session__set_id_hdr_size(top->session); diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 0f1aae3b8a99..27860a082381 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -75,13 +75,11 @@ static struct { { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) }, }; -static struct machine *setup_fake_machine(void) +static struct machine *setup_fake_machine(struct machines *machines) { - struct rb_root machine_root = RB_ROOT; - struct machine *machine; + struct machine *machine = machines__find(machines, HOST_KERNEL_ID); size_t i; - machine = machines__findnew(&machine_root, HOST_KERNEL_ID); if (machine == NULL) { pr_debug("Not enough memory for machine setup\n"); return NULL; @@ -435,6 +433,7 @@ static void print_hists(struct hists *hists) int test__hists_link(void) { int err = -1; + struct machines machines; struct machine *machine = NULL; struct perf_evsel *evsel, *first; struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); @@ -452,8 +451,10 @@ int test__hists_link(void) /* default sort order (comm,dso,sym) will be used */ setup_sorting(NULL, NULL); + machines__init(&machines); + /* setup threads/dso/map/symbols also */ - machine = setup_fake_machine(); + machine = setup_fake_machine(&machines); if (!machine) goto out; @@ -492,11 +493,7 @@ int test__hists_link(void) out: /* tear down everything */ perf_evlist__delete(evlist); - - if (machine) { - machine__delete_threads(machine); - machine__delete(machine); - } + machines__exit(&machines); return err; } diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index bb578d2d10f9..fccd69dbbbb9 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -287,12 +287,12 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd) struct perf_session *session = container_of(header, struct perf_session, header); struct rb_node *nd; - int err = machine__write_buildid_table(&session->host_machine, fd); + int err = machine__write_buildid_table(&session->machines.host, fd); if (err) return err; - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); err = machine__write_buildid_table(pos, fd); if (err) @@ -448,9 +448,9 @@ static int perf_session__cache_build_ids(struct perf_session *session) if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) return -1; - ret = machine__cache_build_ids(&session->host_machine, debugdir); + ret = machine__cache_build_ids(&session->machines.host, debugdir); - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret |= machine__cache_build_ids(pos, debugdir); } @@ -467,9 +467,9 @@ static bool machine__read_build_ids(struct machine *machine, bool with_hits) static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) { struct rb_node *nd; - bool ret = machine__read_build_ids(&session->host_machine, with_hits); + bool ret = machine__read_build_ids(&session->machines.host, with_hits); - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret |= machine__read_build_ids(pos, with_hits); } diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 71fa90391fe4..efdb38e65a92 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -91,10 +91,22 @@ void machine__delete(struct machine *machine) free(machine); } -struct machine *machines__add(struct rb_root *machines, pid_t pid, +void machines__init(struct machines *machines) +{ + machine__init(&machines->host, "", HOST_KERNEL_ID); + machines->guests = RB_ROOT; +} + +void machines__exit(struct machines *machines) +{ + machine__exit(&machines->host); + /* XXX exit guest */ +} + +struct machine *machines__add(struct machines *machines, pid_t pid, const char *root_dir) { - struct rb_node **p = &machines->rb_node; + struct rb_node **p = &machines->guests.rb_node; struct rb_node *parent = NULL; struct machine *pos, *machine = malloc(sizeof(*machine)); @@ -116,18 +128,21 @@ struct machine *machines__add(struct rb_root *machines, pid_t pid, } rb_link_node(&machine->rb_node, parent, p); - rb_insert_color(&machine->rb_node, machines); + rb_insert_color(&machine->rb_node, &machines->guests); return machine; } -struct machine *machines__find(struct rb_root *machines, pid_t pid) +struct machine *machines__find(struct machines *machines, pid_t pid) { - struct rb_node **p = &machines->rb_node; + struct rb_node **p = &machines->guests.rb_node; struct rb_node *parent = NULL; struct machine *machine; struct machine *default_machine = NULL; + if (pid == HOST_KERNEL_ID) + return &machines->host; + while (*p != NULL) { parent = *p; machine = rb_entry(parent, struct machine, rb_node); @@ -144,7 +159,7 @@ struct machine *machines__find(struct rb_root *machines, pid_t pid) return default_machine; } -struct machine *machines__findnew(struct rb_root *machines, pid_t pid) +struct machine *machines__findnew(struct machines *machines, pid_t pid) { char path[PATH_MAX]; const char *root_dir = ""; @@ -178,12 +193,12 @@ out: return machine; } -void machines__process(struct rb_root *machines, - machine__process_t process, void *data) +void machines__process_guests(struct machines *machines, + machine__process_t process, void *data) { struct rb_node *nd; - for (nd = rb_first(machines); nd; nd = rb_next(nd)) { + for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); process(pos, data); } @@ -203,12 +218,14 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size) return bf; } -void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size) +void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) { struct rb_node *node; struct machine *machine; - for (node = rb_first(machines); node; node = rb_next(node)) { + machines->host.id_hdr_size = id_hdr_size; + + for (node = rb_first(&machines->guests); node; node = rb_next(node)) { machine = rb_entry(node, struct machine, rb_node); machine->id_hdr_size = id_hdr_size; } @@ -313,12 +330,13 @@ struct map *machine__new_module(struct machine *machine, u64 start, return map; } -size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) +size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) { struct rb_node *nd; - size_t ret = 0; + size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) + + __dsos__fprintf(&machines->host.user_dsos, fp); - for (nd = rb_first(machines); nd; nd = rb_next(nd)) { + for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret += __dsos__fprintf(&pos->kernel_dsos, fp); ret += __dsos__fprintf(&pos->user_dsos, fp); @@ -334,13 +352,13 @@ size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm); } -size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, +size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm) { struct rb_node *nd; - size_t ret = 0; + size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm); - for (nd = rb_first(machines); nd; nd = rb_next(nd)) { + for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); } @@ -511,7 +529,7 @@ void machine__destroy_kernel_maps(struct machine *machine) } } -int machines__create_guest_kernel_maps(struct rb_root *machines) +int machines__create_guest_kernel_maps(struct machines *machines) { int ret = 0; struct dirent **namelist = NULL; @@ -560,20 +578,22 @@ failure: return ret; } -void machines__destroy_guest_kernel_maps(struct rb_root *machines) +void machines__destroy_kernel_maps(struct machines *machines) { - struct rb_node *next = rb_first(machines); + struct rb_node *next = rb_first(&machines->guests); + + machine__destroy_kernel_maps(&machines->host); while (next) { struct machine *pos = rb_entry(next, struct machine, rb_node); next = rb_next(&pos->rb_node); - rb_erase(&pos->rb_node, machines); + rb_erase(&pos->rb_node, &machines->guests); machine__delete(pos); } } -int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) +int machines__create_kernel_maps(struct machines *machines, pid_t pid) { struct machine *machine = machines__findnew(machines, pid); diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index e11236878ec1..5ac5892f2326 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -47,16 +47,24 @@ int machine__process_event(struct machine *machine, union perf_event *event); typedef void (*machine__process_t)(struct machine *machine, void *data); -void machines__process(struct rb_root *machines, - machine__process_t process, void *data); +struct machines { + struct machine host; + struct rb_root guests; +}; + +void machines__init(struct machines *machines); +void machines__exit(struct machines *machines); + +void machines__process_guests(struct machines *machines, + machine__process_t process, void *data); -struct machine *machines__add(struct rb_root *machines, pid_t pid, +struct machine *machines__add(struct machines *machines, pid_t pid, const char *root_dir); -struct machine *machines__find_host(struct rb_root *machines); -struct machine *machines__find(struct rb_root *machines, pid_t pid); -struct machine *machines__findnew(struct rb_root *machines, pid_t pid); +struct machine *machines__find_host(struct machines *machines); +struct machine *machines__find(struct machines *machines, pid_t pid); +struct machine *machines__findnew(struct machines *machines, pid_t pid); -void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size); +void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size); char *machine__mmap_name(struct machine *machine, char *bf, size_t size); int machine__init(struct machine *machine, const char *root_dir, pid_t pid); @@ -132,17 +140,17 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type, size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm); -size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); -size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, +size_t machines__fprintf_dsos(struct machines *machines, FILE *fp); +size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm); void machine__destroy_kernel_maps(struct machine *machine); int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); int machine__create_kernel_maps(struct machine *machine); -int machines__create_kernel_maps(struct rb_root *machines, pid_t pid); -int machines__create_guest_kernel_maps(struct rb_root *machines); -void machines__destroy_guest_kernel_maps(struct rb_root *machines); +int machines__create_kernel_maps(struct machines *machines, pid_t pid); +int machines__create_guest_kernel_maps(struct machines *machines); +void machines__destroy_kernel_maps(struct machines *machines); size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index b0bcc328d1fb..046b057c8f7f 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -86,13 +86,12 @@ void perf_session__set_id_hdr_size(struct perf_session *session) { u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); - session->host_machine.id_hdr_size = id_hdr_size; machines__set_id_hdr_size(&session->machines, id_hdr_size); } int perf_session__create_kernel_maps(struct perf_session *self) { - int ret = machine__create_kernel_maps(&self->host_machine); + int ret = machine__create_kernel_maps(&self->machines.host); if (ret >= 0) ret = machines__create_guest_kernel_maps(&self->machines); @@ -101,8 +100,7 @@ int perf_session__create_kernel_maps(struct perf_session *self) static void perf_session__destroy_kernel_maps(struct perf_session *self) { - machine__destroy_kernel_maps(&self->host_machine); - machines__destroy_guest_kernel_maps(&self->machines); + machines__destroy_kernel_maps(&self->machines); } struct perf_session *perf_session__new(const char *filename, int mode, @@ -127,12 +125,11 @@ struct perf_session *perf_session__new(const char *filename, int mode, goto out; memcpy(self->filename, filename, len); - self->machines = RB_ROOT; self->repipe = repipe; INIT_LIST_HEAD(&self->ordered_samples.samples); INIT_LIST_HEAD(&self->ordered_samples.sample_cache); INIT_LIST_HEAD(&self->ordered_samples.to_free); - machine__init(&self->host_machine, "", HOST_KERNEL_ID); + machines__init(&self->machines); if (mode == O_RDONLY) { if (perf_session__open(self, force) < 0) @@ -162,12 +159,12 @@ out_delete: static void perf_session__delete_dead_threads(struct perf_session *session) { - machine__delete_dead_threads(&session->host_machine); + machine__delete_dead_threads(&session->machines.host); } static void perf_session__delete_threads(struct perf_session *session) { - machine__delete_threads(&session->host_machine); + machine__delete_threads(&session->machines.host); } static void perf_session_env__delete(struct perf_session_env *env) @@ -192,7 +189,7 @@ void perf_session__delete(struct perf_session *self) perf_session__delete_dead_threads(self); perf_session__delete_threads(self); perf_session_env__delete(&self->header.env); - machine__exit(&self->host_machine); + machines__exit(&self->machines); close(self->fd); free(self); vdso__exit(); @@ -998,7 +995,7 @@ void perf_event_header__bswap(struct perf_event_header *self) struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) { - return machine__findnew_thread(&session->host_machine, pid); + return machine__findnew_thread(&session->machines.host, pid); } static struct thread *perf_session__register_idle_thread(struct perf_session *self) @@ -1335,16 +1332,13 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps, size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) { - return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) + - __dsos__fprintf(&self->host_machine.user_dsos, fp) + - machines__fprintf_dsos(&self->machines, fp); + return machines__fprintf_dsos(&self->machines, fp); } size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm) { - size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, skip, parm); - return ret + machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm); + return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm); } size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) @@ -1368,7 +1362,7 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp) * FIXME: Here we have to actually print all the machines in this * session, not just the host... */ - return machine__fprintf(&session->host_machine, fp); + return machine__fprintf(&session->machines.host, fp); } void perf_session__remove_thread(struct perf_session *session, @@ -1377,10 +1371,10 @@ void perf_session__remove_thread(struct perf_session *session, /* * FIXME: This one makes no sense, we need to remove the thread from * the machine it belongs to, perf_session can have many machines, so - * doing it always on ->host_machine is wrong. Fix when auditing all + * doing it always on ->machines.host is wrong. Fix when auditing all * the 'perf kvm' code. */ - machine__remove_thread(&session->host_machine, th); + machine__remove_thread(&session->machines.host, th); } struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 57066cb867a6..de4e68716626 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -30,8 +30,7 @@ struct ordered_samples { struct perf_session { struct perf_header header; unsigned long size; - struct machine host_machine; - struct rb_root machines; + struct machines machines; struct perf_evlist *evlist; struct pevent *pevent; struct events_stats stats; @@ -49,7 +48,7 @@ struct perf_tool; struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe, struct perf_tool *tool); -void perf_session__delete(struct perf_session *self); +void perf_session__delete(struct perf_session *session); void perf_event_header__bswap(struct perf_event_header *self); @@ -78,22 +77,18 @@ void perf_session__remove_thread(struct perf_session *self, struct thread *th); static inline struct machine *perf_session__find_host_machine(struct perf_session *self) { - return &self->host_machine; + return &self->machines.host; } static inline struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) { - if (pid == HOST_KERNEL_ID) - return &self->host_machine; return machines__find(&self->machines, pid); } static inline struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid) { - if (pid == HOST_KERNEL_ID) - return &self->host_machine; return machines__findnew(&self->machines, pid); } -- cgit v1.2.3-59-g8ed1b From 34ba5122bf198c9cdfcbecc9b23eaa414244a3f6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 Dec 2012 09:04:24 -0300 Subject: perf machine: Simplify accessing the host machine It is always there, no sense in calling a function named "perf_session__find_host_machine". Also no sense in checking if that function return is NULL, so ditch needless error handling. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-a6a3zx3afbrxo8p2zqm5mxo8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kmem.c | 7 +------ tools/perf/builtin-record.c | 7 +------ tools/perf/builtin-top.c | 4 ++-- tools/perf/util/session.c | 2 +- tools/perf/util/session.h | 6 ------ 5 files changed, 5 insertions(+), 21 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 0b4b796167be..9fddca749ca2 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -340,7 +340,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session, int n_lines, int is_caller) { struct rb_node *next; - struct machine *machine; + struct machine *machine = &session->machines.host; printf("%.102s\n", graph_dotted_line); printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); @@ -349,11 +349,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session, next = rb_first(root); - machine = perf_session__find_host_machine(session); - if (!machine) { - pr_err("__print_result: couldn't find kernel information\n"); - return; - } while (next && n_lines--) { struct alloc_stat *data = rb_entry(next, struct alloc_stat, node); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index a0b2427b509d..2ac690cad411 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -512,12 +512,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) rec->post_processing_offset = lseek(output, 0, SEEK_CUR); - machine = perf_session__find_host_machine(session); - if (!machine) { - pr_err("Couldn't find native kernel information.\n"); - err = -1; - goto out_delete_session; - } + machine = &session->machines.host; if (opts->pipe_output) { err = perf_event__synthesize_attrs(tool, session, diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e0ecebdde3fe..bc788126397b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -847,13 +847,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) ++top->us_samples; if (top->hide_user_symbols) continue; - machine = perf_session__find_host_machine(session); + machine = &session->machines.host; break; case PERF_RECORD_MISC_KERNEL: ++top->kernel_samples; if (top->hide_kernel_symbols) continue; - machine = perf_session__find_host_machine(session); + machine = &session->machines.host; break; case PERF_RECORD_MISC_GUEST_KERNEL: ++top->guest_kernel_samples; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 046b057c8f7f..bd85280bb6e8 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -821,7 +821,7 @@ static struct machine * return perf_session__findnew_machine(session, pid); } - return perf_session__find_host_machine(session); + return &session->machines.host; } static int perf_session_deliver_event(struct perf_session *session, diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index de4e68716626..b5c0847edfa9 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -74,12 +74,6 @@ int perf_session__create_kernel_maps(struct perf_session *self); void perf_session__set_id_hdr_size(struct perf_session *session); void perf_session__remove_thread(struct perf_session *self, struct thread *th); -static inline -struct machine *perf_session__find_host_machine(struct perf_session *self) -{ - return &self->machines.host; -} - static inline struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) { -- cgit v1.2.3-59-g8ed1b From 53985a7bfa7b947c91f35c6adcdc9cacc6fef07f Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 20 Dec 2012 14:11:20 -0500 Subject: perf tools: remove redundant checks from _sort__sym_cmp We already check that sym_l and sum_r are non-NULLs, no need to do it twice. Signed-off-by: Sasha Levin Acked-by: Namhyung Kim Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1356030701-16284-12-git-send-email-sasha.levin@oracle.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index cfd1c0feb32d..dbaded90312c 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -143,10 +143,8 @@ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, if (sym_l == sym_r) return 0; - if (sym_l) - ip_l = sym_l->start; - if (sym_r) - ip_r = sym_r->start; + ip_l = sym_l->start; + ip_r = sym_r->start; return (int64_t)(ip_r - ip_l); } -- cgit v1.2.3-59-g8ed1b From a65c23420668f7112395abf9c6f22c6450567bf0 Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Tue, 25 Dec 2012 17:23:39 +0100 Subject: perf tools: Fix possible (unlikely) buffer overflow cppcheck reported: [tools/perf/util/sysfs.c:50]: (error) Width 4096 given in format string (no. 1) is larger than destination buffer 'sysfs_mountpoint[4096]', use %4095s to prevent overflowing it -> All other places in the kernel that use STR(PATH_MAX) have a buffer size of PATH_MAX + 1. Signed-off-by: Thomas Jarosch Link: http://lkml.kernel.org/r/50D9D30B.8090002@intra2net.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c index 48c6902e749f..f71e9eafe15a 100644 --- a/tools/perf/util/sysfs.c +++ b/tools/perf/util/sysfs.c @@ -8,7 +8,7 @@ static const char * const sysfs_known_mountpoints[] = { }; static int sysfs_found; -char sysfs_mountpoint[PATH_MAX]; +char sysfs_mountpoint[PATH_MAX + 1]; static int sysfs_valid_mountpoint(const char *sysfs) { -- cgit v1.2.3-59-g8ed1b From eec185ab603fab3b7b5021e840cf4b282c4c7e6b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 28 Dec 2012 16:16:49 +0900 Subject: perf symbols: Include elf.h header regardless LIBELF_SUPPORT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The elf.h header file is used for NO_LIBELF build too so it should be included anyway. Also remove duplicated include of the header file in symbol-*.c. This patch fixes following build error on NO_LIBELF build: CC tests/hists_link.o tests/hists_link.c: In function ‘setup_fake_machine’: tests/hists_link.c:132:8: error: ‘STB_GLOBAL’ undeclared (first use in this function) tests/hists_link.c:132:8: note: each undeclared identifier is reported only once for each function it appears in Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1356679009-32122-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol-elf.c | 3 --- tools/perf/util/symbol-minimal.c | 1 - tools/perf/util/symbol.h | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index f63557b59c06..54efcb5659ac 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1,6 +1,3 @@ -#include -#include -#include #include #include #include diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 259f8f2ea9c9..a7390cde63bc 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -1,6 +1,5 @@ #include "symbol.h" -#include #include #include #include diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index ec7b2405c377..d97377ac2f16 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -16,8 +16,8 @@ #ifdef LIBELF_SUPPORT #include #include -#include #endif +#include #include "dso.h" -- cgit v1.2.3-59-g8ed1b From d0528b5d71faf612014dd7672e44225c915344b2 Mon Sep 17 00:00:00 2001 From: Joshua Zhu Date: Sat, 5 Jan 2013 13:29:57 +0800 Subject: perf tools: Add anonymous huge page recognition Judging anonymous memory's vm_area_struct, perf_mmap_event's filename will be set to "//anon" indicating this vma belongs to anonymous memory. Once hugepage is used, vma's vm_file points to hugetlbfs. In this way, this vma will not be regarded as anonymous memory by is_anon_memory() in perf user space utility. Signed-off-by: Joshua Zhu Cc: Akihiro Nagai Cc: Andi Kleen Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Joshua Zhu Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1357363797-3550-1-git-send-email-zhu.wen-jie@hp.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/map.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 0328d45c4f2a..ff94425779a2 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -19,7 +19,8 @@ const char *map_type__name[MAP__NR_TYPES] = { static inline int is_anon_memory(const char *filename) { - return strcmp(filename, "//anon") == 0; + return !strcmp(filename, "//anon") || + !strcmp(filename, "/anon_hugepage (deleted)"); } static inline int is_no_dso_memory(const char *filename) -- cgit v1.2.3-59-g8ed1b From 7ce28b5b5b320e26ac6a0e352d5005bce3530e05 Mon Sep 17 00:00:00 2001 From: Hyeoncheol Lee Date: Tue, 11 Sep 2012 16:57:28 +0900 Subject: perf probe: Allow of casting an array of char to string Before casting a type of a variable to string, convert_variable_type() confirms that the type is a pointer or an array. then if it is a pointer to char, it is casted to string. but in case of an array of char, it isn't Signed-off-by: H.C. Lee Acked-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Masami Hiramatsu Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Srikar Dronamraju Link: http://lkml.kernel.org/r/CANFS6bb75e8a_UtyAD9yF73hfXDy0N8tSjDz=a+Vna=Y8ORMHg@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-finder.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 1daf5c14e751..be0329394d56 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -413,12 +413,12 @@ static int convert_variable_type(Dwarf_Die *vr_die, dwarf_diename(vr_die), dwarf_diename(&type)); return -EINVAL; } + if (die_get_real_type(&type, &type) == NULL) { + pr_warning("Failed to get a type" + " information.\n"); + return -ENOENT; + } if (ret == DW_TAG_pointer_type) { - if (die_get_real_type(&type, &type) == NULL) { - pr_warning("Failed to get a type" - " information.\n"); - return -ENOENT; - } while (*ref_ptr) ref_ptr = &(*ref_ptr)->next; /* Add new reference with offset +0 */ -- cgit v1.2.3-59-g8ed1b From 14d1ac7429d104b09d65c72fd215e1cffd5c7eba Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 27 Dec 2012 18:11:38 +0900 Subject: perf sort: Move misplaced sort entry functions Some functions are misplaced along with other entries. Move them to a right place so that it can be found together with related functions. No functional change intended. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1356599507-14226-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 119 +++++++++++++++++++++++++------------------------ 1 file changed, 60 insertions(+), 59 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index dbaded90312c..ce5d40456c07 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -97,6 +97,16 @@ static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf, return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); } +struct sort_entry sort_comm = { + .se_header = "Command", + .se_cmp = sort__comm_cmp, + .se_collapse = sort__comm_collapse, + .se_snprintf = hist_entry__comm_snprintf, + .se_width_idx = HISTC_COMM, +}; + +/* --sort dso */ + static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) { struct dso *dso_l = map_l ? map_l->dso : NULL; @@ -117,22 +127,38 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) return strcmp(dso_name_l, dso_name_r); } -struct sort_entry sort_comm = { - .se_header = "Command", - .se_cmp = sort__comm_cmp, - .se_collapse = sort__comm_collapse, - .se_snprintf = hist_entry__comm_snprintf, - .se_width_idx = HISTC_COMM, -}; - -/* --sort dso */ - static int64_t sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) { return _sort__dso_cmp(left->ms.map, right->ms.map); } +static int _hist_entry__dso_snprintf(struct map *map, char *bf, + size_t size, unsigned int width) +{ + if (map && map->dso) { + const char *dso_name = !verbose ? map->dso->short_name : + map->dso->long_name; + return repsep_snprintf(bf, size, "%-*s", width, dso_name); + } + + return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); +} + +static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, + size_t size, unsigned int width) +{ + return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); +} + +struct sort_entry sort_dso = { + .se_header = "Shared Object", + .se_cmp = sort__dso_cmp, + .se_snprintf = hist_entry__dso_snprintf, + .se_width_idx = HISTC_DSO, +}; + +/* --sort symbol */ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, u64 ip_l, u64 ip_r) @@ -149,22 +175,24 @@ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, return (int64_t)(ip_r - ip_l); } -static int _hist_entry__dso_snprintf(struct map *map, char *bf, - size_t size, unsigned int width) +static int64_t +sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) { - if (map && map->dso) { - const char *dso_name = !verbose ? map->dso->short_name : - map->dso->long_name; - return repsep_snprintf(bf, size, "%-*s", width, dso_name); - } + u64 ip_l, ip_r; - return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); -} + if (!left->ms.sym && !right->ms.sym) + return right->level - left->level; -static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, - size_t size, unsigned int width) -{ - return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); + if (!left->ms.sym || !right->ms.sym) + return cmp_null(left->ms.sym, right->ms.sym); + + if (left->ms.sym == right->ms.sym) + return 0; + + ip_l = left->ms.sym->start; + ip_r = right->ms.sym->start; + + return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r); } static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, @@ -195,14 +223,6 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, return ret; } - -struct sort_entry sort_dso = { - .se_header = "Shared Object", - .se_cmp = sort__dso_cmp, - .se_snprintf = hist_entry__dso_snprintf, - .se_width_idx = HISTC_DSO, -}; - static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, size_t size, unsigned int width __maybe_unused) @@ -211,27 +231,6 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, self->level, bf, size, width); } -/* --sort symbol */ -static int64_t -sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) -{ - u64 ip_l, ip_r; - - if (!left->ms.sym && !right->ms.sym) - return right->level - left->level; - - if (!left->ms.sym || !right->ms.sym) - return cmp_null(left->ms.sym, right->ms.sym); - - if (left->ms.sym == right->ms.sym) - return 0; - - ip_l = left->ms.sym->start; - ip_r = right->ms.sym->start; - - return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r); -} - struct sort_entry sort_sym = { .se_header = "Symbol", .se_cmp = sort__sym_cmp, @@ -343,6 +342,8 @@ struct sort_entry sort_cpu = { .se_width_idx = HISTC_CPU, }; +/* sort keys for branch stacks */ + static int64_t sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) { @@ -357,13 +358,6 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf, bf, size, width); } -struct sort_entry sort_dso_from = { - .se_header = "Source Shared Object", - .se_cmp = sort__dso_from_cmp, - .se_snprintf = hist_entry__dso_from_snprintf, - .se_width_idx = HISTC_DSO_FROM, -}; - static int64_t sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) { @@ -423,6 +417,13 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, } +struct sort_entry sort_dso_from = { + .se_header = "Source Shared Object", + .se_cmp = sort__dso_from_cmp, + .se_snprintf = hist_entry__dso_from_snprintf, + .se_width_idx = HISTC_DSO_FROM, +}; + struct sort_entry sort_dso_to = { .se_header = "Target Shared Object", .se_cmp = sort__dso_to_cmp, -- cgit v1.2.3-59-g8ed1b From 433555221b6c8bff4fee2d5ab84e7aea6b1f068e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 27 Dec 2012 18:11:39 +0900 Subject: perf sort: Get rid of unnecessary __maybe_unused Some functions have set __maybe_unused on its arguments that are used actually. Remove them. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1356599507-14226-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index ce5d40456c07..3c2836eeafb5 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -197,7 +197,7 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, u64 ip, char level, char *bf, size_t size, - unsigned int width __maybe_unused) + unsigned int width) { size_t ret = 0; @@ -224,8 +224,7 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, } static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, - size_t size, - unsigned int width __maybe_unused) + size_t size, unsigned int width) { return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip, self->level, bf, size, width); @@ -398,8 +397,7 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right) } static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, - size_t size, - unsigned int width __maybe_unused) + size_t size, unsigned int width) { struct addr_map_symbol *from = &self->branch_info->from; return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, @@ -408,8 +406,7 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, } static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, - size_t size, - unsigned int width __maybe_unused) + size_t size, unsigned int width) { struct addr_map_symbol *to = &self->branch_info->to; return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, -- cgit v1.2.3-59-g8ed1b From fb29a338b585ebcce793b8e4a6c62440c4574fa7 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 27 Dec 2012 18:11:40 +0900 Subject: perf sort: Fix --sort pid output The "pid" sort key prints "Command: Pid" output but it's misaligned. It's because of the offset of 6 was added to the column length during the calculation in order to reserve an space for Pid part but it isn't honored when printed. The output before this patch was like this: # Overhead Command: Pid Shared Object # ........ ............. ................. # 99.70% noploop:17814 noploop 0.29% noploop:17814 [kernel.kallsyms] 0.01% noploop:17814 ld-2.15.so Fix it by subtracting 6 for printing comm part. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1356599507-14226-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 3c2836eeafb5..8b6d70bd749b 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -60,7 +60,7 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, size_t size, unsigned int width) { - return repsep_snprintf(bf, size, "%*s:%5d", width, + return repsep_snprintf(bf, size, "%*s:%5d", width - 6, self->thread->comm ?: "", self->thread->pid); } -- cgit v1.2.3-59-g8ed1b From dccf180542c4e27621ea526769014dc97b9e5676 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 27 Dec 2012 18:11:41 +0900 Subject: perf sort: Align cpu column to right Since cpu number is a natural number, it'd be more appropriate aligning it to right. Before: # Overhead CPU Command: Pid Shared Object # ........ ... ................. ..................... # 8.91% 8 gnome-shell: 1497 perf-1497.map 8.90% 7 gnome-shell: 1497 perf-1497.map 8.86% 9 gnome-shell: 1497 perf-1497.map 8.83% 6 gnome-shell: 1497 perf-1497.map 8.81% 10 gnome-shell: 1497 perf-1497.map 7.44% 5 gnome-shell: 1497 perf-1497.map 6.20% 3 gnome-shell: 1497 perf-1497.map 5.10% 0 gnome-shell: 1497 perf-1497.map After: # Overhead CPU Command: Pid Shared Object # ........ ... ................. ..................... # 8.91% 8 gnome-shell: 1497 perf-1497.map 8.90% 7 gnome-shell: 1497 perf-1497.map 8.86% 9 gnome-shell: 1497 perf-1497.map 8.83% 6 gnome-shell: 1497 perf-1497.map 8.81% 10 gnome-shell: 1497 perf-1497.map 7.44% 5 gnome-shell: 1497 perf-1497.map 6.20% 3 gnome-shell: 1497 perf-1497.map 5.10% 0 gnome-shell: 1497 perf-1497.map Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1356599507-14226-5-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 8b6d70bd749b..a36051b34901 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -331,7 +331,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right) static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, size_t size, unsigned int width) { - return repsep_snprintf(bf, size, "%-*d", width, self->cpu); + return repsep_snprintf(bf, size, "%*d", width, self->cpu); } struct sort_entry sort_cpu = { -- cgit v1.2.3-59-g8ed1b From cb993744554b0a5bd5c46239544cec9fd252a106 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 27 Dec 2012 18:11:42 +0900 Subject: perf sort: Calculate parent column width too When hists__calc_col_len() called, most of column length are refreshed but it missed parent column. So if the parent sort key was used along with other keys rests will be misalinged since parent has no proper column width. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1356599507-14226-6-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 965ebf948f2f..9485c7024f5b 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -82,6 +82,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) hists__new_col_len(hists, HISTC_DSO, len); } + if (h->parent) + hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen); + if (h->branch_info) { int symlen; /* -- cgit v1.2.3-59-g8ed1b From 6f38cf25a6af5b21da1d52a94d9f56f5af2a215b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 27 Dec 2012 18:11:45 +0900 Subject: perf sort: Clean up sort__first_dimension setting It doesn't need to compare to every sort key names since the index already has the required information. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1356599507-14226-9-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index a36051b34901..39b1ab0967f4 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -526,30 +526,8 @@ int sort_dimension__add(const char *tok) if (sd->entry->se_collapse) sort__need_collapse = 1; - if (list_empty(&hist_entry__sort_list)) { - if (!strcmp(sd->name, "pid")) - sort__first_dimension = SORT_PID; - else if (!strcmp(sd->name, "comm")) - sort__first_dimension = SORT_COMM; - else if (!strcmp(sd->name, "dso")) - sort__first_dimension = SORT_DSO; - else if (!strcmp(sd->name, "symbol")) - sort__first_dimension = SORT_SYM; - else if (!strcmp(sd->name, "parent")) - sort__first_dimension = SORT_PARENT; - else if (!strcmp(sd->name, "cpu")) - sort__first_dimension = SORT_CPU; - else if (!strcmp(sd->name, "symbol_from")) - sort__first_dimension = SORT_SYM_FROM; - else if (!strcmp(sd->name, "symbol_to")) - sort__first_dimension = SORT_SYM_TO; - else if (!strcmp(sd->name, "dso_from")) - sort__first_dimension = SORT_DSO_FROM; - else if (!strcmp(sd->name, "dso_to")) - sort__first_dimension = SORT_DSO_TO; - else if (!strcmp(sd->name, "mispredict")) - sort__first_dimension = SORT_MISPREDICT; - } + if (list_empty(&hist_entry__sort_list)) + sort__first_dimension = i; list_add_tail(&sd->entry->list, &hist_entry__sort_list); sd->taken = 1; -- cgit v1.2.3-59-g8ed1b From fc5871ed0dcf8c76dd1b3b36ff0f70112d2f0e74 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 27 Dec 2012 18:11:46 +0900 Subject: perf sort: Separate out branch stack specific sort keys Current perf report gets segmentation fault when a branch stack specific sort key is provided by --sort option to a perf.data file which contains no branch infomation. It's because those sort keys reference branch info of a hist entry unconditionally. Maybe we can change it checks whether such branch info is valid or not. But if the branch stacks are not recorded, it'd be nop. Thus it'd be better to make those keys are unselectable. This patch separates those keys to a different dimension array, so that if user passes such a key to a file which has no branch stack will get following message rather than a segfault. Error: Invalid --sort key: `symbol_from' Signed-off-by: Namhyung Kim Reported-by: Stefan Beller Acked-by: Jiri Olsa Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1356599507-14226-10-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 64 ++++++++++++++++++++++++++++++++++++++++---------- tools/perf/util/sort.h | 8 +++++-- 2 files changed, 58 insertions(+), 14 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 39b1ab0967f4..7ad62393aa88 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -480,30 +480,40 @@ struct sort_dimension { #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } -static struct sort_dimension sort_dimensions[] = { +static struct sort_dimension common_sort_dimensions[] = { DIM(SORT_PID, "pid", sort_thread), DIM(SORT_COMM, "comm", sort_comm), DIM(SORT_DSO, "dso", sort_dso), - DIM(SORT_DSO_FROM, "dso_from", sort_dso_from), - DIM(SORT_DSO_TO, "dso_to", sort_dso_to), DIM(SORT_SYM, "symbol", sort_sym), - DIM(SORT_SYM_TO, "symbol_from", sort_sym_from), - DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to), DIM(SORT_PARENT, "parent", sort_parent), DIM(SORT_CPU, "cpu", sort_cpu), - DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), DIM(SORT_SRCLINE, "srcline", sort_srcline), }; +#undef DIM + +#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) } + +static struct sort_dimension bstack_sort_dimensions[] = { + DIM(SORT_DSO_FROM, "dso_from", sort_dso_from), + DIM(SORT_DSO_TO, "dso_to", sort_dso_to), + DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from), + DIM(SORT_SYM_TO, "symbol_to", sort_sym_to), + DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), +}; + +#undef DIM + int sort_dimension__add(const char *tok) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { - struct sort_dimension *sd = &sort_dimensions[i]; + for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { + struct sort_dimension *sd = &common_sort_dimensions[i]; if (strncasecmp(tok, sd->name, strlen(tok))) continue; + if (sd->entry == &sort_parent) { int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); if (ret) { @@ -514,9 +524,7 @@ int sort_dimension__add(const char *tok) return -EINVAL; } sort__has_parent = 1; - } else if (sd->entry == &sort_sym || - sd->entry == &sort_sym_from || - sd->entry == &sort_sym_to) { + } else if (sd->entry == &sort_sym) { sort__has_sym = 1; } @@ -534,6 +542,34 @@ int sort_dimension__add(const char *tok) return 0; } + + for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { + struct sort_dimension *sd = &bstack_sort_dimensions[i]; + + if (strncasecmp(tok, sd->name, strlen(tok))) + continue; + + if (sort__branch_mode != 1) + return -EINVAL; + + if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) + sort__has_sym = 1; + + if (sd->taken) + return 0; + + if (sd->entry->se_collapse) + sort__need_collapse = 1; + + if (list_empty(&hist_entry__sort_list)) + sort__first_dimension = i + __SORT_BRANCH_STACK; + + list_add_tail(&sd->entry->list, &hist_entry__sort_list); + sd->taken = 1; + + return 0; + } + return -ESRCH; } @@ -543,7 +579,11 @@ void setup_sorting(const char * const usagestr[], const struct option *opts) for (tok = strtok_r(str, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) { - if (sort_dimension__add(tok) < 0) { + int ret = sort_dimension__add(tok); + if (ret == -EINVAL) { + error("Invalid --sort key: `%s'", tok); + usage_with_options(usagestr, opts); + } else if (ret == -ESRCH) { error("Unknown --sort key: `%s'", tok); usage_with_options(usagestr, opts); } diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index a1c0d56b6885..e994ad3e9897 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -122,18 +122,22 @@ static inline void hist_entry__add_pair(struct hist_entry *he, } enum sort_type { + /* common sort keys */ SORT_PID, SORT_COMM, SORT_DSO, SORT_SYM, SORT_PARENT, SORT_CPU, - SORT_DSO_FROM, + SORT_SRCLINE, + + /* branch stack specific sort keys */ + __SORT_BRANCH_STACK, + SORT_DSO_FROM = __SORT_BRANCH_STACK, SORT_DSO_TO, SORT_SYM_FROM, SORT_SYM_TO, SORT_MISPREDICT, - SORT_SRCLINE, }; /* -- cgit v1.2.3-59-g8ed1b From 164c800e42657e586f6fd446b3d8d41cf1f815f1 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 14 Jan 2013 10:46:47 -0700 Subject: perf symbols: Move name malloc to when needed in dso__load Memory is currently leaked on some paths. Signed-off-by: David Ahern Link: http://lkml.kernel.org/r/1358185607-90799-1-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 2960284d6ae1..daf95549e7b9 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -768,10 +768,6 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) else machine = NULL; - name = malloc(PATH_MAX); - if (!name) - return -1; - dso->adjust_symbols = 0; if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { @@ -795,6 +791,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) if (machine) root_dir = machine->root_dir; + name = malloc(PATH_MAX); + if (!name) + return -1; + /* Iterate over candidate debug images. * Keep track of "interesting" ones (those which have a symtab, dynsym, * and/or opd section) for processing. -- cgit v1.2.3-59-g8ed1b From b7c14a0b6a4e3add92e1527a31cb1826f4799248 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 14 Jan 2013 10:47:30 -0700 Subject: perf symbols: Mark vmlinux filename as allocated Needs to be marked allocated so memory can be freed when dso is deleted. Signed-off-by: David Ahern Link: http://lkml.kernel.org/r/1358185650-90848-1-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index daf95549e7b9..e6432d85b43d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -923,8 +923,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, filename = dso__build_id_filename(dso, NULL, 0); if (filename != NULL) { err = dso__load_vmlinux(dso, map, filename, filter); - if (err > 0) + if (err > 0) { + dso->lname_alloc = 1; goto out; + } free(filename); } @@ -932,6 +934,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); if (err > 0) { dso__set_long_name(dso, strdup(vmlinux_path[i])); + dso->lname_alloc = 1; break; } } @@ -971,6 +974,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, if (err > 0) { dso__set_long_name(dso, strdup(symbol_conf.vmlinux_name)); + dso->lname_alloc = 1; goto out_fixup; } return err; -- cgit v1.2.3-59-g8ed1b From 2c803e5248d038988ec7c52e8fd7c83130dd3c13 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 14 Jan 2013 10:48:01 -0700 Subject: perf tools: Move get_term_dimensions from top to util.c It is used by util/help.c so it should be a lib function and included in libperf.a. Code move only. Signed-off-by: David Ahern Link: http://lkml.kernel.org/r/1358185681-90926-1-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 22 ---------------------- tools/perf/perf.h | 4 ---- tools/perf/util/util.c | 22 ++++++++++++++++++++++ tools/perf/util/util.h | 3 +++ 4 files changed, 25 insertions(+), 26 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index bc788126397b..e05ba817f8ce 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -68,28 +68,6 @@ #include #include -void get_term_dimensions(struct winsize *ws) -{ - char *s = getenv("LINES"); - - if (s != NULL) { - ws->ws_row = atoi(s); - s = getenv("COLUMNS"); - if (s != NULL) { - ws->ws_col = atoi(s); - if (ws->ws_row && ws->ws_col) - return; - } - } -#ifdef TIOCGWINSZ - if (ioctl(1, TIOCGWINSZ, ws) == 0 && - ws->ws_row && ws->ws_col) - return; -#endif - ws->ws_row = 25; - ws->ws_col = 80; -} - static void perf_top__update_print_entries(struct perf_top *top) { if (top->print_entries > 9) diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 7622f15bcfb7..8f3bf388e414 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -1,10 +1,6 @@ #ifndef _PERF_PERF_H #define _PERF_PERF_H -struct winsize; - -void get_term_dimensions(struct winsize *ws); - #include #if defined(__i386__) diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 252b889ac8c2..805d1f52c5b4 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -220,3 +220,25 @@ void dump_stack(void) #else void dump_stack(void) {} #endif + +void get_term_dimensions(struct winsize *ws) +{ + char *s = getenv("LINES"); + + if (s != NULL) { + ws->ws_row = atoi(s); + s = getenv("COLUMNS"); + if (s != NULL) { + ws->ws_col = atoi(s); + if (ws->ws_row && ws->ws_col) + return; + } + } +#ifdef TIOCGWINSZ + if (ioctl(1, TIOCGWINSZ, ws) == 0 && + ws->ws_row && ws->ws_col) + return; +#endif + ws->ws_row = 25; + ws->ws_col = 80; +} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index c2330918110c..ec5de5e3330c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -271,4 +271,7 @@ void dump_stack(void); extern unsigned int page_size; +struct winsize; +void get_term_dimensions(struct winsize *ws); + #endif -- cgit v1.2.3-59-g8ed1b From 3cf0cb1f899640f1eb8b3984739cfd70375c9c36 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Mon, 14 Jan 2013 15:02:45 +0100 Subject: perf tools: Mark branch_info maps as referenced As noticed by Jiri, the hist_entry->branch_info.to/from maps need to be marked as referenced to avoid problems later on. So we do this when the hist_entry is allocated. Signed-off-by: Stephane Eranian Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20130114140245.GA4692@quad Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 9485c7024f5b..8170a3d11ffa 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -245,6 +245,14 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) if (he->ms.map) he->ms.map->referenced = true; + + if (he->branch_info) { + if (he->branch_info->from.map) + he->branch_info->from.map->referenced = true; + if (he->branch_info->to.map) + he->branch_info->to.map->referenced = true; + } + if (symbol_conf.use_callchain) callchain_init(he->callchain); -- cgit v1.2.3-59-g8ed1b From d8f7bbc947afb59c68a8574d1fe99b20cff2b1be Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 15 Jan 2013 14:39:51 +0100 Subject: perf tools: Remove unused 'unset' parameter from parse_events The 'unset' parameter is option callback leftover with no use, removing. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Ulrich Drepper Link: http://lkml.kernel.org/r/1358257194-8204-2-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/evsel-roundtrip-name.c | 4 ++-- tools/perf/tests/hists_link.c | 4 ++-- tools/perf/tests/parse-events.c | 2 +- tools/perf/util/parse-events.c | 5 ++--- tools/perf/util/parse-events.h | 3 +-- 5 files changed, 8 insertions(+), 10 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index e61fc828a158..0fd99a9adb91 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c @@ -22,7 +22,7 @@ static int perf_evsel__roundtrip_cache_name_test(void) for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { __perf_evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); - err = parse_events(evlist, name, 0); + err = parse_events(evlist, name); if (err) ret = err; } @@ -70,7 +70,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names) return -ENOMEM; for (i = 0; i < nr_names; ++i) { - err = parse_events(evlist, names[i], 0); + err = parse_events(evlist, names[i]); if (err) { pr_debug("failed to parse event '%s', err %d\n", names[i], err); diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 27860a082381..0afd9223bde7 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -441,10 +441,10 @@ int test__hists_link(void) if (evlist == NULL) return -ENOMEM; - err = parse_events(evlist, "cpu-clock", 0); + err = parse_events(evlist, "cpu-clock"); if (err) goto out; - err = parse_events(evlist, "task-clock", 0); + err = parse_events(evlist, "task-clock"); if (err) goto out; diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index e7eb708da32c..337424d02e53 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1018,7 +1018,7 @@ static int test_event(struct test__event_st *e) if (evlist == NULL) return -ENOMEM; - ret = parse_events(evlist, e->name, 0); + ret = parse_events(evlist, e->name); if (ret) { pr_debug("failed to parse event '%s', err %d\n", e->name, ret); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 626c120f00da..d3bf570a7084 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -872,8 +872,7 @@ int parse_events_terms(struct list_head *terms, const char *str) return ret; } -int parse_events(struct perf_evlist *evlist, const char *str, - int unset __maybe_unused) +int parse_events(struct perf_evlist *evlist, const char *str) { struct parse_events_data__events data = { .list = LIST_HEAD_INIT(data.list), @@ -900,7 +899,7 @@ int parse_events_option(const struct option *opt, const char *str, int unset __maybe_unused) { struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; - int ret = parse_events(evlist, str, unset); + int ret = parse_events(evlist, str); if (ret) { fprintf(stderr, "invalid or unsupported event: '%s'\n", str); diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index b7af80b8bdda..7c5244fa0885 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -29,8 +29,7 @@ const char *event_type(int type); extern int parse_events_option(const struct option *opt, const char *str, int unset); -extern int parse_events(struct perf_evlist *evlist, const char *str, - int unset); +extern int parse_events(struct perf_evlist *evlist, const char *str); extern int parse_events_terms(struct list_head *terms, const char *str); extern int parse_filter(const struct option *opt, const char *str, int unset); -- cgit v1.2.3-59-g8ed1b From 3cecaa2002273887a9364c454684fa8491bb2b10 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 16 Jan 2013 20:59:53 +0900 Subject: perf tools: Do not include PERF-VERSION-FILE to Makefile When make runs it tries to update the Makefile rules by reading all of included Makefiles. During the perf build it checks PERF-VERSION-FILE to get the current version number. But it triggers Makefile update so that make runs again with the update Makefile and, in turn, users will see duplicate CHK message on the second path. Running make with -d option for debugging tells me this: GNU Make 3.82 Built for x86_64-redhat-linux-gnu Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Reading makefiles... Reading makefile `Makefile'... Reading makefile `../scripts/Makefile.include' (search path) (no ~ expansion)... Reading makefile `config/utilities.mak' (search path) (no ~ expansion)... Reading makefile `PERF-VERSION-FILE' (search path) (don't care) (no ~ expansion)... Reading makefile `config/feature-tests.mak' (search path) (don't care) (no ~ expansion)... CHK -fstack-protector-all CHK -Wstack-protector CHK -Wvolatile-register-var ... Updating makefiles.... Considering target file `PERF-VERSION-FILE'. Must remake target `PERF-VERSION-FILE'. Invoking recipe from Makefile:52 to update target `PERF-VERSION-FILE'. Putting child 0x14037a0 (PERF-VERSION-FILE) PID 31925 on the chain. Live child 0x14037a0 (PERF-VERSION-FILE) PID 31925 PERF_VERSION = 3.8.rc3.gf751db6 Reaping winning child 0x14037a0 PID 31925 Removing child 0x14037a0 PID 31925 from chain. Successfully remade target file `PERF-VERSION-FILE'. ... Re-executing[1]: make -d <------------ here GNU Make 3.82 Built for x86_64-redhat-linux-gnu Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Reading makefiles... Reading makefile `Makefile'... Reading makefile `../scripts/Makefile.include' (search path) (no ~ expansion)... Reading makefile `config/utilities.mak' (search path) (no ~ expansion)... Reading makefile `PERF-VERSION-FILE' (search path) (don't care) (no ~ expansion)... Reading makefile `config/feature-tests.mak' (search path) (don't care) (no ~ expansion)... CHK -fstack-protector-all CHK -Wstack-protector CHK -Wvolatile-register-var ... Actually PERF-VERSION-FILE is used only for perf.c to #define PERF_VERSION macro. So make it like a C header file and include it during compiling the perf.c file will remove the need of being included into Makefile. Hench no need to update the Makefile and no CHK lines anymore. Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1358337594-10916-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 3 +-- tools/perf/util/PERF-VERSION-GEN | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 6aef6d00e3c2..a84021abb3fe 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -50,7 +50,6 @@ include config/utilities.mak $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) --include $(OUTPUT)PERF-VERSION-FILE uname_M := $(shell uname -m 2>/dev/null || echo not) @@ -887,7 +886,7 @@ strip: $(PROGRAMS) $(OUTPUT)perf $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS - $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ + $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \ '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN index 6aa34e5afdcf..055fef34b6f6 100755 --- a/tools/perf/util/PERF-VERSION-GEN +++ b/tools/perf/util/PERF-VERSION-GEN @@ -26,13 +26,13 @@ VN=$(expr "$VN" : v*'\(.*\)') if test -r $GVF then - VC=$(sed -e 's/^PERF_VERSION = //' <$GVF) + VC=$(sed -e 's/^#define PERF_VERSION "\(.*\)"/\1/' <$GVF) else VC=unset fi test "$VN" = "$VC" || { echo >&2 "PERF_VERSION = $VN" - echo "PERF_VERSION = $VN" >$GVF + echo "#define PERF_VERSION \"$VN\"" >$GVF } -- cgit v1.2.3-59-g8ed1b From 15268138e334bd0362f8395edac4822351714a22 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Thu, 17 Jan 2013 09:11:30 -0800 Subject: perf tools: Fix PMU format parsing test failure On POWER, the 'perf format parsing' test always fails. Looks like it is because memset() is being passed number of longs rather than number of bytes. It is interesting that the test always passes on my x86 box. With this patch, the test passes on POWER and continues to pass on x86. Signed-off-by: Sukadev Bhattiprolu Acked-by: Jiri Olsa Cc: Anton Blanchard Cc: Jiri Olsa Cc: Paul Mackerras Cc: linuxppc-dev@ozlabs.org Link: http://lkml.kernel.org/r/20130117172814.GA18882@us.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/include/linux/bitops.h | 1 + tools/perf/util/pmu.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h index a55d8cf083c9..45cf10a562bd 100644 --- a/tools/perf/util/include/linux/bitops.h +++ b/tools/perf/util/include/linux/bitops.h @@ -14,6 +14,7 @@ #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) +#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE) #define for_each_set_bit(bit, addr, size) \ for ((bit) = find_first_bit((addr), (size)); \ diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 9bdc60c6f138..b93ff146766e 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -548,7 +548,7 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to) if (!to) to = from; - memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS)); + memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); for (b = from; b <= to; b++) set_bit(b, bits); } -- cgit v1.2.3-59-g8ed1b From 08aa9cce6bf3ecdfa386cf0a0be842855eac3e7d Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 22 Jan 2013 18:09:41 +0900 Subject: perf tools: Move ltrim() to util/string.c As we have ltrim() implementation in builtin-script.c move it to the more generic location of util/string.c so that it can be used from other places. Signed-off-by: Namhyung Kim Cc: Feng Tang Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1358845787-1350-14-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 12 ------------ tools/perf/util/string.c | 18 ++++++++++++++++++ tools/perf/util/util.h | 1 + 3 files changed, 19 insertions(+), 12 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 3314ef2ec83e..fee4c9a8aee5 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -909,18 +909,6 @@ static const char *ends_with(const char *str, const char *suffix) return NULL; } -static char *ltrim(char *str) -{ - int len = strlen(str); - - while (len && isspace(*str)) { - len--; - str++; - } - - return str; -} - static int read_script_info(struct script_desc *desc, const char *filename) { char line[BUFSIZ], *p; diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index 346707df04b9..29c7b2cb2521 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c @@ -331,6 +331,24 @@ char *strxfrchar(char *s, char from, char to) return s; } +/** + * ltrim - Removes leading whitespace from @s. + * @s: The string to be stripped. + * + * Return pointer to the first non-whitespace character in @s. + */ +char *ltrim(char *s) +{ + int len = strlen(s); + + while (len && isspace(*s)) { + len--; + s++; + } + + return s; +} + /** * rtrim - Removes trailing whitespace from @s. * @s: The string to be stripped. diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index ec5de5e3330c..09b4c26b71aa 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -265,6 +265,7 @@ bool is_power_of_2(unsigned long n) size_t hex_width(u64 v); int hex2u64(const char *ptr, u64 *val); +char *ltrim(char *s); char *rtrim(char *s); void dump_stack(void); -- cgit v1.2.3-59-g8ed1b From 6cee6cd310638cd5751eea0c81315b17eb7c28a9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 18 Jan 2013 16:29:49 -0300 Subject: perf tools: Fix usage of __ in parse_events_term struct In tools/perf we use a convention where __ separates the struct name from the function name for functions that operate on a struct instance. Fix this usage by removing it from the struct parse_events_term and fix also its associated functions. Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-h6vkql4jr7dv0096f1s6hldm@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 10 +++++----- tools/perf/tests/pmu.c | 4 ++-- tools/perf/util/parse-events.c | 26 +++++++++++++------------- tools/perf/util/parse-events.h | 14 +++++++------- tools/perf/util/parse-events.y | 38 +++++++++++++++++++------------------- tools/perf/util/pmu.c | 12 ++++++------ 6 files changed, 52 insertions(+), 52 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 337424d02e53..9ac45c58305e 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -464,10 +464,10 @@ static int test__checkevent_pmu_events(struct perf_evlist *evlist) static int test__checkterms_simple(struct list_head *terms) { - struct parse_events__term *term; + struct parse_events_term *term; /* config=10 */ - term = list_entry(terms->next, struct parse_events__term, list); + term = list_entry(terms->next, struct parse_events_term, list); TEST_ASSERT_VAL("wrong type term", term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG); TEST_ASSERT_VAL("wrong type val", @@ -476,7 +476,7 @@ static int test__checkterms_simple(struct list_head *terms) TEST_ASSERT_VAL("wrong config", !term->config); /* config1 */ - term = list_entry(term->list.next, struct parse_events__term, list); + term = list_entry(term->list.next, struct parse_events_term, list); TEST_ASSERT_VAL("wrong type term", term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1); TEST_ASSERT_VAL("wrong type val", @@ -485,7 +485,7 @@ static int test__checkterms_simple(struct list_head *terms) TEST_ASSERT_VAL("wrong config", !term->config); /* config2=3 */ - term = list_entry(term->list.next, struct parse_events__term, list); + term = list_entry(term->list.next, struct parse_events_term, list); TEST_ASSERT_VAL("wrong type term", term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2); TEST_ASSERT_VAL("wrong type val", @@ -494,7 +494,7 @@ static int test__checkterms_simple(struct list_head *terms) TEST_ASSERT_VAL("wrong config", !term->config); /* umask=1*/ - term = list_entry(term->list.next, struct parse_events__term, list); + term = list_entry(term->list.next, struct parse_events_term, list); TEST_ASSERT_VAL("wrong type term", term->type_term == PARSE_EVENTS__TERM_TYPE_USER); TEST_ASSERT_VAL("wrong type val", diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c index a5f379863b8f..6803ed1a06dd 100644 --- a/tools/perf/tests/pmu.c +++ b/tools/perf/tests/pmu.c @@ -22,7 +22,7 @@ static struct test_format { #define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format)) /* Simulated users input. */ -static struct parse_events__term test_terms[] = { +static struct parse_events_term test_terms[] = { { .config = (char *) "krava01", .val.num = 15, @@ -78,7 +78,7 @@ static struct parse_events__term test_terms[] = { .type_term = PARSE_EVENTS__TERM_TYPE_USER, }, }; -#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term)) +#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events_term)) /* * Prepare format directory data, exported by kernel diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d3bf570a7084..e5c0fcbe8dbe 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -534,7 +534,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx, } static int config_term(struct perf_event_attr *attr, - struct parse_events__term *term) + struct parse_events_term *term) { #define CHECK_TYPE_VAL(type) \ do { \ @@ -579,7 +579,7 @@ do { \ static int config_attr(struct perf_event_attr *attr, struct list_head *head, int fail) { - struct parse_events__term *term; + struct parse_events_term *term; list_for_each_entry(term, head, list) if (config_term(attr, term) && fail) @@ -605,14 +605,14 @@ int parse_events_add_numeric(struct list_head **list, int *idx, return add_event(list, idx, &attr, NULL); } -static int parse_events__is_name_term(struct parse_events__term *term) +static int parse_events__is_name_term(struct parse_events_term *term) { return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; } static char *pmu_event_name(struct list_head *head_terms) { - struct parse_events__term *term; + struct parse_events_term *term; list_for_each_entry(term, head_terms, list) if (parse_events__is_name_term(term)) @@ -1162,16 +1162,16 @@ void print_events(const char *event_glob, bool name_only) print_tracepoint_events(NULL, NULL, name_only); } -int parse_events__is_hardcoded_term(struct parse_events__term *term) +int parse_events__is_hardcoded_term(struct parse_events_term *term) { return term->type_term != PARSE_EVENTS__TERM_TYPE_USER; } -static int new_term(struct parse_events__term **_term, int type_val, +static int new_term(struct parse_events_term **_term, int type_val, int type_term, char *config, char *str, u64 num) { - struct parse_events__term *term; + struct parse_events_term *term; term = zalloc(sizeof(*term)); if (!term) @@ -1197,21 +1197,21 @@ static int new_term(struct parse_events__term **_term, int type_val, return 0; } -int parse_events__term_num(struct parse_events__term **term, +int parse_events_term__num(struct parse_events_term **term, int type_term, char *config, u64 num) { return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, config, NULL, num); } -int parse_events__term_str(struct parse_events__term **term, +int parse_events_term__str(struct parse_events_term **term, int type_term, char *config, char *str) { return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, config, str, 0); } -int parse_events__term_sym_hw(struct parse_events__term **term, +int parse_events_term__sym_hw(struct parse_events_term **term, char *config, unsigned idx) { struct event_symbol *sym; @@ -1229,8 +1229,8 @@ int parse_events__term_sym_hw(struct parse_events__term **term, (char *) "event", (char *) sym->symbol, 0); } -int parse_events__term_clone(struct parse_events__term **new, - struct parse_events__term *term) +int parse_events_term__clone(struct parse_events_term **new, + struct parse_events_term *term) { return new_term(new, term->type_val, term->type_term, term->config, term->val.str, term->val.num); @@ -1238,7 +1238,7 @@ int parse_events__term_clone(struct parse_events__term **new, void parse_events__free_terms(struct list_head *terms) { - struct parse_events__term *term, *h; + struct parse_events_term *term, *h; list_for_each_entry_safe(term, h, terms, list) free(term); diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 7c5244fa0885..dd2978e7b8c0 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -50,7 +50,7 @@ enum { PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, }; -struct parse_events__term { +struct parse_events_term { char *config; union { char *str; @@ -70,15 +70,15 @@ struct parse_events_data__terms { struct list_head *terms; }; -int parse_events__is_hardcoded_term(struct parse_events__term *term); -int parse_events__term_num(struct parse_events__term **_term, +int parse_events__is_hardcoded_term(struct parse_events_term *term); +int parse_events_term__num(struct parse_events_term **_term, int type_term, char *config, u64 num); -int parse_events__term_str(struct parse_events__term **_term, +int parse_events_term__str(struct parse_events_term **_term, int type_term, char *config, char *str); -int parse_events__term_sym_hw(struct parse_events__term **term, +int parse_events_term__sym_hw(struct parse_events_term **term, char *config, unsigned idx); -int parse_events__term_clone(struct parse_events__term **new, - struct parse_events__term *term); +int parse_events_term__clone(struct parse_events_term **new, + struct parse_events_term *term); void parse_events__free_terms(struct list_head *terms); int parse_events__modifier_event(struct list_head *list, char *str, bool add); int parse_events__modifier_group(struct list_head *list, char *event_mod); diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 0f9914ae6bac..57ecf9db1f29 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -68,7 +68,7 @@ do { \ char *str; u64 num; struct list_head *head; - struct parse_events__term *term; + struct parse_events_term *term; } %% @@ -315,7 +315,7 @@ event_config: event_config ',' event_term { struct list_head *head = $1; - struct parse_events__term *term = $3; + struct parse_events_term *term = $3; ABORT_ON(!head); list_add_tail(&term->list, head); @@ -325,7 +325,7 @@ event_config ',' event_term event_term { struct list_head *head = malloc(sizeof(*head)); - struct parse_events__term *term = $1; + struct parse_events_term *term = $1; ABORT_ON(!head); INIT_LIST_HEAD(head); @@ -336,70 +336,70 @@ event_term event_term: PE_NAME '=' PE_NAME { - struct parse_events__term *term; + struct parse_events_term *term; - ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER, + ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, $1, $3)); $$ = term; } | PE_NAME '=' PE_VALUE { - struct parse_events__term *term; + struct parse_events_term *term; - ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, + ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, $1, $3)); $$ = term; } | PE_NAME '=' PE_VALUE_SYM_HW { - struct parse_events__term *term; + struct parse_events_term *term; int config = $3 & 255; - ABORT_ON(parse_events__term_sym_hw(&term, $1, config)); + ABORT_ON(parse_events_term__sym_hw(&term, $1, config)); $$ = term; } | PE_NAME { - struct parse_events__term *term; + struct parse_events_term *term; - ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, + ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, $1, 1)); $$ = term; } | PE_VALUE_SYM_HW { - struct parse_events__term *term; + struct parse_events_term *term; int config = $1 & 255; - ABORT_ON(parse_events__term_sym_hw(&term, NULL, config)); + ABORT_ON(parse_events_term__sym_hw(&term, NULL, config)); $$ = term; } | PE_TERM '=' PE_NAME { - struct parse_events__term *term; + struct parse_events_term *term; - ABORT_ON(parse_events__term_str(&term, (int)$1, NULL, $3)); + ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3)); $$ = term; } | PE_TERM '=' PE_VALUE { - struct parse_events__term *term; + struct parse_events_term *term; - ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, $3)); + ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3)); $$ = term; } | PE_TERM { - struct parse_events__term *term; + struct parse_events_term *term; - ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, 1)); + ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1)); $$ = term; } diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index b93ff146766e..c107e24b75f8 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -175,12 +175,12 @@ static int pmu_aliases(char *name, struct list_head *head) static int pmu_alias_terms(struct perf_pmu__alias *alias, struct list_head *terms) { - struct parse_events__term *term, *clone; + struct parse_events_term *term, *clone; LIST_HEAD(list); int ret; list_for_each_entry(term, &alias->terms, list) { - ret = parse_events__term_clone(&clone, term); + ret = parse_events_term__clone(&clone, term); if (ret) { parse_events__free_terms(&list); return ret; @@ -403,7 +403,7 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value) */ static int pmu_config_term(struct list_head *formats, struct perf_event_attr *attr, - struct parse_events__term *term) + struct parse_events_term *term) { struct perf_pmu__format *format; __u64 *vp; @@ -450,7 +450,7 @@ int perf_pmu__config_terms(struct list_head *formats, struct perf_event_attr *attr, struct list_head *head_terms) { - struct parse_events__term *term; + struct parse_events_term *term; list_for_each_entry(term, head_terms, list) if (pmu_config_term(formats, attr, term)) @@ -472,7 +472,7 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, } static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, - struct parse_events__term *term) + struct parse_events_term *term) { struct perf_pmu__alias *alias; char *name; @@ -507,7 +507,7 @@ static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, */ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) { - struct parse_events__term *term, *h; + struct parse_events_term *term, *h; struct perf_pmu__alias *alias; int ret; -- cgit v1.2.3-59-g8ed1b From 5c6ccc3755650497234f9027a0ac9e3b2cf1ba9f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 18 Jan 2013 16:54:00 -0300 Subject: perf pmu: Fix usage of __ in struct names In tools/perf we use a convention where __ separates the struct name from the function name for functions that operate on a struct instance. Fix this usage by removing it from the struct names and fix also the associated functions. Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-1tepcpohpvfg589pizx7tlkq@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 20 ++++++++++---------- tools/perf/util/pmu.h | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index c107e24b75f8..244edbbe1969 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -85,7 +85,7 @@ static int pmu_format(char *name, struct list_head *format) static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) { - struct perf_pmu__alias *alias; + struct perf_pmu_alias *alias; char buf[256]; int ret; @@ -172,7 +172,7 @@ static int pmu_aliases(char *name, struct list_head *head) return 0; } -static int pmu_alias_terms(struct perf_pmu__alias *alias, +static int pmu_alias_terms(struct perf_pmu_alias *alias, struct list_head *terms) { struct parse_events_term *term, *clone; @@ -360,10 +360,10 @@ struct perf_pmu *perf_pmu__find(char *name) return pmu_lookup(name); } -static struct perf_pmu__format* +static struct perf_pmu_format * pmu_find_format(struct list_head *formats, char *name) { - struct perf_pmu__format *format; + struct perf_pmu_format *format; list_for_each_entry(format, formats, list) if (!strcmp(format->name, name)) @@ -405,7 +405,7 @@ static int pmu_config_term(struct list_head *formats, struct perf_event_attr *attr, struct parse_events_term *term) { - struct perf_pmu__format *format; + struct perf_pmu_format *format; __u64 *vp; /* @@ -471,10 +471,10 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, return perf_pmu__config_terms(&pmu->format, attr, head_terms); } -static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, - struct parse_events_term *term) +static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, + struct parse_events_term *term) { - struct perf_pmu__alias *alias; + struct perf_pmu_alias *alias; char *name; if (parse_events__is_hardcoded_term(term)) @@ -508,7 +508,7 @@ static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) { struct parse_events_term *term, *h; - struct perf_pmu__alias *alias; + struct perf_pmu_alias *alias; int ret; list_for_each_entry_safe(term, h, head_terms, list) { @@ -527,7 +527,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) int perf_pmu__new_format(struct list_head *list, char *name, int config, unsigned long *bits) { - struct perf_pmu__format *format; + struct perf_pmu_format *format; format = zalloc(sizeof(*format)); if (!format) diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index a313ed76a49a..e881dd180acb 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -12,14 +12,14 @@ enum { #define PERF_PMU_FORMAT_BITS 64 -struct perf_pmu__format { +struct perf_pmu_format { char *name; int value; DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); struct list_head list; }; -struct perf_pmu__alias { +struct perf_pmu_alias { char *name; struct list_head terms; struct list_head list; @@ -42,7 +42,7 @@ int perf_pmu__config_terms(struct list_head *formats, struct list_head *head_terms); int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); struct list_head *perf_pmu__alias(struct perf_pmu *pmu, - struct list_head *head_terms); + struct list_head *head_terms); int perf_pmu_wrap(void); void perf_pmu_error(struct list_head *list, char *name, char const *msg); -- cgit v1.2.3-59-g8ed1b From 23b6339b914ec009ba206584a410039b589243aa Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 18 Jan 2013 16:56:57 -0300 Subject: perf tools: Fix usage of __ in event parsing struct names In tools/perf we use a convention where __ separates the struct name from the function name for functions that operate on a struct instance. Fix this usage by removing it from the struct names and fix also the associated functions. Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-kdcoh7uitivx68otqcz12aaz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 24 ++++++++++++------------ tools/perf/util/parse-events.c | 4 ++-- tools/perf/util/parse-events.h | 4 ++-- tools/perf/util/parse-events.y | 26 +++++++++++++------------- 4 files changed, 29 insertions(+), 29 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 9ac45c58305e..20acaff295d2 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -840,13 +840,13 @@ static int test__all_tracepoints(struct perf_evlist *evlist) return test__checkevent_tracepoint_multi(evlist); } -struct test__event_st { +struct evlist_test { const char *name; __u32 type; int (*check)(struct perf_evlist *evlist); }; -static struct test__event_st test__events[] = { +static struct evlist_test test__events[] = { [0] = { .name = "syscalls:sys_enter_open", .check = test__checkevent_tracepoint, @@ -985,7 +985,7 @@ static struct test__event_st test__events[] = { }, }; -static struct test__event_st test__events_pmu[] = { +static struct evlist_test test__events_pmu[] = { [0] = { .name = "cpu/config=10,config1,config2=3,period=1000/u", .check = test__checkevent_pmu, @@ -996,20 +996,20 @@ static struct test__event_st test__events_pmu[] = { }, }; -struct test__term { +struct terms_test { const char *str; __u32 type; int (*check)(struct list_head *terms); }; -static struct test__term test__terms[] = { +static struct terms_test test__terms[] = { [0] = { .str = "config=10,config1,config2=3,umask=1", .check = test__checkterms_simple, }, }; -static int test_event(struct test__event_st *e) +static int test_event(struct evlist_test *e) { struct perf_evlist *evlist; int ret; @@ -1031,13 +1031,13 @@ static int test_event(struct test__event_st *e) return ret; } -static int test_events(struct test__event_st *events, unsigned cnt) +static int test_events(struct evlist_test *events, unsigned cnt) { int ret1, ret2 = 0; unsigned i; for (i = 0; i < cnt; i++) { - struct test__event_st *e = &events[i]; + struct evlist_test *e = &events[i]; pr_debug("running test %d '%s'\n", i, e->name); ret1 = test_event(e); @@ -1048,7 +1048,7 @@ static int test_events(struct test__event_st *events, unsigned cnt) return ret2; } -static int test_term(struct test__term *t) +static int test_term(struct terms_test *t) { struct list_head *terms; int ret; @@ -1072,13 +1072,13 @@ static int test_term(struct test__term *t) return ret; } -static int test_terms(struct test__term *terms, unsigned cnt) +static int test_terms(struct terms_test *terms, unsigned cnt) { int ret = 0; unsigned i; for (i = 0; i < cnt; i++) { - struct test__term *t = &terms[i]; + struct terms_test *t = &terms[i]; pr_debug("running test %d '%s'\n", i, t->str); ret = test_term(t); @@ -1129,7 +1129,7 @@ static int test_pmu_events(void) while (!ret && (ent = readdir(dir))) { #define MAX_NAME 100 - struct test__event_st e; + struct evlist_test e; char name[MAX_NAME]; if (!strcmp(ent->d_name, ".") || diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index e5c0fcbe8dbe..02f6421f03a0 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -856,7 +856,7 @@ static int parse_events__scanner(const char *str, void *data, int start_token) */ int parse_events_terms(struct list_head *terms, const char *str) { - struct parse_events_data__terms data = { + struct parse_events_terms data = { .terms = NULL, }; int ret; @@ -874,7 +874,7 @@ int parse_events_terms(struct list_head *terms, const char *str) int parse_events(struct perf_evlist *evlist, const char *str) { - struct parse_events_data__events data = { + struct parse_events_evlist data = { .list = LIST_HEAD_INIT(data.list), .idx = evlist->nr_entries, }; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index dd2978e7b8c0..2cd2c42a69c5 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -61,12 +61,12 @@ struct parse_events_term { struct list_head list; }; -struct parse_events_data__events { +struct parse_events_evlist { struct list_head list; int idx; }; -struct parse_events_data__terms { +struct parse_events_terms { struct list_head *terms; }; diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 57ecf9db1f29..9d43c86176ff 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -79,7 +79,7 @@ PE_START_TERMS start_terms start_events: groups { - struct parse_events_data__events *data = _data; + struct parse_events_evlist *data = _data; parse_events_update_lists($1, &data->list); } @@ -186,7 +186,7 @@ event_def: event_pmu | event_pmu: PE_NAME '/' event_config '/' { - struct parse_events_data__events *data = _data; + struct parse_events_evlist *data = _data; struct list_head *list = NULL; ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); @@ -202,7 +202,7 @@ PE_VALUE_SYM_SW event_legacy_symbol: value_sym '/' event_config '/' { - struct parse_events_data__events *data = _data; + struct parse_events_evlist *data = _data; struct list_head *list = NULL; int type = $1 >> 16; int config = $1 & 255; @@ -215,7 +215,7 @@ value_sym '/' event_config '/' | value_sym sep_slash_dc { - struct parse_events_data__events *data = _data; + struct parse_events_evlist *data = _data; struct list_head *list = NULL; int type = $1 >> 16; int config = $1 & 255; @@ -228,7 +228,7 @@ value_sym sep_slash_dc event_legacy_cache: PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT { - struct parse_events_data__events *data = _data; + struct parse_events_evlist *data = _data; struct list_head *list = NULL; ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); @@ -237,7 +237,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT { - struct parse_events_data__events *data = _data; + struct parse_events_evlist *data = _data; struct list_head *list = NULL; ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); @@ -246,7 +246,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT | PE_NAME_CACHE_TYPE { - struct parse_events_data__events *data = _data; + struct parse_events_evlist *data = _data; struct list_head *list = NULL; ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); @@ -256,7 +256,7 @@ PE_NAME_CACHE_TYPE event_legacy_mem: PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc { - struct parse_events_data__events *data = _data; + struct parse_events_evlist *data = _data; struct list_head *list = NULL; ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, @@ -266,7 +266,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc | PE_PREFIX_MEM PE_VALUE sep_dc { - struct parse_events_data__events *data = _data; + struct parse_events_evlist *data = _data; struct list_head *list = NULL; ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, @@ -277,7 +277,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc event_legacy_tracepoint: PE_NAME ':' PE_NAME { - struct parse_events_data__events *data = _data; + struct parse_events_evlist *data = _data; struct list_head *list = NULL; ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); @@ -287,7 +287,7 @@ PE_NAME ':' PE_NAME event_legacy_numeric: PE_VALUE ':' PE_VALUE { - struct parse_events_data__events *data = _data; + struct parse_events_evlist *data = _data; struct list_head *list = NULL; ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); @@ -297,7 +297,7 @@ PE_VALUE ':' PE_VALUE event_legacy_raw: PE_RAW { - struct parse_events_data__events *data = _data; + struct parse_events_evlist *data = _data; struct list_head *list = NULL; ABORT_ON(parse_events_add_numeric(&list, &data->idx, @@ -307,7 +307,7 @@ PE_RAW start_terms: event_config { - struct parse_events_data__terms *data = _data; + struct parse_events_terms *data = _data; data->terms = $1; } -- cgit v1.2.3-59-g8ed1b From ab1bf653220b37927b838df81042c8355d20bc49 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 18 Jan 2013 17:05:09 -0300 Subject: perf pmu: Privatize perf_pmu_{format,alias} structs They are only used in pmu.c, so no need to make them public in pmu.h. Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-3gu6vhyro22ywqcldy0gtegv@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 14 +++++++++++++- tools/perf/util/pmu.h | 13 ------------- 2 files changed, 13 insertions(+), 14 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 244edbbe1969..4c6f9c490a8d 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1,4 +1,3 @@ - #include #include #include @@ -11,6 +10,19 @@ #include "parse-events.h" #include "cpumap.h" +struct perf_pmu_alias { + char *name; + struct list_head terms; + struct list_head list; +}; + +struct perf_pmu_format { + char *name; + int value; + DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); + struct list_head list; +}; + #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" int perf_pmu_parse(struct list_head *list, char *name); diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index e881dd180acb..32fe55b659fa 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -12,19 +12,6 @@ enum { #define PERF_PMU_FORMAT_BITS 64 -struct perf_pmu_format { - char *name; - int value; - DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); - struct list_head list; -}; - -struct perf_pmu_alias { - char *name; - struct list_head terms; - struct list_head list; -}; - struct perf_pmu { char *name; __u32 type; -- cgit v1.2.3-59-g8ed1b From 2de9533d6d61d3086a7079bf142d2bfa374e664e Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Fri, 18 Jan 2013 13:51:27 -0600 Subject: perf script: hook up perf_scripting_context->pevent Running the check-perf-trace scripts causes segfaults in both the Perl and Python cases: # perf script record check-perf-trace # perf script -s libexec/perf-core/scripts/python/check-perf-trace.py trace_begin Segmentation fault (core dumped) The reason is that the 'pevent' field was added to perf_scripting_context but it wasn't hooked up with an actual pevent in either case, so when one of the 'common' fields is accessed (in util/trace-event-parse.c:get_common_fields()), pevent->events tries to dereference a NULL pointer. This sets the pevent field when the scripting context is set up. Signed-off-by: Tom Zanussi Link: http://lkml.kernel.org/r/d2b1b8166a6ca0a36e1f5255b88a8289058ba236.1358527965.git.tom.zanussi@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/scripting-engines/trace-event-perl.c | 1 + tools/perf/util/scripting-engines/trace-event-python.c | 1 + 2 files changed, 2 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index f80605eb1855..eacec859f299 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -292,6 +292,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, ns = nsecs - s * NSECS_PER_SEC; scripting_context->event_data = data; + scripting_context->pevent = evsel->tp_format->pevent; ENTER; SAVETMPS; diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 14683dfca2ee..e87aa5d9696b 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -265,6 +265,7 @@ static void python_process_tracepoint(union perf_event *perf_event ns = nsecs - s * NSECS_PER_SEC; scripting_context->event_data = data; + scripting_context->pevent = evsel->tp_format->pevent; context = PyCObject_FromVoidPtr(scripting_context, NULL); -- cgit v1.2.3-59-g8ed1b From 5a3d04d6dc9050b4b4562f5c66aea23f0aa1c003 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 Jan 2013 16:10:42 -0300 Subject: perf tools: Allow passing NULL to intlist__find So that we can work with optional parameters that may not set up an intlist. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-e9tmvgdzehqrza11zs0nbg7g@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intlist.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c index 9d0740024ba8..cbf0c32ce403 100644 --- a/tools/perf/util/intlist.c +++ b/tools/perf/util/intlist.c @@ -59,9 +59,14 @@ void intlist__remove(struct intlist *ilist, struct int_node *node) struct int_node *intlist__find(struct intlist *ilist, int i) { - struct int_node *node = NULL; - struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); + struct int_node *node; + struct rb_node *rb_node; + + if (ilist == NULL) + return NULL; + node = NULL; + rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); if (rb_node) node = container_of(rb_node, struct int_node, rb_node); -- cgit v1.2.3-59-g8ed1b From ffe0fb769a6db3b6027d9228b6fecb6b352e4834 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 Jan 2013 16:17:27 -0300 Subject: perf tools: Allow passing a list to intlist__new Just like strlist allows passing a list of entries to parse. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-em50vqvvmlnc6k9tw4xtixus@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 +- tools/perf/util/intlist.c | 27 ++++++++++++++++++++++++++- tools/perf/util/intlist.h | 2 +- 3 files changed, 28 insertions(+), 3 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e05ba817f8ce..7978c8117b7f 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -694,7 +694,7 @@ static void perf_event__process_sample(struct perf_tool *tool, static struct intlist *seen; if (!seen) - seen = intlist__new(); + seen = intlist__new(NULL); if (!intlist__has_entry(seen, event->ip.pid)) { pr_err("Can't find guest [%d]'s kernel information\n", diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c index cbf0c32ce403..11a8d86f7fea 100644 --- a/tools/perf/util/intlist.c +++ b/tools/perf/util/intlist.c @@ -73,7 +73,26 @@ struct int_node *intlist__find(struct intlist *ilist, int i) return node; } -struct intlist *intlist__new(void) +static int intlist__parse_list(struct intlist *ilist, const char *s) +{ + char *sep; + int err; + + do { + long value = strtol(s, &sep, 10); + err = -EINVAL; + if (*sep != ',' && *sep != '\0') + break; + err = intlist__add(ilist, value); + if (err) + break; + s = sep + 1; + } while (*sep != '\0'); + + return err; +} + +struct intlist *intlist__new(const char *slist) { struct intlist *ilist = malloc(sizeof(*ilist)); @@ -82,9 +101,15 @@ struct intlist *intlist__new(void) ilist->rblist.node_cmp = intlist__node_cmp; ilist->rblist.node_new = intlist__node_new; ilist->rblist.node_delete = intlist__node_delete; + + if (slist && intlist__parse_list(ilist, slist)) + goto out_delete; } return ilist; +out_delete: + intlist__delete(ilist); + return NULL; } void intlist__delete(struct intlist *ilist) diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h index 6d63ab90db50..62351dad848f 100644 --- a/tools/perf/util/intlist.h +++ b/tools/perf/util/intlist.h @@ -15,7 +15,7 @@ struct intlist { struct rblist rblist; }; -struct intlist *intlist__new(void); +struct intlist *intlist__new(const char *slist); void intlist__delete(struct intlist *ilist); void intlist__remove(struct intlist *ilist, struct int_node *in); -- cgit v1.2.3-59-g8ed1b From d8639f068a59c842882339173f58311a583c555f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 Jan 2013 21:59:59 -0300 Subject: perf tools: Stop using 'self' in strlist As suggested by tglx, 'self' should be replaced by something that is more useful. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-933537sxtcz47qs0e0ledmrp@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/strlist.c | 54 +++++++++++++++++++++++------------------------ tools/perf/util/strlist.h | 42 ++++++++++++++++++------------------ 2 files changed, 48 insertions(+), 48 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c index 155d8b7078a7..55433aa42c8f 100644 --- a/tools/perf/util/strlist.c +++ b/tools/perf/util/strlist.c @@ -35,11 +35,11 @@ out_delete: return NULL; } -static void str_node__delete(struct str_node *self, bool dupstr) +static void str_node__delete(struct str_node *snode, bool dupstr) { if (dupstr) - free((void *)self->s); - free(self); + free((void *)snode->s); + free(snode); } static @@ -59,12 +59,12 @@ static int strlist__node_cmp(struct rb_node *rb_node, const void *entry) return strcmp(snode->s, str); } -int strlist__add(struct strlist *self, const char *new_entry) +int strlist__add(struct strlist *slist, const char *new_entry) { - return rblist__add_node(&self->rblist, new_entry); + return rblist__add_node(&slist->rblist, new_entry); } -int strlist__load(struct strlist *self, const char *filename) +int strlist__load(struct strlist *slist, const char *filename) { char entry[1024]; int err; @@ -80,7 +80,7 @@ int strlist__load(struct strlist *self, const char *filename) continue; entry[len - 1] = '\0'; - err = strlist__add(self, entry); + err = strlist__add(slist, entry); if (err != 0) goto out; } @@ -107,56 +107,56 @@ struct str_node *strlist__find(struct strlist *slist, const char *entry) return snode; } -static int strlist__parse_list_entry(struct strlist *self, const char *s) +static int strlist__parse_list_entry(struct strlist *slist, const char *s) { if (strncmp(s, "file://", 7) == 0) - return strlist__load(self, s + 7); + return strlist__load(slist, s + 7); - return strlist__add(self, s); + return strlist__add(slist, s); } -int strlist__parse_list(struct strlist *self, const char *s) +int strlist__parse_list(struct strlist *slist, const char *s) { char *sep; int err; while ((sep = strchr(s, ',')) != NULL) { *sep = '\0'; - err = strlist__parse_list_entry(self, s); + err = strlist__parse_list_entry(slist, s); *sep = ','; if (err != 0) return err; s = sep + 1; } - return *s ? strlist__parse_list_entry(self, s) : 0; + return *s ? strlist__parse_list_entry(slist, s) : 0; } -struct strlist *strlist__new(bool dupstr, const char *slist) +struct strlist *strlist__new(bool dupstr, const char *list) { - struct strlist *self = malloc(sizeof(*self)); + struct strlist *slist = malloc(sizeof(*slist)); - if (self != NULL) { - rblist__init(&self->rblist); - self->rblist.node_cmp = strlist__node_cmp; - self->rblist.node_new = strlist__node_new; - self->rblist.node_delete = strlist__node_delete; + if (slist != NULL) { + rblist__init(&slist->rblist); + slist->rblist.node_cmp = strlist__node_cmp; + slist->rblist.node_new = strlist__node_new; + slist->rblist.node_delete = strlist__node_delete; - self->dupstr = dupstr; - if (slist && strlist__parse_list(self, slist) != 0) + slist->dupstr = dupstr; + if (slist && strlist__parse_list(slist, list) != 0) goto out_error; } - return self; + return slist; out_error: - free(self); + free(slist); return NULL; } -void strlist__delete(struct strlist *self) +void strlist__delete(struct strlist *slist) { - if (self != NULL) - rblist__delete(&self->rblist); + if (slist != NULL) + rblist__delete(&slist->rblist); } struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx) diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h index dd9f922ec67c..5c7f87069d9c 100644 --- a/tools/perf/util/strlist.h +++ b/tools/perf/util/strlist.h @@ -17,34 +17,34 @@ struct strlist { }; struct strlist *strlist__new(bool dupstr, const char *slist); -void strlist__delete(struct strlist *self); +void strlist__delete(struct strlist *slist); -void strlist__remove(struct strlist *self, struct str_node *sn); -int strlist__load(struct strlist *self, const char *filename); -int strlist__add(struct strlist *self, const char *str); +void strlist__remove(struct strlist *slist, struct str_node *sn); +int strlist__load(struct strlist *slist, const char *filename); +int strlist__add(struct strlist *slist, const char *str); -struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); -struct str_node *strlist__find(struct strlist *self, const char *entry); +struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx); +struct str_node *strlist__find(struct strlist *slist, const char *entry); -static inline bool strlist__has_entry(struct strlist *self, const char *entry) +static inline bool strlist__has_entry(struct strlist *slist, const char *entry) { - return strlist__find(self, entry) != NULL; + return strlist__find(slist, entry) != NULL; } -static inline bool strlist__empty(const struct strlist *self) +static inline bool strlist__empty(const struct strlist *slist) { - return rblist__empty(&self->rblist); + return rblist__empty(&slist->rblist); } -static inline unsigned int strlist__nr_entries(const struct strlist *self) +static inline unsigned int strlist__nr_entries(const struct strlist *slist) { - return rblist__nr_entries(&self->rblist); + return rblist__nr_entries(&slist->rblist); } /* For strlist iteration */ -static inline struct str_node *strlist__first(struct strlist *self) +static inline struct str_node *strlist__first(struct strlist *slist) { - struct rb_node *rn = rb_first(&self->rblist.entries); + struct rb_node *rn = rb_first(&slist->rblist.entries); return rn ? rb_entry(rn, struct str_node, rb_node) : NULL; } static inline struct str_node *strlist__next(struct str_node *sn) @@ -59,21 +59,21 @@ static inline struct str_node *strlist__next(struct str_node *sn) /** * strlist_for_each - iterate over a strlist * @pos: the &struct str_node to use as a loop cursor. - * @self: the &struct strlist for loop. + * @slist: the &struct strlist for loop. */ -#define strlist__for_each(pos, self) \ - for (pos = strlist__first(self); pos; pos = strlist__next(pos)) +#define strlist__for_each(pos, slist) \ + for (pos = strlist__first(slist); pos; pos = strlist__next(pos)) /** * strlist_for_each_safe - iterate over a strlist safe against removal of * str_node * @pos: the &struct str_node to use as a loop cursor. * @n: another &struct str_node to use as temporary storage. - * @self: the &struct strlist for loop. + * @slist: the &struct strlist for loop. */ -#define strlist__for_each_safe(pos, n, self) \ - for (pos = strlist__first(self), n = strlist__next(pos); pos;\ +#define strlist__for_each_safe(pos, n, slist) \ + for (pos = strlist__first(slist), n = strlist__next(pos); pos;\ pos = n, n = strlist__next(n)) -int strlist__parse_list(struct strlist *self, const char *s); +int strlist__parse_list(struct strlist *slist, const char *s); #endif /* __PERF_STRLIST_H */ -- cgit v1.2.3-59-g8ed1b From 237a7e04a1a4461843a998fae78517dbbd08602e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 Jan 2013 21:59:59 -0300 Subject: perf tools: Stop using 'self' in map.[ch] As suggested by tglx, 'self' should be replaced by something that is more useful. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-vse2c54m0yahx6p79tmoel03@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/map.c | 118 +++++++++++++++++++++++++------------------------- tools/perf/util/map.h | 24 +++++----- 2 files changed, 70 insertions(+), 72 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index ff94425779a2..b6b163642c7d 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -29,29 +29,29 @@ static inline int is_no_dso_memory(const char *filename) !strcmp(filename, "[heap]"); } -void map__init(struct map *self, enum map_type type, +void map__init(struct map *map, enum map_type type, u64 start, u64 end, u64 pgoff, struct dso *dso) { - self->type = type; - self->start = start; - self->end = end; - self->pgoff = pgoff; - self->dso = dso; - self->map_ip = map__map_ip; - self->unmap_ip = map__unmap_ip; - RB_CLEAR_NODE(&self->rb_node); - self->groups = NULL; - self->referenced = false; - self->erange_warned = false; + map->type = type; + map->start = start; + map->end = end; + map->pgoff = pgoff; + map->dso = dso; + map->map_ip = map__map_ip; + map->unmap_ip = map__unmap_ip; + RB_CLEAR_NODE(&map->rb_node); + map->groups = NULL; + map->referenced = false; + map->erange_warned = false; } struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, u64 pgoff, u32 pid, char *filename, enum map_type type) { - struct map *self = malloc(sizeof(*self)); + struct map *map = malloc(sizeof(*map)); - if (self != NULL) { + if (map != NULL) { char newfilename[PATH_MAX]; struct dso *dso; int anon, no_dso, vdso; @@ -74,10 +74,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, if (dso == NULL) goto out_delete; - map__init(self, type, start, start + len, pgoff, dso); + map__init(map, type, start, start + len, pgoff, dso); if (anon || no_dso) { - self->map_ip = self->unmap_ip = identity__map_ip; + map->map_ip = map->unmap_ip = identity__map_ip; /* * Set memory without DSO as loaded. All map__find_* @@ -85,12 +85,12 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, * unnecessary map__load warning. */ if (no_dso) - dso__set_loaded(dso, self->type); + dso__set_loaded(dso, map->type); } } - return self; + return map; out_delete: - free(self); + free(map); return NULL; } @@ -113,48 +113,48 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type) return map; } -void map__delete(struct map *self) +void map__delete(struct map *map) { - free(self); + free(map); } -void map__fixup_start(struct map *self) +void map__fixup_start(struct map *map) { - struct rb_root *symbols = &self->dso->symbols[self->type]; + struct rb_root *symbols = &map->dso->symbols[map->type]; struct rb_node *nd = rb_first(symbols); if (nd != NULL) { struct symbol *sym = rb_entry(nd, struct symbol, rb_node); - self->start = sym->start; + map->start = sym->start; } } -void map__fixup_end(struct map *self) +void map__fixup_end(struct map *map) { - struct rb_root *symbols = &self->dso->symbols[self->type]; + struct rb_root *symbols = &map->dso->symbols[map->type]; struct rb_node *nd = rb_last(symbols); if (nd != NULL) { struct symbol *sym = rb_entry(nd, struct symbol, rb_node); - self->end = sym->end; + map->end = sym->end; } } #define DSO__DELETED "(deleted)" -int map__load(struct map *self, symbol_filter_t filter) +int map__load(struct map *map, symbol_filter_t filter) { - const char *name = self->dso->long_name; + const char *name = map->dso->long_name; int nr; - if (dso__loaded(self->dso, self->type)) + if (dso__loaded(map->dso, map->type)) return 0; - nr = dso__load(self->dso, self, filter); + nr = dso__load(map->dso, map, filter); if (nr < 0) { - if (self->dso->has_build_id) { + if (map->dso->has_build_id) { char sbuild_id[BUILD_ID_SIZE * 2 + 1]; - build_id__sprintf(self->dso->build_id, - sizeof(self->dso->build_id), + build_id__sprintf(map->dso->build_id, + sizeof(map->dso->build_id), sbuild_id); pr_warning("%s with build id %s not found", name, sbuild_id); @@ -184,43 +184,41 @@ int map__load(struct map *self, symbol_filter_t filter) * Only applies to the kernel, as its symtabs aren't relative like the * module ones. */ - if (self->dso->kernel) - map__reloc_vmlinux(self); + if (map->dso->kernel) + map__reloc_vmlinux(map); return 0; } -struct symbol *map__find_symbol(struct map *self, u64 addr, +struct symbol *map__find_symbol(struct map *map, u64 addr, symbol_filter_t filter) { - if (map__load(self, filter) < 0) + if (map__load(map, filter) < 0) return NULL; - return dso__find_symbol(self->dso, self->type, addr); + return dso__find_symbol(map->dso, map->type, addr); } -struct symbol *map__find_symbol_by_name(struct map *self, const char *name, +struct symbol *map__find_symbol_by_name(struct map *map, const char *name, symbol_filter_t filter) { - if (map__load(self, filter) < 0) + if (map__load(map, filter) < 0) return NULL; - if (!dso__sorted_by_name(self->dso, self->type)) - dso__sort_by_name(self->dso, self->type); + if (!dso__sorted_by_name(map->dso, map->type)) + dso__sort_by_name(map->dso, map->type); - return dso__find_symbol_by_name(self->dso, self->type, name); + return dso__find_symbol_by_name(map->dso, map->type, name); } -struct map *map__clone(struct map *self) +struct map *map__clone(struct map *map) { - struct map *map = malloc(sizeof(*self)); + struct map *clone = malloc(sizeof(*clone)); - if (!map) - return NULL; + if (clone != NULL) + memcpy(clone, map, sizeof(*clone)); - memcpy(map, self, sizeof(*self)); - - return map; + return clone; } int map__overlap(struct map *l, struct map *r) @@ -237,10 +235,10 @@ int map__overlap(struct map *l, struct map *r) return 0; } -size_t map__fprintf(struct map *self, FILE *fp) +size_t map__fprintf(struct map *map, FILE *fp) { return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", - self->start, self->end, self->pgoff, self->dso->name); + map->start, map->end, map->pgoff, map->dso->name); } size_t map__fprintf_dsoname(struct map *map, FILE *fp) @@ -528,9 +526,9 @@ static u64 map__reloc_unmap_ip(struct map *map, u64 ip) return ip - (s64)map->pgoff; } -void map__reloc_vmlinux(struct map *self) +void map__reloc_vmlinux(struct map *map) { - struct kmap *kmap = map__kmap(self); + struct kmap *kmap = map__kmap(map); s64 reloc; if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr) @@ -542,9 +540,9 @@ void map__reloc_vmlinux(struct map *self) if (!reloc) return; - self->map_ip = map__reloc_map_ip; - self->unmap_ip = map__reloc_unmap_ip; - self->pgoff = reloc; + map->map_ip = map__reloc_map_ip; + map->unmap_ip = map__reloc_unmap_ip; + map->pgoff = reloc; } void maps__insert(struct rb_root *maps, struct map *map) @@ -567,9 +565,9 @@ void maps__insert(struct rb_root *maps, struct map *map) rb_insert_color(&map->rb_node, maps); } -void maps__remove(struct rb_root *self, struct map *map) +void maps__remove(struct rb_root *maps, struct map *map) { - rb_erase(&map->rb_node, self); + rb_erase(&map->rb_node, maps); } struct map *maps__find(struct rb_root *maps, u64 ip) diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index bcb39e2a6965..a887f2c9dfbb 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -57,9 +57,9 @@ struct map_groups { struct machine *machine; }; -static inline struct kmap *map__kmap(struct map *self) +static inline struct kmap *map__kmap(struct map *map) { - return (struct kmap *)(self + 1); + return (struct kmap *)(map + 1); } static inline u64 map__map_ip(struct map *map, u64 ip) @@ -85,27 +85,27 @@ struct symbol; typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); -void map__init(struct map *self, enum map_type type, +void map__init(struct map *map, enum map_type type, u64 start, u64 end, u64 pgoff, struct dso *dso); struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, u64 pgoff, u32 pid, char *filename, enum map_type type); struct map *map__new2(u64 start, struct dso *dso, enum map_type type); -void map__delete(struct map *self); -struct map *map__clone(struct map *self); +void map__delete(struct map *map); +struct map *map__clone(struct map *map); int map__overlap(struct map *l, struct map *r); -size_t map__fprintf(struct map *self, FILE *fp); +size_t map__fprintf(struct map *map, FILE *fp); size_t map__fprintf_dsoname(struct map *map, FILE *fp); -int map__load(struct map *self, symbol_filter_t filter); -struct symbol *map__find_symbol(struct map *self, +int map__load(struct map *map, symbol_filter_t filter); +struct symbol *map__find_symbol(struct map *map, u64 addr, symbol_filter_t filter); -struct symbol *map__find_symbol_by_name(struct map *self, const char *name, +struct symbol *map__find_symbol_by_name(struct map *map, const char *name, symbol_filter_t filter); -void map__fixup_start(struct map *self); -void map__fixup_end(struct map *self); +void map__fixup_start(struct map *map); +void map__fixup_end(struct map *map); -void map__reloc_vmlinux(struct map *self); +void map__reloc_vmlinux(struct map *map); size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type, int verbose, FILE *fp); -- cgit v1.2.3-59-g8ed1b From 8e16017d497e9bb37c8c3c5ed1edb8d6adeebf3a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 Jan 2013 22:16:43 -0300 Subject: perf tools: Use memdup in map__clone We have memdup() exactly for that, remove open coded dup. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-tnsoexrgv6u9l125srq2c7su@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/map.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index b6b163642c7d..6fcb9de62340 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -11,6 +11,7 @@ #include "strlist.h" #include "vdso.h" #include "build-id.h" +#include const char *map_type__name[MAP__NR_TYPES] = { [MAP__FUNCTION] = "Functions", @@ -213,12 +214,7 @@ struct symbol *map__find_symbol_by_name(struct map *map, const char *name, struct map *map__clone(struct map *map) { - struct map *clone = malloc(sizeof(*clone)); - - if (clone != NULL) - memcpy(clone, map, sizeof(*clone)); - - return clone; + return memdup(map, sizeof(*map)); } int map__overlap(struct map *l, struct map *r) -- cgit v1.2.3-59-g8ed1b From 2caa48a24061b1f8e8dab43ea3292a608a15e3c9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 Jan 2013 22:34:33 -0300 Subject: perf header: Stop using die() calls when processing tracing data The callers of this function (perf_event__process_tracing_data) already handles a negative value return as error, so just use pr_err() to log the problem and return -1 instead of panic'ing. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-eeeljnecpi0zi5s7ux1mzdv9@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index fccd69dbbbb9..e17a8fe9c4d7 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2921,16 +2921,22 @@ int perf_event__process_tracing_data(union perf_event *event, session->repipe); padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; - if (readn(session->fd, buf, padding) < 0) - die("reading input file"); + if (readn(session->fd, buf, padding) < 0) { + pr_err("%s: reading input file", __func__); + return -1; + } if (session->repipe) { int retw = write(STDOUT_FILENO, buf, padding); - if (retw <= 0 || retw != padding) - die("repiping tracing data padding"); + if (retw <= 0 || retw != padding) { + pr_err("%s: repiping tracing data padding", __func__); + return -1; + } } - if (size_read + padding != size) - die("tracing data size mismatch"); + if (size_read + padding != size) { + pr_err("%s: tracing data size mismatch", __func__); + return -1; + } perf_evlist__prepare_tracepoint_events(session->evlist, session->pevent); -- cgit v1.2.3-59-g8ed1b From c7a79c47c683de6979a3e1a96dc723b0606c07ca Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 29 Jan 2013 12:47:43 +0100 Subject: perf evsel: Add prev_raw_count field This field will be used by commands which print counter deltas on regular timer intervals, such as perf stat -I. Signed-off-by: Stephane Eranian Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1359460064-3060-2-git-send-email-eranian@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 26 ++++++++++++++++++++++++++ tools/perf/util/evsel.h | 1 + 2 files changed, 27 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index e45332d08a58..dbdcca43cac6 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -659,6 +659,28 @@ void perf_evsel__delete(struct perf_evsel *evsel) free(evsel); } +static inline void compute_deltas(struct perf_evsel *evsel, + int cpu, + struct perf_counts_values *count) +{ + struct perf_counts_values tmp; + + if (!evsel->prev_raw_counts) + return; + + if (cpu == -1) { + tmp = evsel->prev_raw_counts->aggr; + evsel->prev_raw_counts->aggr = *count; + } else { + tmp = evsel->prev_raw_counts->cpu[cpu]; + evsel->prev_raw_counts->cpu[cpu] = *count; + } + + count->val = count->val - tmp.val; + count->ena = count->ena - tmp.ena; + count->run = count->run - tmp.run; +} + int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, int cpu, int thread, bool scale) { @@ -674,6 +696,8 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) return -errno; + compute_deltas(evsel, cpu, &count); + if (scale) { if (count.run == 0) count.val = 0; @@ -712,6 +736,8 @@ int __perf_evsel__read(struct perf_evsel *evsel, } } + compute_deltas(evsel, -1, aggr); + evsel->counts->scaled = 0; if (scale) { if (aggr->run == 0) { diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index c68d1b82e843..3a4cd60044ea 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -53,6 +53,7 @@ struct perf_evsel { struct xyarray *sample_id; u64 *id; struct perf_counts *counts; + struct perf_counts *prev_raw_counts; int idx; u32 ids; struct hists hists; -- cgit v1.2.3-59-g8ed1b From 43f8e76e6b96eb1327cff62ac1cc733a51f31068 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 25 Jan 2013 10:44:44 +0900 Subject: perf evsel: Fix memory leaks on evsel->counts The ->counts field was never freed in the current code. Add perf_evsel__free_counts() function to free it properly. Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1359078284-32080-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 1 + tools/perf/tests/open-syscall-all-cpus.c | 1 + tools/perf/util/evsel.c | 5 +++++ tools/perf/util/evsel.h | 1 + 4 files changed, 8 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 493043abd164..0368a1036ad6 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1372,6 +1372,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) out_free_fd: list_for_each_entry(pos, &evsel_list->entries, node) { perf_evsel__free_stat_priv(pos); + perf_evsel__free_counts(pos); perf_evsel__free_prev_raw_counts(pos); } perf_evlist__delete_maps(evsel_list); diff --git a/tools/perf/tests/open-syscall-all-cpus.c b/tools/perf/tests/open-syscall-all-cpus.c index 9b920a0cce79..b0657a9ccda6 100644 --- a/tools/perf/tests/open-syscall-all-cpus.c +++ b/tools/perf/tests/open-syscall-all-cpus.c @@ -98,6 +98,7 @@ int test__open_syscall_event_on_all_cpus(void) } } + perf_evsel__free_counts(evsel); out_close_fd: perf_evsel__close_fd(evsel, 1, threads->nr); out_evsel_delete: diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index dbdcca43cac6..baa26ddbcc7b 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -640,6 +640,11 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) } } +void perf_evsel__free_counts(struct perf_evsel *evsel) +{ + free(evsel->counts); +} + void perf_evsel__exit(struct perf_evsel *evsel) { assert(list_empty(&evsel->node)); diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 3a4cd60044ea..cbf42322a27e 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -117,6 +117,7 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); void perf_evsel__free_fd(struct perf_evsel *evsel); void perf_evsel__free_id(struct perf_evsel *evsel); +void perf_evsel__free_counts(struct perf_evsel *evsel); void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, -- cgit v1.2.3-59-g8ed1b From 8eb44dd76ac994b020e5cfe72635c90d9e0ad995 Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Fri, 25 Jan 2013 11:02:13 +0100 Subject: perf sort: Use pclose() instead of fclose() on pipe stream cppcheck message: [tools/perf/util/sort.c:277]: (error) Mismatching allocation and deallocation: fp Also fix descriptor leak on error and always initialize the "fp" variable. Signed-off-by: Thomas Jarosch Link: http://lkml.kernel.org/r/1359112354.yZcisNZ4k0@storm Link: http://lkml.kernel.org/r/2266358.qvDXKLvJ67@storm Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 7ad62393aa88..83336610faa9 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -249,7 +249,7 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, size_t size, unsigned int width __maybe_unused) { - FILE *fp; + FILE *fp = NULL; char cmd[PATH_MAX + 2], *path = self->srcline, *nl; size_t line_len; @@ -270,7 +270,6 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, if (getline(&path, &line_len, fp) < 0 || !line_len) goto out_ip; - fclose(fp); self->srcline = strdup(path); if (self->srcline == NULL) goto out_ip; @@ -280,8 +279,12 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, *nl = '\0'; path = self->srcline; out_path: + if (fp) + pclose(fp); return repsep_snprintf(bf, size, "%s", path); out_ip: + if (fp) + pclose(fp); return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip); } -- cgit v1.2.3-59-g8ed1b From 0b9e01a4f0d1c8277da6824fe060ccb0434d2fde Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Fri, 25 Jan 2013 11:20:47 +0100 Subject: perf tools: Fix memory leak on error cppcheck reported: [util/event.c:480]: (error) Memory leak: event Signed-off-by: Thomas Jarosch Link: http://lkml.kernel.org/r/2717013.8dV0naNhAV@storm Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 3cf2c3e0605f..5cd13d768cec 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -476,8 +476,10 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, } } - if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) + if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) { + free(event); return -ENOENT; + } map = machine->vmlinux_maps[MAP__FUNCTION]; size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), -- cgit v1.2.3-59-g8ed1b From fdae6373910c10e27b8ae07e11e821b183d0bba5 Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Fri, 25 Jan 2013 11:21:39 +0100 Subject: perf header: Fix memory leak for the "Not caching a kptr_restrict'ed /proc/kallsyms" case cppcheck reported: [util/header.c:316]: (error) Memory leak: filename [util/header.c:316]: (error) Memory leak: linkname Signed-off-by: Thomas Jarosch Link: http://lkml.kernel.org/r/9377388.0eFDp53iW6@storm Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index e17a8fe9c4d7..7b24cf3237d8 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -313,7 +313,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, if (is_kallsyms) { if (symbol_conf.kptr_restrict) { pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); - return 0; + err = 0; + goto out_free; } realname = (char *) name; } else -- cgit v1.2.3-59-g8ed1b From 5809fde040de2afa477a6c593ce2e8fd2c11d9d3 Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Mon, 28 Jan 2013 10:21:14 +0100 Subject: perf header: Fix double fclose() on do_write(fd, xxx) failure cppcheck reported: [util/header.c:983]: (error) Used file that is not opened. Thanks to Arnaldo Carvalho de Melo for pointing out that fclose(NULL) is undefined behavior -> protect against it. Signed-off-by: Thomas Jarosch Link: http://lkml.kernel.org/r/1751778.SZQB4fNdIh@storm Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 7b24cf3237d8..f6081cb3fca3 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -955,6 +955,7 @@ static int write_topo_node(int fd, int node) } fclose(fp); + fp = NULL; ret = do_write(fd, &mem_total, sizeof(u64)); if (ret) @@ -981,7 +982,8 @@ static int write_topo_node(int fd, int node) ret = do_write_string(fd, buf); done: free(buf); - fclose(fp); + if (fp) + fclose(fp); return ret; } -- cgit v1.2.3-59-g8ed1b From 97f63e4a2cf88e9d7bc086a1c3f10fa41c9174df Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 22 Jan 2013 18:09:29 +0900 Subject: perf tools: Keep group information Add a few of group-related field in struct perf_{evlist,evsel} so that the group information in a evlist can be known easily. It only counts groups which have more than 1 members since leader-only groups are treated as non-group events. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1358845787-1350-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 7 ++++++- tools/perf/util/evlist.h | 1 + tools/perf/util/evsel.h | 6 ++++++ tools/perf/util/parse-events.c | 1 + tools/perf/util/parse-events.h | 1 + tools/perf/util/parse-events.y | 10 ++++++++++ 6 files changed, 25 insertions(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index dc8aee97a488..eddd5ebcd690 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -117,6 +117,9 @@ void __perf_evlist__set_leader(struct list_head *list) struct perf_evsel *evsel, *leader; leader = list_entry(list->next, struct perf_evsel, node); + evsel = list_entry(list->prev, struct perf_evsel, node); + + leader->nr_members = evsel->idx - leader->idx + 1; list_for_each_entry(evsel, list, node) { if (evsel != leader) @@ -126,8 +129,10 @@ void __perf_evlist__set_leader(struct list_head *list) void perf_evlist__set_leader(struct perf_evlist *evlist) { - if (evlist->nr_entries) + if (evlist->nr_entries) { + evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0; __perf_evlist__set_leader(&evlist->entries); + } } int perf_evlist__add_default(struct perf_evlist *evlist) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 457e2350d21d..73579a25a93e 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -21,6 +21,7 @@ struct perf_evlist { struct list_head entries; struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; int nr_entries; + int nr_groups; int nr_fds; int nr_mmaps; int mmap_len; diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index cbf42322a27e..c9031ebf196e 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -74,6 +74,7 @@ struct perf_evsel { bool needs_swap; /* parse modifier helper */ int exclude_GH; + int nr_members; struct perf_evsel *leader; char *group_name; }; @@ -259,4 +260,9 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, int perf_evsel__open_strerror(struct perf_evsel *evsel, struct perf_target *target, int err, char *msg, size_t size); + +static inline int perf_evsel__group_idx(struct perf_evsel *evsel) +{ + return evsel->idx - evsel->leader->idx; +} #endif /* __PERF_EVSEL_H */ diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 02f6421f03a0..4e0f5c2a9fda 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -884,6 +884,7 @@ int parse_events(struct perf_evlist *evlist, const char *str) if (!ret) { int entries = data.idx - evlist->nr_entries; perf_evlist__splice_list_tail(evlist, &data.list, entries); + evlist->nr_groups += data.nr_groups; return 0; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 2cd2c42a69c5..8a4859315fd9 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -64,6 +64,7 @@ struct parse_events_term { struct parse_events_evlist { struct list_head list; int idx; + int nr_groups; }; struct parse_events_terms { diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 9d43c86176ff..4de2fdca98c8 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -23,6 +23,14 @@ do { \ YYABORT; \ } while (0) +static inc_group_count(struct list_head *list, + struct parse_events_evlist *data) +{ + /* Count groups only have more than 1 members */ + if (!list_is_last(list->next, list)) + data->nr_groups++; +} + %} %token PE_START_EVENTS PE_START_TERMS @@ -123,6 +131,7 @@ PE_NAME '{' events '}' { struct list_head *list = $3; + inc_group_count(list, _data); parse_events__set_leader($1, list); $$ = list; } @@ -131,6 +140,7 @@ PE_NAME '{' events '}' { struct list_head *list = $2; + inc_group_count(list, _data); parse_events__set_leader(NULL, list); $$ = list; } -- cgit v1.2.3-59-g8ed1b From a8bb559bd4eff5c71601e2e61a4bd1deef44a03c Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 22 Jan 2013 18:09:31 +0900 Subject: perf header: Add HEADER_GROUP_DESC feature Save group relationship information so that it can be restored when perf report is running. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1358845787-1350-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 3 + tools/perf/util/header.c | 164 ++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 2 + 3 files changed, 169 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 2ac690cad411..774c90713a53 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -486,6 +486,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) goto out_delete_session; } + if (!evsel_list->nr_groups) + perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); + /* * perf_session__delete(session) will be called at perf_record__exit() */ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index f6081cb3fca3..8022b5254f75 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1084,6 +1084,52 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused, return 0; } +/* + * File format: + * + * struct group_descs { + * u32 nr_groups; + * struct group_desc { + * char name[]; + * u32 leader_idx; + * u32 nr_members; + * }[nr_groups]; + * }; + */ +static int write_group_desc(int fd, struct perf_header *h __maybe_unused, + struct perf_evlist *evlist) +{ + u32 nr_groups = evlist->nr_groups; + struct perf_evsel *evsel; + int ret; + + ret = do_write(fd, &nr_groups, sizeof(nr_groups)); + if (ret < 0) + return ret; + + list_for_each_entry(evsel, &evlist->entries, node) { + if (perf_evsel__is_group_leader(evsel) && + evsel->nr_members > 1) { + const char *name = evsel->group_name ?: "{anon_group}"; + u32 leader_idx = evsel->idx; + u32 nr_members = evsel->nr_members; + + ret = do_write_string(fd, name); + if (ret < 0) + return ret; + + ret = do_write(fd, &leader_idx, sizeof(leader_idx)); + if (ret < 0) + return ret; + + ret = do_write(fd, &nr_members, sizeof(nr_members)); + if (ret < 0) + return ret; + } + } + return 0; +} + /* * default get_cpuid(): nothing gets recorded * actual implementation must be in arch/$(ARCH)/util/header.c @@ -1447,6 +1493,31 @@ error: fprintf(fp, "# pmu mappings: unable to read\n"); } +static void print_group_desc(struct perf_header *ph, int fd __maybe_unused, + FILE *fp) +{ + struct perf_session *session; + struct perf_evsel *evsel; + u32 nr = 0; + + session = container_of(ph, struct perf_session, header); + + list_for_each_entry(evsel, &session->evlist->entries, node) { + if (perf_evsel__is_group_leader(evsel) && + evsel->nr_members > 1) { + fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", + perf_evsel__name(evsel)); + + nr = evsel->nr_members - 1; + } else if (nr) { + fprintf(fp, ",%s", perf_evsel__name(evsel)); + + if (--nr == 0) + fprintf(fp, "}\n"); + } + } +} + static int __event_process_build_id(struct build_id_event *bev, char *filename, struct perf_session *session) @@ -1961,6 +2032,98 @@ error: return -1; } +static int process_group_desc(struct perf_file_section *section __maybe_unused, + struct perf_header *ph, int fd, + void *data __maybe_unused) +{ + size_t ret = -1; + u32 i, nr, nr_groups; + struct perf_session *session; + struct perf_evsel *evsel, *leader = NULL; + struct group_desc { + char *name; + u32 leader_idx; + u32 nr_members; + } *desc; + + if (readn(fd, &nr_groups, sizeof(nr_groups)) != sizeof(nr_groups)) + return -1; + + if (ph->needs_swap) + nr_groups = bswap_32(nr_groups); + + ph->env.nr_groups = nr_groups; + if (!nr_groups) { + pr_debug("group desc not available\n"); + return 0; + } + + desc = calloc(nr_groups, sizeof(*desc)); + if (!desc) + return -1; + + for (i = 0; i < nr_groups; i++) { + desc[i].name = do_read_string(fd, ph); + if (!desc[i].name) + goto out_free; + + if (readn(fd, &desc[i].leader_idx, sizeof(u32)) != sizeof(u32)) + goto out_free; + + if (readn(fd, &desc[i].nr_members, sizeof(u32)) != sizeof(u32)) + goto out_free; + + if (ph->needs_swap) { + desc[i].leader_idx = bswap_32(desc[i].leader_idx); + desc[i].nr_members = bswap_32(desc[i].nr_members); + } + } + + /* + * Rebuild group relationship based on the group_desc + */ + session = container_of(ph, struct perf_session, header); + session->evlist->nr_groups = nr_groups; + + i = nr = 0; + list_for_each_entry(evsel, &session->evlist->entries, node) { + if (evsel->idx == (int) desc[i].leader_idx) { + evsel->leader = evsel; + /* {anon_group} is a dummy name */ + if (strcmp(desc[i].name, "{anon_group}")) + evsel->group_name = desc[i].name; + evsel->nr_members = desc[i].nr_members; + + if (i >= nr_groups || nr > 0) { + pr_debug("invalid group desc\n"); + goto out_free; + } + + leader = evsel; + nr = evsel->nr_members - 1; + i++; + } else if (nr) { + /* This is a group member */ + evsel->leader = leader; + + nr--; + } + } + + if (i != nr_groups || nr != 0) { + pr_debug("invalid group desc\n"); + goto out_free; + } + + ret = 0; +out_free: + while ((int) --i >= 0) + free(desc[i].name); + free(desc); + + return ret; +} + struct feature_ops { int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); void (*print)(struct perf_header *h, int fd, FILE *fp); @@ -2000,6 +2163,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), + FEAT_OPP(HEADER_GROUP_DESC, group_desc), }; struct header_print_data { diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 20f0344accb1..c9fc55cada6d 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -29,6 +29,7 @@ enum { HEADER_NUMA_TOPOLOGY, HEADER_BRANCH_STACK, HEADER_PMU_MAPPINGS, + HEADER_GROUP_DESC, HEADER_LAST_FEATURE, HEADER_FEAT_BITS = 256, }; @@ -79,6 +80,7 @@ struct perf_session_env { char *numa_nodes; int nr_pmu_mappings; char *pmu_mappings; + int nr_groups; }; struct perf_header { -- cgit v1.2.3-59-g8ed1b From 6e1f601a10cbaa5cda869f844292dd81c519a8e7 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 22 Jan 2013 18:09:32 +0900 Subject: perf report: Make another loop for linking group hists Now the event grouping viewing requires linking all member hists in a group to the leader's. Thus hists__output_resort should be called after linking all events in evlist. Introduce symbol_conf.event_group flag to determine whether the feature is enabled or not. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1358845787-1350-5-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 13 ++++++++++++- tools/perf/util/symbol.h | 3 ++- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 47a864478543..fd2503a5f876 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -416,8 +416,16 @@ static int __cmd_report(struct perf_report *rep) hists->symbol_filter_str = rep->symbol_filter_str; hists__collapse_resort(hists); - hists__output_resort(hists); nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; + + /* Non-group events are considered as leader */ + if (symbol_conf.event_group && + !perf_evsel__is_group_leader(pos)) { + struct hists *leader_hists = &pos->leader->hists; + + hists__match(leader_hists, hists); + hists__link(leader_hists, hists); + } } if (nr_samples == 0) { @@ -425,6 +433,9 @@ static int __cmd_report(struct perf_report *rep) goto out_delete; } + list_for_each_entry(pos, &session->evlist->entries, node) + hists__output_resort(&pos->hists); + if (use_browser > 0) { if (use_browser == 1) { perf_evlist__tui_browse_hists(session->evlist, help, diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index d97377ac2f16..b62ca37c4b77 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -96,7 +96,8 @@ struct symbol_conf { initialized, kptr_restrict, annotate_asm_raw, - annotate_src; + annotate_src, + event_group; const char *vmlinux_name, *kallsyms_name, *source_prefix, -- cgit v1.2.3-59-g8ed1b From 29d720ed5f897d7e26f6b36c12c7704dc200d107 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 22 Jan 2013 18:09:33 +0900 Subject: perf hists: Resort hist entries using group members for output When event group is enabled, sorting hist entries on periods for output should consider groups members' period also. To do that, build period table using link/pair information and compare the table. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1358845787-1350-6-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.h | 2 ++ tools/perf/util/hist.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index c9031ebf196e..371713977888 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -79,6 +79,8 @@ struct perf_evsel { char *group_name; }; +#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists) + struct cpu_map; struct thread_map; struct perf_evlist; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 8170a3d11ffa..f855941bebea 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -4,6 +4,7 @@ #include "hist.h" #include "session.h" #include "sort.h" +#include "evsel.h" #include static bool hists__filter_entry_by_dso(struct hists *hists, @@ -540,6 +541,62 @@ void hists__collapse_resort_threaded(struct hists *hists) * reverse the map, sort on period. */ +static int period_cmp(u64 period_a, u64 period_b) +{ + if (period_a > period_b) + return 1; + if (period_a < period_b) + return -1; + return 0; +} + +static int hist_entry__sort_on_period(struct hist_entry *a, + struct hist_entry *b) +{ + int ret; + int i, nr_members; + struct perf_evsel *evsel; + struct hist_entry *pair; + u64 *periods_a, *periods_b; + + ret = period_cmp(a->stat.period, b->stat.period); + if (ret || !symbol_conf.event_group) + return ret; + + evsel = hists_to_evsel(a->hists); + nr_members = evsel->nr_members; + if (nr_members <= 1) + return ret; + + periods_a = zalloc(sizeof(periods_a) * nr_members); + periods_b = zalloc(sizeof(periods_b) * nr_members); + + if (!periods_a || !periods_b) + goto out; + + list_for_each_entry(pair, &a->pairs.head, pairs.node) { + evsel = hists_to_evsel(pair->hists); + periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period; + } + + list_for_each_entry(pair, &b->pairs.head, pairs.node) { + evsel = hists_to_evsel(pair->hists); + periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period; + } + + for (i = 1; i < nr_members; i++) { + ret = period_cmp(periods_a[i], periods_b[i]); + if (ret) + break; + } + +out: + free(periods_a); + free(periods_b); + + return ret; +} + static void __hists__insert_output_entry(struct rb_root *entries, struct hist_entry *he, u64 min_callchain_hits) @@ -556,7 +613,7 @@ static void __hists__insert_output_entry(struct rb_root *entries, parent = *p; iter = rb_entry(parent, struct hist_entry, rb_node); - if (he->stat.period > iter->stat.period) + if (hist_entry__sort_on_period(he, iter) > 0) p = &(*p)->rb_left; else p = &(*p)->rb_right; -- cgit v1.2.3-59-g8ed1b From 717e263fc354d53d0961e952b779d14a42c8ea66 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 22 Jan 2013 18:09:44 +0900 Subject: perf report: Show group description when event group is enabled When using event group viewer, it's better to show the group description rather than the leader information alone. If a leader did not contain any member, it's a non-group event. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1358845787-1350-17-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 15 +++++++++++++++ tools/perf/ui/browsers/hists.c | 25 +++++++++++++++++++++++++ tools/perf/ui/gtk/hists.c | 14 +++++++++++--- tools/perf/util/evsel.c | 25 +++++++++++++++++++++++++ tools/perf/util/evsel.h | 8 ++++++++ 5 files changed, 84 insertions(+), 3 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 9cc768ecacad..ce518c48a525 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -299,6 +299,21 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self, char unit; unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE]; u64 nr_events = self->stats.total_period; + struct perf_evsel *evsel = hists_to_evsel(self); + char buf[512]; + size_t size = sizeof(buf); + + if (symbol_conf.event_group && evsel->nr_members > 1) { + struct perf_evsel *pos; + + perf_evsel__group_desc(evsel, buf, size); + evname = buf; + + for_each_group_member(pos, evsel) { + nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; + nr_events += pos->hists.stats.total_period; + } + } nr_samples = convert_unit(nr_samples, &unit); ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit); diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 167f7701f94e..20ccd57753f7 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1189,6 +1189,21 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, const struct thread *thread = hists->thread_filter; unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; u64 nr_events = hists->stats.total_period; + struct perf_evsel *evsel = hists_to_evsel(hists); + char buf[512]; + size_t buflen = sizeof(buf); + + if (symbol_conf.event_group && evsel->nr_members > 1) { + struct perf_evsel *pos; + + perf_evsel__group_desc(evsel, buf, buflen); + ev_name = buf; + + for_each_group_member(pos, evsel) { + nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; + nr_events += pos->hists.stats.total_period; + } + } nr_samples = convert_unit(nr_samples, &unit); printed = scnprintf(bf, size, @@ -1585,6 +1600,16 @@ static void perf_evsel_menu__write(struct ui_browser *browser, ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : HE_COLORSET_NORMAL); + if (symbol_conf.event_group && evsel->nr_members > 1) { + struct perf_evsel *pos; + + ev_name = perf_evsel__group_name(evsel); + + for_each_group_member(pos, evsel) { + nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; + } + } + nr_events = convert_unit(nr_events, &unit); printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, unit, unit == ' ' ? "" : " ", ev_name); diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 9c02c4c0f3b7..1e764a8ad259 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -270,10 +270,18 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *evname = perf_evsel__name(pos); GtkWidget *scrolled_window; GtkWidget *tab_label; + char buf[512]; + size_t size = sizeof(buf); - if (symbol_conf.event_group && - !perf_evsel__is_group_leader(pos)) - continue; + if (symbol_conf.event_group) { + if (!perf_evsel__is_group_leader(pos)) + continue; + + if (pos->nr_members > 1) { + perf_evsel__group_desc(pos, buf, size); + evname = buf; + } + } scrolled_window = gtk_scrolled_window_new(NULL, NULL); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index baa26ddbcc7b..94e74043ded8 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -434,6 +434,31 @@ const char *perf_evsel__name(struct perf_evsel *evsel) return evsel->name ?: "unknown"; } +const char *perf_evsel__group_name(struct perf_evsel *evsel) +{ + return evsel->group_name ?: "anon group"; +} + +int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) +{ + int ret; + struct perf_evsel *pos; + const char *group_name = perf_evsel__group_name(evsel); + + ret = scnprintf(buf, size, "%s", group_name); + + ret += scnprintf(buf + ret, size - ret, " { %s", + perf_evsel__name(evsel)); + + for_each_group_member(pos, evsel) + ret += scnprintf(buf + ret, size - ret, ", %s", + perf_evsel__name(pos)); + + ret += scnprintf(buf + ret, size - ret, " }"); + + return ret; +} + /* * The enable_on_exec/disabled value strategy: * diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 371713977888..8512f6a8a6ea 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -114,6 +114,8 @@ extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX]; int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, char *bf, size_t size); const char *perf_evsel__name(struct perf_evsel *evsel); +const char *perf_evsel__group_name(struct perf_evsel *evsel); +int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); @@ -267,4 +269,10 @@ static inline int perf_evsel__group_idx(struct perf_evsel *evsel) { return evsel->idx - evsel->leader->idx; } + +#define for_each_group_member(_evsel, _leader) \ +for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \ + (_evsel) && (_evsel)->leader == (_leader); \ + (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) + #endif /* __PERF_EVSEL_H */ -- cgit v1.2.3-59-g8ed1b From e6ab07d027d47e55d8a5c0f33b16dfdd3e18c96f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 22 Jan 2013 18:09:47 +0900 Subject: perf evlist: Add --group option Add '-g/--group' option for showing event groups. For simplicity it is currently not compatible with other options. $ perf evlist --group {ref-cycles,cycles} $ perf evlist ref-cycles cycles Suggested-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1358845787-1350-20-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-evlist.txt | 4 ++++ tools/perf/builtin-evlist.c | 7 +++++++ tools/perf/util/evsel.c | 24 ++++++++++++++++++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt index 15217345c2fa..1ceb3700ffbb 100644 --- a/tools/perf/Documentation/perf-evlist.txt +++ b/tools/perf/Documentation/perf-evlist.txt @@ -28,6 +28,10 @@ OPTIONS --verbose=:: Show all fields. +-g:: +--group:: + Show event group information. + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-list[1], diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 1312a5e03ec7..85a5e35dd147 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -39,6 +39,8 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), OPT_BOOLEAN('v', "verbose", &details.verbose, "Show all event attr details"), + OPT_BOOLEAN('g', "group", &symbol_conf.event_group, + "Show event group information"), OPT_END() }; const char * const evlist_usage[] = { @@ -50,5 +52,10 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) if (argc) usage_with_options(evlist_usage, options); + if (symbol_conf.event_group && (details.verbose || details.freq)) { + pr_err("--group option is not compatible with other options\n"); + usage_with_options(evlist_usage, options); + } + return __cmd_evlist(input_name, &details); } diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 94e74043ded8..a54701504606 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1389,7 +1389,27 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, struct perf_attr_details *details, FILE *fp) { bool first = true; - int printed = fprintf(fp, "%s", perf_evsel__name(evsel)); + int printed = 0; + + if (symbol_conf.event_group) { + struct perf_evsel *pos; + + if (!perf_evsel__is_group_leader(evsel)) + return 0; + + if (evsel->nr_members > 1) + printed += fprintf(fp, "%s{", evsel->group_name ?: ""); + + printed += fprintf(fp, "%s", perf_evsel__name(evsel)); + for_each_group_member(pos, evsel) + printed += fprintf(fp, ",%s", perf_evsel__name(pos)); + + if (evsel->nr_members > 1) + printed += fprintf(fp, "}"); + goto out; + } + + printed += fprintf(fp, "%s", perf_evsel__name(evsel)); if (details->verbose || details->freq) { printed += comma_fprintf(fp, &first, " sample_freq=%" PRIu64, @@ -1430,7 +1450,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, if_print(bp_type); if_print(branch_sample_type); } - +out: fputc('\n', fp); return ++printed; } -- cgit v1.2.3-59-g8ed1b From 74b2133d19e776924b2773e27dd9d6940f1cc594 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Thu, 31 Jan 2013 13:54:37 +0100 Subject: perf evlist: Fix set event list leader The __perf_evlist__set_leader() was setting the leader for all events in the list except the first. Which means it assumed the first event already had event->leader = event. Seems like this should be the role of the function to also do this. This is a requirement for an upcoming patch set. Signed-off-by: Stephane Eranian Acked-by: Jiri Olsa Tested-by: Jiri Olsa Acked-by: Namhyung Kim Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20130131125437.GA3656@quad Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index eddd5ebcd690..ecf123e080bb 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -122,8 +122,7 @@ void __perf_evlist__set_leader(struct list_head *list) leader->nr_members = evsel->idx - leader->idx + 1; list_for_each_entry(evsel, list, node) { - if (evsel != leader) - evsel->leader = leader; + evsel->leader = leader; } } -- cgit v1.2.3-59-g8ed1b From 51f27d1440cede5a413d279a20b38767b6f85097 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 6 Feb 2013 14:57:15 +0900 Subject: perf sort: Drop ip_[lr] arguments from _sort__sym_cmp() Current _sort__sym_cmp() function is used for comparing symbols between two hist entries on symbol, symbol_from and symbol_to sort keys. Those functions pass addresses of symbols but it's meaningless since it gets over-written inside of the _sort__sym_cmp function to a start address of the symbol. So just get rid of them. This might cause a difference than prior output for branch stacks since it seems not using start address of the symbol but branch address. However AFAICS it'd be same as it gets overwritten anyway. Also remove redundant part of code in sort__sym_cmp(). Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1360130237-9963-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 83336610faa9..03cabe5678d0 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -160,9 +160,10 @@ struct sort_entry sort_dso = { /* --sort symbol */ -static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, - u64 ip_l, u64 ip_r) +static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) { + u64 ip_l, ip_r; + if (!sym_l || !sym_r) return cmp_null(sym_l, sym_r); @@ -178,21 +179,10 @@ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, static int64_t sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) { - u64 ip_l, ip_r; - if (!left->ms.sym && !right->ms.sym) return right->level - left->level; - if (!left->ms.sym || !right->ms.sym) - return cmp_null(left->ms.sym, right->ms.sym); - - if (left->ms.sym == right->ms.sym) - return 0; - - ip_l = left->ms.sym->start; - ip_r = right->ms.sym->start; - - return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r); + return _sort__sym_cmp(left->ms.sym, right->ms.sym); } static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, @@ -383,8 +373,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right) if (!from_l->sym && !from_r->sym) return right->level - left->level; - return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr, - from_r->addr); + return _sort__sym_cmp(from_l->sym, from_r->sym); } static int64_t @@ -396,7 +385,7 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right) if (!to_l->sym && !to_r->sym) return right->level - left->level; - return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr); + return _sort__sym_cmp(to_l->sym, to_r->sym); } static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, -- cgit v1.2.3-59-g8ed1b From 553099857702bb77e541c47bde47f6863834d2e2 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 6 Feb 2013 14:57:16 +0900 Subject: perf sort: Make setup_sorting returns an error code Currently the setup_sorting() is called for parsing sort keys and exits if it failed to add the sort key. As it's included in libperf it'd be better returning an error code rather than exiting application inside of the library. Signed-off-by: Namhyung Kim Suggested-by: Arnaldo Carvalho de Melo Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1360130237-9963-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 3 ++- tools/perf/builtin-diff.c | 4 +++- tools/perf/builtin-report.c | 3 ++- tools/perf/builtin-top.c | 3 ++- tools/perf/tests/hists_link.c | 3 ++- tools/perf/util/sort.c | 10 ++++++---- tools/perf/util/sort.h | 2 +- 7 files changed, 18 insertions(+), 10 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index dc870cf31b79..95a2ad3f043e 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -309,7 +309,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) if (symbol__init() < 0) return -1; - setup_sorting(annotate_usage, options); + if (setup_sorting() < 0) + usage_with_options(annotate_usage, options); if (argc) { /* diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 4af0b580b046..d207a97a2db1 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -605,7 +605,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) ui_init(); - setup_sorting(diff_usage, options); + if (setup_sorting() < 0) + usage_with_options(diff_usage, options); + setup_pager(); sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 91555d4885f4..96b5a7fee4bb 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -751,7 +751,8 @@ repeat: } - setup_sorting(report_usage, options); + if (setup_sorting() < 0) + usage_with_options(report_usage, options); /* * Only in the newt browser we are doing integrated annotation, diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index f561757b1bfa..72f6eb7b4173 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1129,7 +1129,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) if (sort_order == default_sort_order) sort_order = "dso,symbol"; - setup_sorting(top_usage, options); + if (setup_sorting() < 0) + usage_with_options(top_usage, options); if (top.use_stdio) use_browser = 0; diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 0afd9223bde7..1be64a6c5daf 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -449,7 +449,8 @@ int test__hists_link(void) goto out; /* default sort order (comm,dso,sym) will be used */ - setup_sorting(NULL, NULL); + if (setup_sorting() < 0) + goto out; machines__init(&machines); diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 03cabe5678d0..d8b48827a17e 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -565,23 +565,25 @@ int sort_dimension__add(const char *tok) return -ESRCH; } -void setup_sorting(const char * const usagestr[], const struct option *opts) +int setup_sorting(void) { char *tmp, *tok, *str = strdup(sort_order); + int ret = 0; for (tok = strtok_r(str, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) { - int ret = sort_dimension__add(tok); + ret = sort_dimension__add(tok); if (ret == -EINVAL) { error("Invalid --sort key: `%s'", tok); - usage_with_options(usagestr, opts); + break; } else if (ret == -ESRCH) { error("Unknown --sort key: `%s'", tok); - usage_with_options(usagestr, opts); + break; } } free(str); + return ret; } void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index e994ad3e9897..b13e56f6ccbe 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -160,7 +160,7 @@ struct sort_entry { extern struct sort_entry sort_thread; extern struct list_head hist_entry__sort_list; -void setup_sorting(const char * const usagestr[], const struct option *opts); +int setup_sorting(void); extern int sort_dimension__add(const char *); void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, const char *list_name, FILE *fp); -- cgit v1.2.3-59-g8ed1b From 5936f54d6ca2857d81188dcdff8c61b8fc482f53 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 6 Feb 2013 14:57:17 +0900 Subject: perf sort: Check return value of strdup() When setup_sorting() is called, 'str' is passed to strtok_r() but it's not checked to have a valid pointer. As strtok_r() accepts NULL pointer on a first argument and use the third argument in that case, it can cause a trouble since our third argument, tmp, is not initialized. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1360130237-9963-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index d8b48827a17e..d41926cb9e3f 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -570,6 +570,11 @@ int setup_sorting(void) char *tmp, *tok, *str = strdup(sort_order); int ret = 0; + if (str == NULL) { + error("Not enough memory to setup sort keys"); + return -ENOMEM; + } + for (tok = strtok_r(str, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) { ret = sort_dimension__add(tok); -- cgit v1.2.3-59-g8ed1b From 0479b8b9cf4377df5d2c81506ce93326c31eff40 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 5 Feb 2013 14:12:42 -0700 Subject: perf evlist: Make event_copy local to mmaps I am getting segfaults *after* the time sorting of perf samples where the event type is off the charts: (gdb) bt \#0 0x0807b1b2 in hists__inc_nr_events (hists=0x80a99c4, type=1163281902) at util/hist.c:1225 \#1 0x08070795 in perf_session_deliver_event (session=0x80a9b90, event=0xf7a6aff8, sample=0xffffc318, tool=0xffffc520, file_offset=0) at util/session.c:884 \#2 0x0806f9b9 in flush_sample_queue (s=0x80a9b90, tool=0xffffc520) at util/session.c:555 \#3 0x0806fc53 in process_finished_round (tool=0xffffc520, event=0x0, session=0x80a9b90) at util/session.c:645 This is bizarre because the event has already been processed once -- before it was added to the samples queue -- and the event was found to be sane at that time. There seem to be 2 causes: 1. perf_evlist__mmap_read updates the read location even though there are outstanding references to events sitting in the mmap buffers via the ordered samples queue. 2. There is a single evlist->event_copy for all evlist entries. event_copy is used to handle an event wrapping at the mmap buffer boundary. This patch addresses the second problem - making event_copy local to each perf_mmap. With this change my highly repeatable use case no longer fails. The first problem is much more complicated and will be the subject of a future patch. Signed-off-by: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1360098762-61827-1-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/perf.h | 26 -------------------------- tools/perf/util/evlist.c | 4 ++-- tools/perf/util/evlist.h | 29 ++++++++++++++++++++++++++++- 3 files changed, 30 insertions(+), 29 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 8f3bf388e414..c2206c87fc9f 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -103,32 +103,6 @@ #include "util/types.h" #include -struct perf_mmap { - void *base; - int mask; - unsigned int prev; -}; - -static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm) -{ - struct perf_event_mmap_page *pc = mm->base; - int head = pc->data_head; - rmb(); - return head; -} - -static inline void perf_mmap__write_tail(struct perf_mmap *md, - unsigned long tail) -{ - struct perf_event_mmap_page *pc = md->base; - - /* - * ensure all reads are done before we write the tail out. - */ - /* mb(); */ - pc->data_tail = tail; -} - /* * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all * counters in the current task. diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index ecf123e080bb..bc4ad7977438 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -375,7 +375,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) if ((old & md->mask) + size != ((old + size) & md->mask)) { unsigned int offset = old; unsigned int len = min(sizeof(*event), size), cpy; - void *dst = &evlist->event_copy; + void *dst = &md->event_copy; do { cpy = min(md->mask + 1 - (offset & md->mask), len); @@ -385,7 +385,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) len -= cpy; } while (len); - event = &evlist->event_copy; + event = &md->event_copy; } old += size; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 73579a25a93e..2dd07bd60b4f 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -17,6 +17,13 @@ struct perf_record_opts; #define PERF_EVLIST__HLIST_BITS 8 #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) +struct perf_mmap { + void *base; + int mask; + unsigned int prev; + union perf_event event_copy; +}; + struct perf_evlist { struct list_head entries; struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; @@ -30,7 +37,6 @@ struct perf_evlist { pid_t pid; } workload; bool overwrite; - union perf_event event_copy; struct perf_mmap *mmap; struct pollfd *pollfd; struct thread_map *threads; @@ -136,4 +142,25 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist) } size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); + +static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm) +{ + struct perf_event_mmap_page *pc = mm->base; + int head = pc->data_head; + rmb(); + return head; +} + +static inline void perf_mmap__write_tail(struct perf_mmap *md, + unsigned long tail) +{ + struct perf_event_mmap_page *pc = md->base; + + /* + * ensure all reads are done before we write the tail out. + */ + /* mb(); */ + pc->data_tail = tail; +} + #endif /* __PERF_EVLIST_H */ -- cgit v1.2.3-59-g8ed1b From 5ac59a8a77e3faa1eaf9bfe82a61e9396b082c3d Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Wed, 6 Feb 2013 15:46:01 +0100 Subject: perf tools: Add cpu_map processor socket level functions This patch adds: - cpu_map__get_socket: get socked id from cpu - cpu_map__build_socket_map: build socket map - cpu_map__socket: gets acutal socket from logical socket Those functions are used by uncore and processor socket-level aggregation modes. Signed-off-by: Stephane Eranian Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1360161962-9675-2-git-send-email-eranian@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cpumap.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/cpumap.h | 9 ++++++++ 2 files changed, 63 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 2b32ffa9ebdb..f817046e22b1 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -1,4 +1,5 @@ #include "util.h" +#include "sysfs.h" #include "../perf.h" #include "cpumap.h" #include @@ -201,3 +202,56 @@ void cpu_map__delete(struct cpu_map *map) { free(map); } + +int cpu_map__get_socket(struct cpu_map *map, int idx) +{ + FILE *fp; + const char *mnt; + char path[PATH_MAX]; + int cpu, ret; + + if (idx > map->nr) + return -1; + + cpu = map->map[idx]; + + mnt = sysfs_find_mountpoint(); + if (!mnt) + return -1; + + sprintf(path, + "%s/devices/system/cpu/cpu%d/topology/physical_package_id", + mnt, cpu); + + fp = fopen(path, "r"); + if (!fp) + return -1; + ret = fscanf(fp, "%d", &cpu); + fclose(fp); + return ret == 1 ? cpu : -1; +} + +int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) +{ + struct cpu_map *sock; + int nr = cpus->nr; + int cpu, s1, s2; + + sock = calloc(1, sizeof(*sock) + nr * sizeof(int)); + if (!sock) + return -1; + + for (cpu = 0; cpu < nr; cpu++) { + s1 = cpu_map__get_socket(cpus, cpu); + for (s2 = 0; s2 < sock->nr; s2++) { + if (s1 == sock->map[s2]) + break; + } + if (s2 == sock->nr) { + sock->map[sock->nr] = s1; + sock->nr++; + } + } + *sockp = sock; + return 0; +} diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 2f68a3b8c285..161b00756a12 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -14,6 +14,15 @@ struct cpu_map *cpu_map__dummy_new(void); void cpu_map__delete(struct cpu_map *map); struct cpu_map *cpu_map__read(FILE *file); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); +int cpu_map__get_socket(struct cpu_map *map, int idx); +int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); + +static inline int cpu_map__socket(struct cpu_map *sock, int s) +{ + if (!sock || s > sock->nr || s < 0) + return 0; + return sock->map[s]; +} static inline int cpu_map__nr(const struct cpu_map *map) { -- cgit v1.2.3-59-g8ed1b From 89bb67ff935d461544fed87174bb13dcc4bac673 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 4 Feb 2013 10:56:42 +0100 Subject: perf tools: Fix perf_evsel::exclude_GH handling Let the perf_evsel::exclude_GH only prevent the reset of exclude_host and exclude_guest attributes in case they were already set. We cannot reset their values to 0, because they might have other defaults set by event_attr_init. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1359971803-2343-2-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4e0f5c2a9fda..c84f48cf9678 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -699,14 +699,6 @@ static int get_event_modifier(struct event_modifier *mod, char *str, int exclude = eu | ek | eh; int exclude_GH = evsel ? evsel->exclude_GH : 0; - /* - * We are here for group and 'GH' was not set as event - * modifier and whatever event/group modifier override - * default 'GH' setup. - */ - if (evsel && !exclude_GH) - eH = eG = 0; - memset(mod, 0, sizeof(*mod)); while (*str) { -- cgit v1.2.3-59-g8ed1b From 91b988048bea24eae386da3141d247ccea795a81 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Wed, 30 Jan 2013 20:05:49 -0500 Subject: perf tools: Fix calloc argument ordering A sweep of the kernel for regex "kcalloc(sizeof" turned up 2 reversed args, fixed in commit d3d09e18203dba16a9dbdb2b4cc673d90748cdd1 ("EDAC: Fix kcalloc argument order") and also fixed in the networking commit a1b1add07fa794974573d93483d68e373edfe7bd ("gro: Fix kcalloc argument order"). I know that was the regex used, because on seeing the 1st of these changes, I wondered "how many other instances of this are there" and I happened to just use "calloc(sizeof" as a regex and it in turn found these additional reversed args instances in the perf code. In the kcalloc cases, the changes are cosmetic, since the numbers are simply multiplied. I had no desire to go data mining in userspace to see if the same thing held true there, however. Signed-off-by: Paul Gortmaker Cc: Ingo Molnar Cc: Joe Perches Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1359594349-25912-1-git-send-email-paul.gortmaker@windriver.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/callchain.c | 2 +- tools/perf/util/header.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index d3b3f5d82137..42b6a632fe7b 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -444,7 +444,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor, struct callchain_cursor_node *node = *cursor->last; if (!node) { - node = calloc(sizeof(*node), 1); + node = calloc(1, sizeof(*node)); if (!node) return -ENOMEM; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 8022b5254f75..f4bfd79ef6a7 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2253,7 +2253,7 @@ static int perf_header__adds_write(struct perf_header *header, if (!nr_sections) return 0; - feat_sec = p = calloc(sizeof(*feat_sec), nr_sections); + feat_sec = p = calloc(nr_sections, sizeof(*feat_sec)); if (feat_sec == NULL) return -ENOMEM; @@ -2425,7 +2425,7 @@ int perf_header__process_sections(struct perf_header *header, int fd, if (!nr_sections) return 0; - feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections); + feat_sec = sec = calloc(nr_sections, sizeof(*feat_sec)); if (!feat_sec) return -1; -- cgit v1.2.3-59-g8ed1b From e35ef355ad3dd26bff79c8711f070ac69501dfa3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 6 Feb 2013 17:20:02 -0300 Subject: perf evlist: Pass the event_group info via perf_attr_details So that we avoid dragging symbol.o into the python binding. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-izjubje7ltd1srji5wb0ygwi@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-evlist.c | 4 ++-- tools/perf/util/evsel.c | 2 +- tools/perf/util/evsel.h | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 85a5e35dd147..05bd9dfe875c 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -39,7 +39,7 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), OPT_BOOLEAN('v', "verbose", &details.verbose, "Show all event attr details"), - OPT_BOOLEAN('g', "group", &symbol_conf.event_group, + OPT_BOOLEAN('g', "group", &details.event_group, "Show event group information"), OPT_END() }; @@ -52,7 +52,7 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) if (argc) usage_with_options(evlist_usage, options); - if (symbol_conf.event_group && (details.verbose || details.freq)) { + if (details.event_group && (details.verbose || details.freq)) { pr_err("--group option is not compatible with other options\n"); usage_with_options(evlist_usage, options); } diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a54701504606..9c82f98f26de 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1391,7 +1391,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, bool first = true; int printed = 0; - if (symbol_conf.event_group) { + if (details->event_group) { struct perf_evsel *pos; if (!perf_evsel__is_group_leader(evsel)) diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 8512f6a8a6ea..52021c3087df 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -254,6 +254,7 @@ static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) struct perf_attr_details { bool freq; bool verbose; + bool event_group; }; int perf_evsel__fprintf(struct perf_evsel *evsel, -- cgit v1.2.3-59-g8ed1b From 88fd2b6a76264e9e14463f532caae09d82a53207 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 6 Feb 2013 17:21:47 -0300 Subject: perf python: Link with sysfs.o So that we fix this regression: [root@sandy linux]# perf test -v 15 15: Try 'use perf' in python, checking link problems : --- start --- Traceback (most recent call last): File "", line 1, in ImportError: /home/acme/git/build/perf/python/perf.so: undefined symbol: sysfs_find_mountpoint ---- end ---- Try 'use perf' in python, checking link problems: FAILED! [root@sandy linux]# Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-8pf64bsdywg1gl9m55ul77hg@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/python-ext-sources | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index c40c2d33199e..64536a993f4a 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources @@ -18,4 +18,5 @@ util/cgroup.c util/debugfs.c util/rblist.c util/strlist.c +util/sysfs.c ../../lib/rbtree.c -- cgit v1.2.3-59-g8ed1b From e3a34029c635b7dee06e51d99441578b96c7d463 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 7 Feb 2013 18:02:12 +0900 Subject: perf annotate: Fix warning message on a missing vmlinux When perf annotate runs with no vmlinux file it cannot annotate kernel symbols because the kallsyms only provides symbol addresses. So it recommends to run perf buildid-cache to install proper vmlinux image. But running perf buildid-cache -av vmlinux as the message gives me a following error: $ perf buildid-cache -av /home/namhyung/build/kernel/vmlinux Couldn't add v: No such file or directory Since the -a option receives a parameter, 'v' should not be after the option. In addition -a option is not work for this case since the build-id cache already has a kallsyms with same build-id so it'll fail with EEXIST. Use recently added -u (--update) option for it. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Borislav Petkov Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1360227734-375-6-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 07aaeea60000..d33fe937e6f1 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -809,7 +809,7 @@ fallback: pr_err("Can't annotate %s:\n\n" "No vmlinux file%s\nwas found in the path.\n\n" "Please use:\n\n" - " perf buildid-cache -av vmlinux\n\n" + " perf buildid-cache -vu vmlinux\n\n" "or:\n\n" " --vmlinux vmlinux\n", sym->name, build_id_msg ?: ""); -- cgit v1.2.3-59-g8ed1b From 2b676bf068916046151277f27113f80828e33001 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 7 Feb 2013 18:02:08 +0900 Subject: perf ui/gtk: Implement basic GTK2 annotation browser Basic implementation of perf annotate on GTK2. Currently only shows first symbol. Add a new --gtk option to use it. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Borislav Petkov Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1360227734-375-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-annotate.txt | 4 +- tools/perf/Makefile | 1 + tools/perf/builtin-annotate.c | 10 +- tools/perf/ui/gtk/annotate.c | 185 +++++++++++++++++++++++++++++ tools/perf/ui/setup.c | 2 +- tools/perf/util/annotate.h | 20 ++++ 6 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 tools/perf/ui/gtk/annotate.c (limited to 'tools/perf/util') diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index c8ffd9fd5c6a..e5e1d06efc37 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt @@ -61,11 +61,13 @@ OPTIONS --stdio:: Use the stdio interface. ---tui:: Use the TUI interface Use of --tui requires a tty, if one is not +--tui:: Use the TUI interface. Use of --tui requires a tty, if one is not present, as when piping to other commands, the stdio interface is used. This interfaces starts by centering on the line with more samples, TAB/UNTAB cycles through the lines with more samples. +--gtk:: Use the GTK interface. + -C:: --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can be provided as a comma-separated list with no space: 0,1. Ranges of diff --git a/tools/perf/Makefile b/tools/perf/Makefile index a158309a65ef..1c8df6f9c4d9 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -698,6 +698,7 @@ ifndef NO_GTK2 LIB_OBJS += $(OUTPUT)ui/gtk/util.o LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o LIB_OBJS += $(OUTPUT)ui/gtk/progress.o + LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o endif endif diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 95a2ad3f043e..9d758c9611a5 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -34,7 +34,7 @@ struct perf_annotate { struct perf_tool tool; - bool force, use_tui, use_stdio; + bool force, use_tui, use_stdio, use_gtk; bool full_paths; bool print_line; const char *sym_hist_filter; @@ -138,7 +138,10 @@ find_next: continue; } - if (use_browser > 0) { + if (use_browser == 2) { + hist_entry__gtk_annotate(he, evidx, NULL); + return; + } else if (use_browser == 1) { key = hist_entry__tui_annotate(he, evidx, NULL); switch (key) { case K_RIGHT: @@ -270,6 +273,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), + OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"), OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, @@ -300,6 +304,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) use_browser = 0; else if (annotate.use_tui) use_browser = 1; + else if (annotate.use_gtk) + use_browser = 2; setup_browser(true); diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c new file mode 100644 index 000000000000..19d84fa327af --- /dev/null +++ b/tools/perf/ui/gtk/annotate.c @@ -0,0 +1,185 @@ +#include "gtk.h" +#include "util/debug.h" +#include "util/annotate.h" +#include "ui/helpline.h" + + +enum { + ANN_COL__PERCENT, + ANN_COL__OFFSET, + ANN_COL__LINE, + + MAX_ANN_COLS +}; + +static const char *const col_names[] = { + "Overhead", + "Offset", + "Line" +}; + +static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym, + struct disasm_line *dl, int evidx) +{ + struct sym_hist *symhist; + double percent = 0.0; + const char *markup; + int ret = 0; + + strcpy(buf, ""); + + if (dl->offset == (s64) -1) + return 0; + + symhist = annotation__histogram(symbol__annotation(sym), evidx); + if (!symhist->addr[dl->offset]) + return 0; + + percent = 100.0 * symhist->addr[dl->offset] / symhist->sum; + + markup = perf_gtk__get_percent_color(percent); + if (markup) + ret += scnprintf(buf, size, "%s", markup); + ret += scnprintf(buf + ret, size - ret, "%6.2f%%", percent); + if (markup) + ret += scnprintf(buf + ret, size - ret, ""); + + return ret; +} + +static int perf_gtk__get_offset(char *buf, size_t size, struct symbol *sym, + struct map *map, struct disasm_line *dl) +{ + u64 start = map__rip_2objdump(map, sym->start); + + strcpy(buf, ""); + + if (dl->offset == (s64) -1) + return 0; + + return scnprintf(buf, size, "%"PRIx64, start + dl->offset); +} + +static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, + struct map *map, int evidx, + struct hist_browser_timer *hbt __maybe_unused) +{ + struct disasm_line *pos, *n; + struct annotation *notes; + GType col_types[MAX_ANN_COLS]; + GtkCellRenderer *renderer; + GtkListStore *store; + GtkWidget *view; + int i; + char s[512]; + + if (map->dso->annotate_warned) + return -1; + + if (symbol__annotate(sym, map, 0) < 0) { + ui__error("%s", ui_helpline__current); + return -1; + } + + notes = symbol__annotation(sym); + + for (i = 0; i < MAX_ANN_COLS; i++) { + col_types[i] = G_TYPE_STRING; + } + store = gtk_list_store_newv(MAX_ANN_COLS, col_types); + + view = gtk_tree_view_new(); + renderer = gtk_cell_renderer_text_new(); + + for (i = 0; i < MAX_ANN_COLS; i++) { + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), + -1, col_names[i], renderer, + i == ANN_COL__PERCENT ? "markup" : "text", + i, NULL); + } + + gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); + g_object_unref(GTK_TREE_MODEL(store)); + + list_for_each_entry(pos, ¬es->src->source, node) { + GtkTreeIter iter; + + gtk_list_store_append(store, &iter); + + if (perf_gtk__get_percent(s, sizeof(s), sym, pos, evidx)) + gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1); + if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos)) + gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1); + gtk_list_store_set(store, &iter, ANN_COL__LINE, pos->line, -1); + } + + gtk_container_add(GTK_CONTAINER(window), view); + + list_for_each_entry_safe(pos, n, ¬es->src->source, node) { + list_del(&pos->node); + disasm_line__free(pos); + } + + return 0; +} + +int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, + struct hist_browser_timer *hbt) +{ + GtkWidget *vbox; + GtkWidget *notebook; + GtkWidget *infobar; + GtkWidget *statbar; + GtkWidget *window; + GtkWidget *scrolled_window; + GtkWidget *tab_label; + + signal(SIGSEGV, perf_gtk__signal); + signal(SIGFPE, perf_gtk__signal); + signal(SIGINT, perf_gtk__signal); + signal(SIGQUIT, perf_gtk__signal); + signal(SIGTERM, perf_gtk__signal); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "perf annotate"); + + g_signal_connect(window, "delete_event", gtk_main_quit, NULL); + + pgctx = perf_gtk__activate_context(window); + if (!pgctx) + return -1; + + vbox = gtk_vbox_new(FALSE, 0); + notebook = gtk_notebook_new(); + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + tab_label = gtk_label_new(sym->name); + + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, + tab_label); + gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); + + infobar = perf_gtk__setup_info_bar(); + if (infobar) + gtk_box_pack_start(GTK_BOX(vbox), infobar, FALSE, FALSE, 0); + + statbar = perf_gtk__setup_statusbar(); + gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); + + gtk_container_add(GTK_CONTAINER(window), vbox); + + perf_gtk__annotate_symbol(scrolled_window, sym, map, evidx, hbt); + + gtk_widget_show_all(window); + + perf_gtk__resize_window(window); + gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); + + gtk_main(); + + perf_gtk__deactivate_context(&pgctx); + return 0; +} diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index 166f13df3134..ae6a789cb0f6 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c @@ -8,7 +8,7 @@ pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; void setup_browser(bool fallback_to_pager) { - if (!isatty(1) || dump_trace) + if (use_browser < 2 && (!isatty(1) || dump_trace)) use_browser = 0; /* default to TUI */ diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 8eec94358a4a..a8ccbda4aeb7 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -6,6 +6,7 @@ #include "types.h" #include "symbol.h" #include "hist.h" +#include "sort.h" #include #include #include @@ -154,6 +155,25 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, } #endif +#ifdef GTK2_SUPPORT +int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, + struct hist_browser_timer *hbt); + +static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx, + struct hist_browser_timer *hbt) +{ + return symbol__gtk_annotate(he->ms.sym, he->ms.map, evidx, hbt); +} +#else +static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused, + int evidx __maybe_unused, + struct hist_browser_timer *hbt + __maybe_unused) +{ + return 0; +} +#endif + extern const char *disassembler_style; #endif /* __PERF_ANNOTATE_H */ -- cgit v1.2.3-59-g8ed1b From 7a60ba948267336d77a48a3539f98151f9dcfba6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 7 Feb 2013 18:02:09 +0900 Subject: perf gtk/annotate: Support multiple event annotation Show multiple annotation result for each evsel. Each result represents the most frquently sampled symbol/function for the evsel and it will be shown in a tab window. For this add a reference to main container (notebook) to the pgctx. At the first call to annotate browser, hist_entry__find_annotations() will setup a new browser, and next calls will add new tabs to the browser. But it requires final perf_gtk__show_annotations() to start processing GUI events. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Borislav Petkov Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1360227734-375-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 4 +++ tools/perf/ui/gtk/annotate.c | 74 +++++++++++++++++++++++++++---------------- tools/perf/ui/gtk/gtk.h | 1 + tools/perf/util/annotate.h | 4 +++ 4 files changed, 56 insertions(+), 27 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 9d758c9611a5..68e3a16abd3d 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -227,6 +227,10 @@ static int __cmd_annotate(struct perf_annotate *ann) ui__error("The %s file has no samples!\n", session->filename); goto out_delete; } + + if (use_browser == 2) + perf_gtk__show_annotations(); + out_delete: /* * Speed up the exit process, for large files this can diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index 19d84fa327af..1ce89f2558fa 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -126,31 +126,52 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, struct hist_browser_timer *hbt) { - GtkWidget *vbox; - GtkWidget *notebook; - GtkWidget *infobar; - GtkWidget *statbar; GtkWidget *window; + GtkWidget *notebook; GtkWidget *scrolled_window; GtkWidget *tab_label; - signal(SIGSEGV, perf_gtk__signal); - signal(SIGFPE, perf_gtk__signal); - signal(SIGINT, perf_gtk__signal); - signal(SIGQUIT, perf_gtk__signal); - signal(SIGTERM, perf_gtk__signal); + if (perf_gtk__is_active_context(pgctx)) { + window = pgctx->main_window; + notebook = pgctx->notebook; + } else { + GtkWidget *vbox; + GtkWidget *infobar; + GtkWidget *statbar; - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(window), "perf annotate"); + signal(SIGSEGV, perf_gtk__signal); + signal(SIGFPE, perf_gtk__signal); + signal(SIGINT, perf_gtk__signal); + signal(SIGQUIT, perf_gtk__signal); + signal(SIGTERM, perf_gtk__signal); - g_signal_connect(window, "delete_event", gtk_main_quit, NULL); + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "perf annotate"); - pgctx = perf_gtk__activate_context(window); - if (!pgctx) - return -1; + g_signal_connect(window, "delete_event", gtk_main_quit, NULL); + + pgctx = perf_gtk__activate_context(window); + if (!pgctx) + return -1; + + vbox = gtk_vbox_new(FALSE, 0); + notebook = gtk_notebook_new(); + pgctx->notebook = notebook; + + gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); + + infobar = perf_gtk__setup_info_bar(); + if (infobar) { + gtk_box_pack_start(GTK_BOX(vbox), infobar, + FALSE, FALSE, 0); + } + + statbar = perf_gtk__setup_statusbar(); + gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); + + gtk_container_add(GTK_CONTAINER(window), vbox); + } - vbox = gtk_vbox_new(FALSE, 0); - notebook = gtk_notebook_new(); scrolled_window = gtk_scrolled_window_new(NULL, NULL); tab_label = gtk_label_new(sym->name); @@ -160,19 +181,19 @@ int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label); - gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); - - infobar = perf_gtk__setup_info_bar(); - if (infobar) - gtk_box_pack_start(GTK_BOX(vbox), infobar, FALSE, FALSE, 0); - statbar = perf_gtk__setup_statusbar(); - gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); + perf_gtk__annotate_symbol(scrolled_window, sym, map, evidx, hbt); + return 0; +} - gtk_container_add(GTK_CONTAINER(window), vbox); +void perf_gtk__show_annotations(void) +{ + GtkWidget *window; - perf_gtk__annotate_symbol(scrolled_window, sym, map, evidx, hbt); + if (!perf_gtk__is_active_context(pgctx)) + return; + window = pgctx->main_window; gtk_widget_show_all(window); perf_gtk__resize_window(window); @@ -181,5 +202,4 @@ int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, gtk_main(); perf_gtk__deactivate_context(&pgctx); - return 0; } diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h index 5d3693754828..3d96785ef155 100644 --- a/tools/perf/ui/gtk/gtk.h +++ b/tools/perf/ui/gtk/gtk.h @@ -10,6 +10,7 @@ struct perf_gtk_context { GtkWidget *main_window; + GtkWidget *notebook; #ifdef HAVE_GTK_INFO_BAR GtkWidget *info_bar; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index a8ccbda4aeb7..c422440fe611 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -164,6 +164,8 @@ static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx, { return symbol__gtk_annotate(he->ms.sym, he->ms.map, evidx, hbt); } + +void perf_gtk__show_annotations(void); #else static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused, int evidx __maybe_unused, @@ -172,6 +174,8 @@ static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused, { return 0; } + +static inline void perf_gtk__show_annotations(void) {} #endif extern const char *disassembler_style; -- cgit v1.2.3-59-g8ed1b From 85df3b3769222894e9692b383c7af124b7721086 Mon Sep 17 00:00:00 2001 From: Vinson Lee Date: Wed, 13 Feb 2013 13:48:58 -0800 Subject: perf tools: Fix build with bison 2.3 and older. The %name-prefix "prefix" syntax is not available on bison 2.3 and older. Substitute with the -p "prefix" command-line option for compatibility with older versions of bison. This patch fixes this build error with older versions of bison. CC util/sysfs.o BISON util/pmu-bison.c util/pmu.y:2.14-24: syntax error, unexpected string, expecting = make: *** [util/pmu-bison.c] Error 1 Signed-off-by: Vinson Lee Tested-by: Li Zefan Cc: stable@vger.kernel.org # 3.4+ Cc: Ingo Molnar Cc: Jiri Olsa Cc: Li Zefan Cc: Namhyung Kim Cc: Paul Mackerras Cc: Pekka Enberg Link: http://lkml.kernel.org/r/1360792138-29186-1-git-send-email-vlee@twitter.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 4 ++-- tools/perf/util/parse-events.y | 1 - tools/perf/util/pmu.y | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index b90528d42b03..a2108ca1cc17 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -296,13 +296,13 @@ $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-event $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c: util/parse-events.y - $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c + $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_ $(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c: util/pmu.y - $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c + $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_ $(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 4de2fdca98c8..afc44c18dfe1 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -1,5 +1,4 @@ %pure-parser -%name-prefix "parse_events_" %parse-param {void *_data} %parse-param {void *scanner} %lex-param {void* scanner} diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y index ec898047ebb9..bfd7e8509869 100644 --- a/tools/perf/util/pmu.y +++ b/tools/perf/util/pmu.y @@ -1,5 +1,4 @@ -%name-prefix "perf_pmu_" %parse-param {struct list_head *format} %parse-param {char *name} -- cgit v1.2.3-59-g8ed1b