From 0ab061cd523a7f2dbf1b59aab0542cb0ab2e4633 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 21 Apr 2010 15:56:16 -0400 Subject: [PATCH 1/5] perf tools: Initialize dso->node member in dso__new If dso->node member is not initialized, it causes a segmentation fault when adding to other lists. It should be initilized in dso__new(). Signed-off-by: Masami Hiramatsu Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Mike Galbraith Cc: Frederic Weisbecker Cc: Ingo Molnar LKML-Reference: : <20100421195616.24664.89980.stgit@localhost6.localdomain6> Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e782e7db16c5..e77c33a11de3 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -189,6 +189,7 @@ struct dso *dso__new(const char *name) self->sorted_by_name = 0; self->has_build_id = 0; self->kernel = DSO_TYPE_USER; + INIT_LIST_HEAD(&self->node); } return self; From 15eca306ec95e164d05457f9f27c722f69af6d18 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 21 Apr 2010 15:56:24 -0400 Subject: [PATCH 2/5] perf probe: Fix to use symtab only if no debuginfo Fix perf probe to use symtab only if there is no debuginfo, because debuginfo has more information than symtab. If we can't find a function in debuginfo, we never find it in symtab. Signed-off-by: Masami Hiramatsu Reported-by: Arnaldo Carvalho de Melo Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Frederic Weisbecker Cc: Ingo Molnar LKML-Reference: <20100421195624.24664.46214.stgit@localhost6.localdomain6> Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 4fb480367c3e..5d3baec216e3 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -180,15 +180,16 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, return -ENOENT; } /* Error path : ntevs < 0 */ - if (need_dwarf) { - if (ntevs == -EBADF) - pr_warning("No dwarf info found in the vmlinux - " - "please rebuild with CONFIG_DEBUG_INFO=y.\n"); - return ntevs; + pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); + if (ntevs == -EBADF) { + pr_warning("Warning: No dwarf info found in the vmlinux - " + "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); + if (!need_dwarf) { + pr_debug("Trying to use symbols.\nn"); + return 0; + } } - pr_debug("An error occurred in debuginfo analysis." - " Try to use symbols.\n"); - return 0; + return ntevs; } #define LINEBUF_SIZE 256 From 5d1ee0413c8e2e0aa48510b1edfb3c4d2d43455b Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 21 Apr 2010 15:56:32 -0400 Subject: [PATCH 3/5] perf probe: Fix to exit callback soon after finding too many probe points Fix to exit callback soon after finding too many probe points. Don't try to continue searching because it already failed. Signed-off-by: Masami Hiramatsu Reported-by: Arnaldo Carvalho de Melo Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Frederic Weisbecker Cc: Ingo Molnar LKML-Reference: <20100421195632.24664.42598.stgit@localhost6.localdomain6> Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-finder.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index e7ee52fd0e09..0d795bc3e1a8 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -871,6 +871,8 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) (uintmax_t)pf->addr); param->retval = convert_probe_point(in_die, pf); + if (param->retval < 0) + return DWARF_CB_ABORT; } return DWARF_CB_OK; @@ -1106,6 +1108,8 @@ static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) return DWARF_CB_OK; param->retval = line_range_add_line(src, lineno, lf->lr); + if (param->retval < 0) + return DWARF_CB_ABORT; return DWARF_CB_OK; } From ef4a356574426877d569f8b6579325537eb7909b Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 21 Apr 2010 15:56:40 -0400 Subject: [PATCH 4/5] perf probe: Add --max-probes option Add --max-probes option to change the maximum limit of findable probe points per event, since inlined function can be expanded into thousands of probe points. Default value is 128. Signed-off-by: Masami Hiramatsu Suggested-by: Arnaldo Carvalho de Melo Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Frederic Weisbecker Cc: Ingo Molnar LKML-Reference: <20100421195640.24664.62984.stgit@localhost6.localdomain6> Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-probe.txt | 3 +++ tools/perf/builtin-probe.c | 9 ++++++++- tools/perf/util/probe-event.c | 17 ++++++++++------- tools/perf/util/probe-event.h | 4 ++-- tools/perf/util/probe-finder.c | 11 ++++++----- tools/perf/util/probe-finder.h | 6 ++++-- 6 files changed, 33 insertions(+), 17 deletions(-) diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 63c25d304880..94a258c96a44 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -62,6 +62,9 @@ OPTIONS Dry run. With this option, --add and --del doesn't execute actual adding and removal operations. +--max-probes:: + Set the maximum number of probe points for an event. Default is 128. + PROBE SYNTAX ------------ Probe points are defined by following syntax. diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c1e54035e8cf..61c6d70732c9 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -54,6 +54,7 @@ static struct { struct perf_probe_event events[MAX_PROBES]; struct strlist *dellist; struct line_range line_range; + int max_probe_points; } params; @@ -179,6 +180,8 @@ static const struct option options[] = { "file", "vmlinux pathname"), #endif OPT__DRY_RUN(&probe_event_dry_run), + OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, + "Set how many probe points can be found for a probe."), OPT_END() }; @@ -200,6 +203,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) } } + if (params.max_probe_points == 0) + params.max_probe_points = MAX_PROBES; + if ((!params.nevents && !params.dellist && !params.list_events && !params.show_lines)) usage_with_options(probe_usage, options); @@ -246,7 +252,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) if (params.nevents) { ret = add_perf_probe_events(params.events, params.nevents, - params.force_add); + params.force_add, + params.max_probe_points); if (ret < 0) { pr_err(" Error: Failed to add events. (%d)\n", ret); return ret; diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 5d3baec216e3..9ded38ced234 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -150,7 +150,8 @@ static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, /* Try to find perf_probe_event with debuginfo */ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, - struct kprobe_trace_event **tevs) + struct kprobe_trace_event **tevs, + int max_tevs) { bool need_dwarf = perf_probe_event_need_dwarf(pev); int fd, ntevs; @@ -166,7 +167,7 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, } /* Searching trace events corresponding to probe event */ - ntevs = find_kprobe_trace_events(fd, pev, tevs); + ntevs = find_kprobe_trace_events(fd, pev, tevs, max_tevs); close(fd); if (ntevs > 0) { /* Succeeded to find trace events */ @@ -318,7 +319,8 @@ static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, } static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, - struct kprobe_trace_event **tevs __unused) + struct kprobe_trace_event **tevs __unused, + int max_tevs __unused) { if (perf_probe_event_need_dwarf(pev)) { pr_warning("Debuginfo-analysis is not supported.\n"); @@ -1408,14 +1410,15 @@ static int __add_kprobe_trace_events(struct perf_probe_event *pev, } static int convert_to_kprobe_trace_events(struct perf_probe_event *pev, - struct kprobe_trace_event **tevs) + struct kprobe_trace_event **tevs, + int max_tevs) { struct symbol *sym; int ret = 0, i; struct kprobe_trace_event *tev; /* Convert perf_probe_event with debuginfo */ - ret = try_to_find_kprobe_trace_events(pev, tevs); + ret = try_to_find_kprobe_trace_events(pev, tevs, max_tevs); if (ret != 0) return ret; @@ -1487,7 +1490,7 @@ struct __event_package { }; int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, - bool force_add) + bool force_add, int max_tevs) { int i, j, ret; struct __event_package *pkgs; @@ -1506,7 +1509,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, pkgs[i].pev = &pevs[i]; /* Convert with or without debuginfo */ ret = convert_to_kprobe_trace_events(pkgs[i].pev, - &pkgs[i].tevs); + &pkgs[i].tevs, max_tevs); if (ret < 0) goto end; pkgs[i].ntevs = ret; diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index e7ff0d02c0d4..e9db1a214ca4 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -115,8 +115,8 @@ extern void clear_kprobe_trace_event(struct kprobe_trace_event *tev); extern int parse_line_range_desc(const char *cmd, struct line_range *lr); -extern int add_perf_probe_events(struct perf_probe_event *pevs, int ntevs, - bool force_add); +extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, + bool force_add, int max_probe_points); extern int del_perf_probe_events(struct strlist *dellist); extern int show_perf_probe_events(void); extern int show_line_range(struct line_range *lr); diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 0d795bc3e1a8..562b1443e785 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -626,8 +626,9 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) Dwarf_Attribute fb_attr; size_t nops; - if (pf->ntevs == MAX_PROBES) { - pr_warning("Too many( > %d) probe point found.\n", MAX_PROBES); + if (pf->ntevs == pf->max_tevs) { + pr_warning("Too many( > %d) probe point found.\n", + pf->max_tevs); return -ERANGE; } tev = &pf->tevs[pf->ntevs++]; @@ -932,9 +933,9 @@ static int find_probe_point_by_func(struct probe_finder *pf) /* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, - struct kprobe_trace_event **tevs) + struct kprobe_trace_event **tevs, int max_tevs) { - struct probe_finder pf = {.pev = pev}; + struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs}; struct perf_probe_point *pp = &pev->point; Dwarf_Off off, noff; size_t cuhl; @@ -942,7 +943,7 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, Dwarf *dbg; int ret = 0; - pf.tevs = zalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES); + pf.tevs = zalloc(sizeof(struct kprobe_trace_event) * max_tevs); if (pf.tevs == NULL) return -ENOMEM; *tevs = pf.tevs; diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 310ce897229c..66f1980e3855 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h @@ -18,7 +18,8 @@ static inline int is_c_varname(const char *name) #ifdef DWARF_SUPPORT /* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, - struct kprobe_trace_event **tevs); + struct kprobe_trace_event **tevs, + int max_tevs); /* Find a perf_probe_point from debuginfo */ extern int find_perf_probe_point(int fd, unsigned long addr, @@ -32,7 +33,8 @@ extern int find_line_range(int fd, struct line_range *lr); struct probe_finder { struct perf_probe_event *pev; /* Target probe event */ struct kprobe_trace_event *tevs; /* Result trace events */ - int ntevs; /* number of trace events */ + int ntevs; /* Number of trace events */ + int max_tevs; /* Max number of trace events */ /* For function searching */ int lno; /* Line number */ From f93830fbb06b67848c762f2177c06cc3cbb97deb Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 26 Apr 2010 15:39:54 -0300 Subject: [PATCH 5/5] perf tools: Fix libdw-dev package name in error message The headers required for DWARF support are provided by the libdw-dev package in Debian-based distros. This patch corrects the elfutils-dev package name to libdw-dev in the Makefile error message when libdw.h is not found. Signed-off-by: Stefan Hajnoczi Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Masami Hiramatsu Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Tom Zanussi LKML-Reference: <1272292023-9869-1-git-send-email-stefanha@linux.vnet.ibm.com> Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/Makefile b/tools/perf/Makefile index e8bf2e1ab497..3ac6b677becd 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -504,7 +504,7 @@ PERFLIBS = $(LIB_FILE) ifndef NO_DWARF ifneq ($(shell sh -c "(echo '\#include '; echo '\#include '; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) - msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev); + msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/libdw-dev); NO_DWARF := 1 endif # Dwarf support endif # NO_DWARF