Skip to content

Commit

Permalink
perf probe: Support glob wildcards for function name
Browse files Browse the repository at this point in the history
Support glob wildcards for function name when adding new probes. This
will allow us to build caches of function-entry level information with
$params.

e.g.
  ----
  # perf probe --no-inlines --add 'kmalloc* $params'
  Added new events:
    probe:kmalloc_slab   (on kmalloc* with $params)
    probe:kmalloc_large_node (on kmalloc* with $params)
    probe:kmalloc_order_trace (on kmalloc* with $params)

  You can now use it in all perf tools, such as:

        perf record -e probe:kmalloc_order_trace -aR sleep 1

  # perf probe --list
    probe:kmalloc_large_node (on kmalloc_large_node@mm/slub.c with size flags node)
    probe:kmalloc_order_trace (on kmalloc_order_trace@mm/slub.c with size flags order)
    probe:kmalloc_slab   (on kmalloc_slab@mm/slab_common.c with size flags)
  ----

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20150508010335.24812.19972.stgit@localhost.localdomain
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Masami Hiramatsu authored and Arnaldo Carvalho de Melo committed May 8, 2015
1 parent 6cfd1f6 commit 4c85935
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 11 deletions.
16 changes: 16 additions & 0 deletions tools/perf/util/dwarf-aux.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,26 @@ int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
{
const char *name;

name = dwarf_diename(dw_die);
return name ? (strcmp(tname, name) == 0) : false;
}

/**
* die_match_name - Match diename and glob
* @dw_die: a DIE
* @glob: a string of target glob pattern
*
* Glob matching the name of @dw_die and @glob. Return false if matching fail.
*/
bool die_match_name(Dwarf_Die *dw_die, const char *glob)
{
const char *name;

name = dwarf_diename(dw_die);
return name ? strglobmatch(name, glob) : false;
}

/**
* die_get_call_lineno - Get callsite line number of inline-function instance
* @in_die: a DIE of an inlined function instance
Expand Down
3 changes: 3 additions & 0 deletions tools/perf/util/dwarf-aux.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ extern bool die_is_func_instance(Dwarf_Die *dw_die);
/* Compare diename and tname */
extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);

/* Matching diename with glob pattern */
extern bool die_match_name(Dwarf_Die *dw_die, const char *glob);

/* Get callsite line number of inline-function instance */
extern int die_get_call_lineno(Dwarf_Die *in_die);

Expand Down
19 changes: 14 additions & 5 deletions tools/perf/util/probe-event.c
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,11 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs,
if (!tmp)
return -ENOMEM;
}
free(tevs[i].point.symbol);
/* If we have no realname, use symbol for it */
if (!tevs[i].point.realname)
tevs[i].point.realname = tevs[i].point.symbol;
else
free(tevs[i].point.symbol);
tevs[i].point.symbol = tmp;
tevs[i].point.offset = tevs[i].point.address -
reloc_sym->unrelocated_addr;
Expand Down Expand Up @@ -1900,6 +1904,7 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
free(tev->event);
free(tev->group);
free(tev->point.symbol);
free(tev->point.realname);
free(tev->point.module);
for (i = 0; i < tev->nargs; i++) {
free(tev->args[i].name);
Expand Down Expand Up @@ -2377,6 +2382,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
struct strlist *namelist;
LIST_HEAD(blacklist);
struct kprobe_blacklist_node *node;
bool safename;

if (pev->uprobes)
fd = open_uprobe_events(true);
Expand All @@ -2402,6 +2408,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
pr_debug("No kprobe blacklist support, ignored\n");
}

safename = (pev->point.function && !strisglob(pev->point.function));
ret = 0;
pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
for (i = 0; i < ntevs; i++) {
Expand All @@ -2420,10 +2427,10 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
if (pev->event)
event = pev->event;
else
if (pev->point.function)
if (safename)
event = pev->point.function;
else
event = tev->point.symbol;
event = tev->point.realname;
if (pev->group)
group = pev->group;
else
Expand Down Expand Up @@ -2488,9 +2495,11 @@ static int find_probe_functions(struct map *map, char *name)
{
int found = 0;
struct symbol *sym;
struct rb_node *tmp;

map__for_each_symbol_by_name(map, name, sym) {
found++;
map__for_each_symbol(map, sym, tmp) {
if (strglobmatch(sym->name, name))
found++;
}

return found;
Expand Down
1 change: 1 addition & 0 deletions tools/perf/util/probe-event.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ extern bool probe_event_dry_run;

/* kprobe-tracer and uprobe-tracer tracing point */
struct probe_trace_point {
char *realname; /* function real name (if needed) */
char *symbol; /* Base symbol */
char *module; /* Module name */
unsigned long offset; /* Offset from symbol */
Expand Down
27 changes: 21 additions & 6 deletions tools/perf/util/probe-finder.c
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
}
/* If the function name is given, that's what user expects */
if (fsp->function) {
if (die_compare_name(fn_die, fsp->function)) {
if (die_match_name(fn_die, fsp->function)) {
memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
fsp->found = true;
return 1;
Expand Down Expand Up @@ -920,13 +920,14 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)

/* Check tag and diename */
if (!die_is_func_def(sp_die) ||
!die_compare_name(sp_die, pp->function))
!die_match_name(sp_die, pp->function))
return DWARF_CB_OK;

/* Check declared file */
if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die)))
return DWARF_CB_OK;

pr_debug("Matched function: %s\n", dwarf_diename(sp_die));
pf->fname = dwarf_decl_file(sp_die);
if (pp->line) { /* Function relative line */
dwarf_decl_line(sp_die, &pf->lno);
Expand All @@ -943,10 +944,20 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
/* TODO: Check the address in this function */
param->retval = call_probe_finder(sp_die, pf);
}
} else if (!probe_conf.no_inlines)
} else if (!probe_conf.no_inlines) {
/* Inlined function: search instances */
param->retval = die_walk_instances(sp_die,
probe_point_inline_cb, (void *)pf);
/* This could be a non-existed inline definition */
if (param->retval == -ENOENT && strisglob(pp->function))
param->retval = 0;
}

/* We need to find other candidates */
if (strisglob(pp->function) && param->retval >= 0) {
param->retval = 0; /* We have to clear the result */
return DWARF_CB_OK;
}

return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
}
Expand Down Expand Up @@ -975,7 +986,7 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
if (dwarf_tag(param->sp_die) != DW_TAG_subprogram)
return DWARF_CB_OK;

if (die_compare_name(param->sp_die, param->function)) {
if (die_match_name(param->sp_die, param->function)) {
if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die))
return DWARF_CB_OK;

Expand Down Expand Up @@ -1028,7 +1039,7 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
return -ENOMEM;

/* Fastpath: lookup by function name from .debug_pubnames section */
if (pp->function) {
if (pp->function && !strisglob(pp->function)) {
struct pubname_callback_param pubname_param = {
.function = pp->function,
.file = pp->file,
Expand Down Expand Up @@ -1177,6 +1188,10 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
if (ret < 0)
return ret;

tev->point.realname = strdup(dwarf_diename(sc_die));
if (!tev->point.realname)
return -ENOMEM;

pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
tev->point.offset);

Expand Down Expand Up @@ -1535,7 +1550,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
return DWARF_CB_OK;

if (die_is_func_def(sp_die) &&
die_compare_name(sp_die, lr->function)) {
die_match_name(sp_die, lr->function)) {
lf->fname = dwarf_decl_file(sp_die);
dwarf_decl_line(sp_die, &lr->offset);
pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
Expand Down
4 changes: 4 additions & 0 deletions tools/perf/util/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ char **argv_split(const char *str, int *argcp);
void argv_free(char **argv);
bool strglobmatch(const char *str, const char *pat);
bool strlazymatch(const char *str, const char *pat);
static inline bool strisglob(const char *str)
{
return strpbrk(str, "*?[") != NULL;
}
int strtailcmp(const char *s1, const char *s2);
char *strxfrchar(char *s, char from, char to);
unsigned long convert_unit(unsigned long value, char *unit);
Expand Down

0 comments on commit 4c85935

Please sign in to comment.