perf-probe --cache and SDT support
v4 cover perf-probe --cache and SDT support
Hi,
Here is the 4th version of the patchset for probe-cache and initial SDT support which are going to be perf-cache finally.
The previous version is here; https://lkml.org/lkml/2015/8/15/52
This version fixes some bugs and improve wildcard support ( including automatic target binary selection, we don't need -x option for SDT/pre-cached events any more :) ), and drops perf-record support currently because it seems more work on cleanup side.
BTW, since I couldn't find list_dir function in Arnaldo's mail, so this series still have a patch to add lsdir().
Note that all SDT events have "sdt_" prefix on the provider name, because of easier to distinguish between other named caches.
TODOs:
- (perf record) Support SDT event recording directly
- (perf record) Support @FILE/@BUILDID suffix to record specific SDTs.
- (perf record) Try to unregister SDT events after record.
- (ftrace) Support multiple SDTs on single event.
Done:
- (perf probe) Allow glob matching for pre-cached events.
- (perf probe) Removes -x option when using pre-cached events.
- (perf probe) Support @FILE/@BUILDID suffix for pre-cached events.
- (perf buildid-cache) Fallback to old style buildid-cache.
Thank you,
---
Hemant Kumar (1):
perf/sdt: ELF support for SDT
Masami Hiramatsu (18):
perf probe: Use strbuf for making strings
perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid perf buildid-cache: Fall back to the old style build-id cache
perf: Add lsdir to read a directory
perf-buildid-cache: Use lsdir for looking up buildid caches
perf-probe: Let probe_file__add_event return 0 if succeeded
perf probe: Add --cache option to cache the probe definitions perf probe: Use cache entry if possible
perf probe: Show all cached probes
perf probe: Remove caches when --cache is given
perf probe: Add group name support
perf-probe: Set default kprobe group name if it is not given perf buildid-cache: Scan and import user SDT events to probe cache perf probe: Accept %sdt and %cached event name
perf-list: Show SDT and pre-cached events
perf-list: Skip SDTs placed in invalid binaries
perf probe: Allow wildcard for cached events
perf probe: Support @BUILDID or @FILE suffix for SDT events
tools/perf/Documentation/perf-probe.txt | 24 + tools/perf/builtin-list.c | 4 tools/perf/builtin-probe.c | 30 + tools/perf/util/build-id.c | 278 ++++++++++-- tools/perf/util/build-id.h | 6 tools/perf/util/dso.h | 5 tools/perf/util/parse-events.c | 83 ++++ tools/perf/util/parse-events.h | 2 tools/perf/util/probe-event.c | 692 ++++++++++++++++++++++--------- tools/perf/util/probe-event.h | 9 tools/perf/util/probe-file.c | 495 ++++++++++++++++++++++ tools/perf/util/probe-file.h | 32 + tools/perf/util/probe-finder.c | 14 - tools/perf/util/symbol-elf.c | 252 +++++++++++ tools/perf/util/symbol.c | 15 - tools/perf/util/symbol.h | 22 + tools/perf/util/util.c | 34 ++ tools/perf/util/util.h | 4 18 files changed, 1725 insertions(+), 276 deletions(-)
--
Masami Hiramatsu
PATCH v4 1/19 perf probe: Use strbuf for making strings
From: Masami Hiramatsu <[email protected]>
Replace many fixed-length char array with strbuf to stringify perf_probe_event and probe_trace_event etc.
---
Changes in v4:
- Update for the latest kernel.
- Remove "probe-event.c" from title and body, because this also changes probe-finder.c too :)
Changes in v3:
- Remove unneeded strbuf_release(). (Thanks Namhyung!)
Changes in v2:
- Make perf_probe_event__sprintf() simpler.
--- tools/perf/util/probe-event.c | 246 ++++++++++++++-------------------------- tools/perf/util/probe-event.h | 2 tools/perf/util/probe-finder.c | 14 +- 3 files changed, 93 insertions(+), 169 deletions(-)
tools/perf/util/probe-event.c +85 -161
@@ -1618,69 +1618,51 @@ out: }/* Compose only probe arg */ -int synthesize_perf_probe_arg (struct perf_probe_arg *pa,char *buf,size_t len) +char *synthesize_perf_probe_arg (struct perf_probe_arg *pa) {struct perf_probe_arg_field *field = pa->field; -int ret; -char *tmp = buf; +struct strbuf buf; +char *ret; +strbuf_init (&buf,64 );if (pa->name && pa->var) - ret =e_snprintf (tmp, len,"%s=%s" , pa->name, pa->var); +strbuf_addf (&buf,"%s=%s" , pa->name, pa->var);else - ret =e_snprintf (tmp, len,"%s" , pa->name ? pa->name : pa->var); -if (ret <=0 ) - goto error; - tmp += ret; - len -= ret; +strbuf_addstr (&buf, pa->name ?: pa->var);while (field) {if (field->name[0 ] =='[' ) - ret =e_snprintf (tmp, len,"%s" , field->name); +strbuf_addstr (&buf, field->name);else - ret =e_snprintf (tmp, len,"%s%s" , - field->ref ?"->" :"." , field->name); -if (ret <=0 ) - goto error; - tmp += ret; - len -= ret; +strbuf_addf (&buf,"%s%s" , field->ref ?"->" :"." , + field->name); field = field->next; } -if (pa->type) { - ret =e_snprintf (tmp, len,":%s" , pa->type); -if (ret <=0 ) - goto error; - tmp += ret; - len -= ret; - } +if (pa->type) +strbuf_addf (&buf,":%s" , pa->type); + + ret =strbuf_detach (&buf,NULL ); -return tmp - buf; -error: -pr_debug ("Failed to synthesize perf probe argument: %d\n" , ret);return ret; }/* Compose only probe point (not argument) */ static char *synthesize_perf_probe_point (struct perf_probe_point *pp) { -char *buf, *tmp; -char offs[32 ] ="" , line[32 ] ="" , file[32 ] ="" ; -int ret, len; - - buf =zalloc (MAX_CMDLEN ); -if (buf ==NULL ) { - ret = -ENOMEM ; - goto error; - } -if (pp->offset) { - ret =e_snprintf (offs,32 ,"+%lu" , pp->offset); -if (ret <=0 ) - goto error; - } -if (pp->line) { - ret =e_snprintf (line,32 ,":%d" , pp->line); -if (ret <=0 ) - goto error; +struct strbuf buf; +char *tmp; +int len; + +strbuf_init (&buf,64 ); +if (pp->function) { +strbuf_addstr (&buf, pp->function); +if (pp->offset) +strbuf_addf (&buf,"+%lu" , pp->offset); +else if (pp->line) +strbuf_addf (&buf,":%d" , pp->line); +else if (pp->retprobe) +strbuf_addstr (&buf,"%return" ); }if (pp->file) { tmp = pp->file;
@@ -1689,25 +1671,12 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) tmp =strchr (pp->file + len -30 ,'/' ); tmp = tmp ? tmp +1 : pp->file + len -30 ; } - ret =e_snprintf (file,32 ,"@%s" , tmp); -if (ret <=0 ) - goto error; +strbuf_addf (&buf,"@%s" , tmp); +if (!pp->function && pp->line) +strbuf_addf (&buf,":%d" , pp->line); } -if (pp->function) - ret =e_snprintf (buf,MAX_CMDLEN ,"%s%s%s%s%s" , pp->function, - offs, pp->retprobe ?"%return" :"" , line, - file); -else - ret =e_snprintf (buf,MAX_CMDLEN ,"%s%s" , file, line); -if (ret <=0 ) - goto error; - -return buf; -error: -pr_debug ("Failed to synthesize perf probe point: %d\n" , ret); -free (buf); -return NULL ; +return strbuf_detach (&buf,NULL ); }#if 0
@@ -1736,45 +1705,30 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev)#endif static int __synthesize_probe_trace_arg_ref (struct probe_trace_arg_ref *ref, -char **buf,size_t *buflen, -int depth) +struct strbuf *buf,int depth) { -int ret;if (ref->next) { depth =__synthesize_probe_trace_arg_ref (ref->next, buf, - buflen, depth +1 ); + depth +1 );if (depth <0 ) goto out; } - - ret =e_snprintf (*buf, *buflen,"%+ld(" , ref->offset); -if (ret <0 ) - depth = ret; -else { - *buf += ret; - *buflen -= ret; - } +strbuf_addf (buf,"%+ld(" , ref->offset); out:return depth; - }static int synthesize_probe_trace_arg (struct probe_trace_arg *arg, -char *buf,size_t buflen) +struct strbuf *buf) {struct probe_trace_arg_ref *ref = arg->ref; -int ret, depth =0 ; -char *tmp = buf; +int depth =0 ;/* Argument name or separator */ if (arg->name) - ret =e_snprintf (buf, buflen," %s=" , arg->name); +strbuf_addf (buf," %s=" , arg->name);else - ret =e_snprintf (buf, buflen," " ); -if (ret <0 ) -return ret; - buf += ret; - buflen -= ret; +strbuf_addch (buf,' ' );/* Special case: @XXX */ if (arg->value[0 ] =='@' && arg->ref)
@@ -1782,60 +1736,41 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,/* Dereferencing arguments */ if (ref) { - depth =__synthesize_probe_trace_arg_ref (ref, &buf, - &buflen,1 ); + depth =__synthesize_probe_trace_arg_ref (ref, buf,1 );if (depth <0 )return depth; }/* Print argument value */ if (arg->value[0 ] =='@' && arg->ref) - ret =e_snprintf (buf, buflen,"%s%+ld" , arg->value, - arg->ref->offset); +strbuf_addf (buf,"%s%+ld" , arg->value, arg->ref->offset);else - ret =e_snprintf (buf, buflen,"%s" , arg->value); -if (ret <0 ) -return ret; - buf += ret; - buflen -= ret; +strbuf_addstr (buf, arg->value);/* Closing */ -while (depth--) { - ret =e_snprintf (buf, buflen,")" ); -if (ret <0 ) -return ret; - buf += ret; - buflen -= ret; - } +while (depth--) +strbuf_addch (buf,')' );/* Print argument type */ -if (arg->type) { - ret =e_snprintf (buf, buflen,":%s" , arg->type); -if (ret <=0 ) -return ret; - buf += ret; - } +if (arg->type) +strbuf_addf (buf,":%s" , arg->type); -return buf - tmp; +return 0 ; }char *synthesize_probe_trace_command (struct probe_trace_event *tev) {struct probe_trace_point *tp = &tev->point; -char *buf; -int i, len, ret; - - buf =zalloc (MAX_CMDLEN ); -if (buf ==NULL ) -return NULL ; - - len =e_snprintf (buf,MAX_CMDLEN ,"%c:%s/%s " , tp->retprobe ?'r' :'p' , - tev->group, tev->event); -if (len <=0 ) - goto error; +struct strbuf buf; +char *ret =NULL ; +int i;/* Uprobes must have tp->module */ if (tev->uprobes && !tp->module) - goto error; +return NULL ; + +strbuf_init (&buf,32 ); +strbuf_addf (&buf,"%c:%s/%s " , tp->retprobe ?'r' :'p' , + tev->group, tev->event);/* * If tp->address == 0, then this point must be a * absolute address uprobe.
@@ -1849,34 +1784,23 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)/* Use the tp->address for uprobes */ if (tev->uprobes) - ret =e_snprintf (buf + len,MAX_CMDLEN - len,"%s:0x%lx" , - tp->module, tp->address); +strbuf_addf (&buf,"%s:0x%lx" , tp->module, tp->address);else if (!strncmp (tp->symbol,"0x" ,2 ))/* Absolute address. See try_to_find_absolute_address() */ - ret =e_snprintf (buf + len,MAX_CMDLEN - len,"%s%s0x%lx" , - tp->module ?:"" , tp->module ?":" :"" , - tp->address); +strbuf_addf (&buf,"%s%s0x%lx" , tp->module ?:"" , + tp->module ?":" :"" , tp->address);else - ret =e_snprintf (buf + len,MAX_CMDLEN - len,"%s%s%s+%lu" , - tp->module ?:"" , tp->module ?":" :"" , - tp->symbol, tp->offset); - -if (ret <=0 ) - goto error; - len += ret; +strbuf_addf (&buf,"%s%s%s+%lu" , tp->module ?:"" , + tp->module ?":" :"" , tp->symbol, tp->offset); -for (i =0 ; i < tev->nargs; i++) { - ret =synthesize_probe_trace_arg (&tev->args[i], buf + len, -MAX_CMDLEN - len); -if (ret <=0 ) +for (i =0 ; i < tev->nargs; i++) +if (synthesize_probe_trace_arg (&tev->args[i], &buf) <0 ) goto error; - len += ret; - } -return buf; + ret =strbuf_detach (&buf,NULL ); error: -free (buf); -return NULL ; +strbuf_release (&buf); +return ret; } static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
@@ -1958,7 +1882,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp,static int convert_to_perf_probe_event (struct probe_trace_event *tev,struct perf_probe_event *pev,bool is_kprobe) { -char buf[64 ] ="" ; +struct strbuf buf =STRBUF_INIT ;int i, ret;/* Convert event/group name */
@@ -1981,9 +1905,9 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,if (tev->args[i].name) pev->args[i].name =strdup (tev->args[i].name);else { - ret =synthesize_probe_trace_arg (&tev->args[i], - buf,64 ); - pev->args[i].name =strdup (buf); +strbuf_init (&buf,32 ); + ret =synthesize_probe_trace_arg (&tev->args[i], &buf); + pev->args[i].name =strbuf_detach (&buf,NULL ); }if (pev->args[i].name ==NULL && ret >=0 ) ret = -ENOMEM ;
@@ -2161,37 +2085,37 @@ static int perf_probe_event__sprintf(const char *group, const char *event,const char *module, struct strbuf *result) { - int i, ret; -char buf[128 ]; -char *place; + int i; +char *buf; -/* Synthesize only event probe point */ - place =synthesize_perf_probe_point (&pev->point); -if (!place) -return -EINVAL ; +if (asprintf (&buf,"%s:%s" , group, event) <0 ) +return -errno; +strbuf_addf (result," %-20s (on " , buf); +free (buf); - ret =e_snprintf (buf,128 ,"%s:%s" , group, event); -if (ret <0 ) - goto out; +/* Synthesize only event probe point */ + buf =synthesize_perf_probe_point (&pev->point); +if (!buf) +return -ENOMEM ; +strbuf_addstr (result, buf); +free (buf); -strbuf_addf (result," %-20s (on %s" , buf, place);if (module)strbuf_addf (result," in %s" , module);if (pev->nargs >0 ) {strbuf_add (result," with" ,5 );for (i =0 ; i < pev->nargs; i++) { - ret =synthesize_perf_probe_arg (&pev->args[i], - buf,128 ); -if (ret <0 ) - goto out; + buf =synthesize_perf_probe_arg (&pev->args[i]); +if (!buf) +return -ENOMEM ;strbuf_addf (result," %s" , buf); +free (buf); } }strbuf_addch (result,')' ); -out: -free (place); -return ret; + +return 0 ; }/* Show an event */
tools/perf/util/probe-event.h +1 -1
@@ -120,7 +120,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev);/* Events to command string */ char *synthesize_perf_probe_command (struct perf_probe_event *pev);char *synthesize_probe_trace_command (struct probe_trace_event *tev); -int synthesize_perf_probe_arg (struct perf_probe_arg *pa,char *buf,size_t len); +char *synthesize_perf_probe_arg (struct perf_probe_arg *pa);/* Check the perf_probe_event needs debuginfo */ bool perf_probe_event_need_dwarf (struct perf_probe_event *pev);
tools/perf/util/probe-finder.c +7 -7
@@ -553,7 +553,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)static int find_variable (Dwarf_Die *sc_die,struct probe_finder *pf) {Dwarf_Die vr_die; -char buf[32 ], *ptr; +char *buf, *ptr;int ret =0 ;/* Copy raw parameters */
@@ -563,13 +563,13 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)if (pf->pvar->name) pf->tvar->name =strdup (pf->pvar->name);else { - ret =synthesize_perf_probe_arg (pf->pvar, buf,32 ); -if (ret <0 ) -return ret; + buf =synthesize_perf_probe_arg (pf->pvar); +if (!buf) +return -ENOMEM ; ptr =strchr (buf,':' );/* Change type separator to _ */ if (ptr) *ptr ='_' ; - pf->tvar->name =strdup (buf); + pf->tvar->name = buf; }if (pf->tvar->name ==NULL )return -ENOMEM ;
@@ -1334,8 +1334,8 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)if (ret2 ==0 ) {strlist__add (vl->vars,strbuf_detach (&buf,NULL )); - } -strbuf_release (&buf); + }else +strbuf_release (&buf); } }
Arnaldo Carvalho de Melo
maintainerRe: [PATCH perf/core v4 01/19] perf probe: Use strbuf for making strings
Em Tue, Apr 26, 2016 at 06:02:11PM +0900, Masami Hiramatsu escreveu:
Quoted 4 lines
From: Masami Hiramatsu <[email protected]>
Replace many fixed-length char array with strbuf to stringify
perf_probe_eventandprobe_trace_eventetc.
Sure you want to do that? From time to time I try to reduce the strbuf usage, not grow it :-\
That is one of the last users of xrealloc(), via that ALLOC_GROW() thing.
- Arnaldo
Quoted 458 lines
Signed-off-by Masami Hiramatsu <[email protected]>Signed-off-by Masami Hiramatsu <[email protected]>---
Changes in v4:
- Update for the latest kernel.
- Remove "probe-event.c" from title and body, because this also changesprobe-finder.ctoo :)Changes in v3:
- Remove unneededstrbuf_release(). (Thanks Namhyung!)Changes in v2:
- Makeperf_probe_event__sprintf()simpler.--- tools/perf/util/probe-event.c | 246 ++++++++++++++-------------------------- tools/perf/util/probe-event.h | 2 tools/perf/util/probe-finder.c | 14 +- 3 files changed, 93 insertions(+), 169 deletions(-)tools/perf/util/probe-event.c +85
-161@@ -1618,69 +1618,51 @@ out: }/* Compose only probe arg */ -int synthesize_perf_probe_arg (struct perf_probe_arg *pa,char *buf,size_t len) +char *synthesize_perf_probe_arg (struct perf_probe_arg *pa) {struct perf_probe_arg_field *field = pa->field; -int ret; -char *tmp = buf; +struct strbuf buf; +char *ret; +strbuf_init (&buf,64 );if (pa->name && pa->var) - ret =e_snprintf (tmp, len,"%s=%s" , pa->name, pa->var); +strbuf_addf (&buf,"%s=%s" , pa->name, pa->var);else - ret =e_snprintf (tmp, len,"%s" , pa->name ? pa->name : pa->var); -if (ret <=0 ) - goto error; - tmp += ret; - len -= ret; +strbuf_addstr (&buf, pa->name ?: pa->var);while (field) {if (field->name[0 ] =='[' ) - ret =e_snprintf (tmp, len,"%s" , field->name); +strbuf_addstr (&buf, field->name);else - ret =e_snprintf (tmp, len,"%s%s" , - field->ref ?"->" :"." , field->name); -if (ret <=0 ) - goto error; - tmp += ret; - len -= ret; +strbuf_addf (&buf,"%s%s" , field->ref ?"->" :"." , + field->name); field = field->next; } -if (pa->type) { - ret =e_snprintf (tmp, len,":%s" , pa->type); -if (ret <=0 ) - goto error; - tmp += ret; - len -= ret; - } +if (pa->type) +strbuf_addf (&buf,":%s" , pa->type); + + ret =strbuf_detach (&buf,NULL ); -return tmp - buf; -error: -pr_debug ("Failed to synthesize perf probe argument: %d\n" , ret);return ret; }/* Compose only probe point (not argument) */ static char *synthesize_perf_probe_point (struct perf_probe_point *pp) { -char *buf, *tmp; -char offs[32 ] ="" , line[32 ] ="" , file[32 ] ="" ; -int ret, len; - - buf =zalloc (MAX_CMDLEN ); -if (buf ==NULL ) { - ret = -ENOMEM ; - goto error; - } -if (pp->offset) { - ret =e_snprintf (offs,32 ,"+%lu" , pp->offset); -if (ret <=0 ) - goto error; - } -if (pp->line) { - ret =e_snprintf (line,32 ,":%d" , pp->line); -if (ret <=0 ) - goto error; +struct strbuf buf; +char *tmp; +int len; + +strbuf_init (&buf,64 ); +if (pp->function) { +strbuf_addstr (&buf, pp->function); +if (pp->offset) +strbuf_addf (&buf,"+%lu" , pp->offset); +else if (pp->line) +strbuf_addf (&buf,":%d" , pp->line); +else if (pp->retprobe) +strbuf_addstr (&buf,"%return" ); }if (pp->file) { tmp = pp->file;@@ -1689,25 +1671,12 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) tmp =strchr (pp->file + len -30 ,'/' ); tmp = tmp ? tmp +1 : pp->file + len -30 ; } - ret =e_snprintf (file,32 ,"@%s" , tmp); -if (ret <=0 ) - goto error; +strbuf_addf (&buf,"@%s" , tmp); +if (!pp->function && pp->line) +strbuf_addf (&buf,":%d" , pp->line); } -if (pp->function) - ret =e_snprintf (buf,MAX_CMDLEN ,"%s%s%s%s%s" , pp->function, - offs, pp->retprobe ?"%return" :"" , line, - file); -else - ret =e_snprintf (buf,MAX_CMDLEN ,"%s%s" , file, line); -if (ret <=0 ) - goto error; - -return buf; -error: -pr_debug ("Failed to synthesize perf probe point: %d\n" , ret); -free (buf); -return NULL ; +return strbuf_detach (&buf,NULL ); }#if 0 @@ -1736,45 +1705,30 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev)#endif static int __synthesize_probe_trace_arg_ref (struct probe_trace_arg_ref *ref, -char **buf,size_t *buflen, -int depth) +struct strbuf *buf,int depth) { -int ret;if (ref->next) { depth =__synthesize_probe_trace_arg_ref (ref->next, buf, - buflen, depth +1 ); + depth +1 );if (depth <0 ) goto out; } - - ret =e_snprintf (*buf, *buflen,"%+ld(" , ref->offset); -if (ret <0 ) - depth = ret; -else { - *buf += ret; - *buflen -= ret; - } +strbuf_addf (buf,"%+ld(" , ref->offset); out:return depth; - }static int synthesize_probe_trace_arg (struct probe_trace_arg *arg, -char *buf,size_t buflen) +struct strbuf *buf) {struct probe_trace_arg_ref *ref = arg->ref; -int ret, depth =0 ; -char *tmp = buf; +int depth =0 ;/* Argument name or separator */ if (arg->name) - ret =e_snprintf (buf, buflen," %s=" , arg->name); +strbuf_addf (buf," %s=" , arg->name);else - ret =e_snprintf (buf, buflen," " ); -if (ret <0 ) -return ret; - buf += ret; - buflen -= ret; +strbuf_addch (buf,' ' );/* Special case: @XXX */ if (arg->value[0 ] =='@' && arg->ref)@@ -1782,60 +1736,41 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,/* Dereferencing arguments */ if (ref) { - depth =__synthesize_probe_trace_arg_ref (ref, &buf, - &buflen,1 ); + depth =__synthesize_probe_trace_arg_ref (ref, buf,1 );if (depth <0 )return depth; }/* Print argument value */ if (arg->value[0 ] =='@' && arg->ref) - ret =e_snprintf (buf, buflen,"%s%+ld" , arg->value, - arg->ref->offset); +strbuf_addf (buf,"%s%+ld" , arg->value, arg->ref->offset);else - ret =e_snprintf (buf, buflen,"%s" , arg->value); -if (ret <0 ) -return ret; - buf += ret; - buflen -= ret; +strbuf_addstr (buf, arg->value);/* Closing */ -while (depth--) { - ret =e_snprintf (buf, buflen,")" ); -if (ret <0 ) -return ret; - buf += ret; - buflen -= ret; - } +while (depth--) +strbuf_addch (buf,')' );/* Print argument type */ -if (arg->type) { - ret =e_snprintf (buf, buflen,":%s" , arg->type); -if (ret <=0 ) -return ret; - buf += ret; - } +if (arg->type) +strbuf_addf (buf,":%s" , arg->type); -return buf - tmp; +return 0 ; }char *synthesize_probe_trace_command (struct probe_trace_event *tev) {struct probe_trace_point *tp = &tev->point; -char *buf; -int i, len, ret; - - buf =zalloc (MAX_CMDLEN ); -if (buf ==NULL ) -return NULL ; - - len =e_snprintf (buf,MAX_CMDLEN ,"%c:%s/%s " , tp->retprobe ?'r' :'p' , - tev->group, tev->event); -if (len <=0 ) - goto error; +struct strbuf buf; +char *ret =NULL ; +int i;/* Uprobes must have tp->module */ if (tev->uprobes && !tp->module) - goto error; +return NULL ; + +strbuf_init (&buf,32 ); +strbuf_addf (&buf,"%c:%s/%s " , tp->retprobe ?'r' :'p' , + tev->group, tev->event);/* * If tp->address == 0, then this point must be a * absolute address uprobe. @@ -1849,34 +1784,23 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)/* Use the tp->address for uprobes */ if (tev->uprobes) - ret =e_snprintf (buf + len,MAX_CMDLEN - len,"%s:0x%lx" , - tp->module, tp->address); +strbuf_addf (&buf,"%s:0x%lx" , tp->module, tp->address);else if (!strncmp (tp->symbol,"0x" ,2 ))/* Absolute address. See try_to_find_absolute_address() */ - ret =e_snprintf (buf + len,MAX_CMDLEN - len,"%s%s0x%lx" , - tp->module ?:"" , tp->module ?":" :"" , - tp->address); +strbuf_addf (&buf,"%s%s0x%lx" , tp->module ?:"" , + tp->module ?":" :"" , tp->address);else - ret =e_snprintf (buf + len,MAX_CMDLEN - len,"%s%s%s+%lu" , - tp->module ?:"" , tp->module ?":" :"" , - tp->symbol, tp->offset); - -if (ret <=0 ) - goto error; - len += ret; +strbuf_addf (&buf,"%s%s%s+%lu" , tp->module ?:"" , + tp->module ?":" :"" , tp->symbol, tp->offset); -for (i =0 ; i < tev->nargs; i++) { - ret =synthesize_probe_trace_arg (&tev->args[i], buf + len, -MAX_CMDLEN - len); -if (ret <=0 ) +for (i =0 ; i < tev->nargs; i++) +if (synthesize_probe_trace_arg (&tev->args[i], &buf) <0 ) goto error; - len += ret; - } -return buf; + ret =strbuf_detach (&buf,NULL ); error: -free (buf); -return NULL ; +strbuf_release (&buf); +return ret; } static int find_perf_probe_point_from_map(struct probe_trace_point *tp,@@ -1958,7 +1882,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp,static int convert_to_perf_probe_event (struct probe_trace_event *tev,struct perf_probe_event *pev,bool is_kprobe) { -char buf[64 ] ="" ; +struct strbuf buf =STRBUF_INIT ;int i, ret;/* Convert event/group name */ @@ -1981,9 +1905,9 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,if (tev->args[i].name) pev->args[i].name =strdup (tev->args[i].name);else { - ret =synthesize_probe_trace_arg (&tev->args[i], - buf,64 ); - pev->args[i].name =strdup (buf); +strbuf_init (&buf,32 ); + ret =synthesize_probe_trace_arg (&tev->args[i], &buf); + pev->args[i].name =strbuf_detach (&buf,NULL ); }if (pev->args[i].name ==NULL && ret >=0 ) ret = -ENOMEM ;@@ -2161,37 +2085,37 @@ static int perf_probe_event__sprintf(const char *group, const char *event,const char *module, struct strbuf *result) { - int i, ret; -char buf[128 ]; -char *place; + int i; +char *buf; -/* Synthesize only event probe point */ - place =synthesize_perf_probe_point (&pev->point); -if (!place) -return -EINVAL ; +if (asprintf (&buf,"%s:%s" , group, event) <0 ) +return -errno; +strbuf_addf (result," %-20s (on " , buf); +free (buf); - ret =e_snprintf (buf,128 ,"%s:%s" , group, event); -if (ret <0 ) - goto out; +/* Synthesize only event probe point */ + buf =synthesize_perf_probe_point (&pev->point); +if (!buf) +return -ENOMEM ; +strbuf_addstr (result, buf); +free (buf); -strbuf_addf (result," %-20s (on %s" , buf, place);if (module)strbuf_addf (result," in %s" , module);if (pev->nargs >0 ) {strbuf_add (result," with" ,5 );for (i =0 ; i < pev->nargs; i++) { - ret =synthesize_perf_probe_arg (&pev->args[i], - buf,128 ); -if (ret <0 ) - goto out; + buf =synthesize_perf_probe_arg (&pev->args[i]); +if (!buf) +return -ENOMEM ;strbuf_addf (result," %s" , buf); +free (buf); } }strbuf_addch (result,')' ); -out: -free (place); -return ret; + +return 0 ; }/* Show an event */ tools/perf/util/probe-event.h +1
-1@@ -120,7 +120,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev);/* Events to command string */ char *synthesize_perf_probe_command (struct perf_probe_event *pev);char *synthesize_probe_trace_command (struct probe_trace_event *tev); -int synthesize_perf_probe_arg (struct perf_probe_arg *pa,char *buf,size_t len); +char *synthesize_perf_probe_arg (struct perf_probe_arg *pa);/* Check the perf_probe_event needs debuginfo */ bool perf_probe_event_need_dwarf (struct perf_probe_event *pev);tools/perf/util/probe-finder.c +7
-7@@ -553,7 +553,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)static int find_variable (Dwarf_Die *sc_die,struct probe_finder *pf) {Dwarf_Die vr_die; -char buf[32 ], *ptr; +char *buf, *ptr;int ret =0 ;/* Copy raw parameters */ @@ -563,13 +563,13 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)if (pf->pvar->name) pf->tvar->name =strdup (pf->pvar->name);else { - ret =synthesize_perf_probe_arg (pf->pvar, buf,32 ); -if (ret <0 ) -return ret; + buf =synthesize_perf_probe_arg (pf->pvar); +if (!buf) +return -ENOMEM ; ptr =strchr (buf,':' );/* Change type separator to _ */ if (ptr) *ptr ='_' ; - pf->tvar->name =strdup (buf); + pf->tvar->name = buf; }if (pf->tvar->name ==NULL )return -ENOMEM ;@@ -1334,8 +1334,8 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)if (ret2 ==0 ) {strlist__add (vl->vars,strbuf_detach (&buf,NULL )); - } -strbuf_release (&buf); + }else +strbuf_release (&buf); } }
Re: [PATCH perf/core v4 01/19] perf probe: Use strbuf for making strings
Quoted 8 lines · On Tue, 26 Apr 2016 10:36:57 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Tue, Apr 26, 2016 at 06:02:11PM +0900, Masami Hiramatsu escreveu:
Quoted 4 lines
From: Masami Hiramatsu <[email protected]>
Replace many fixed-length char array with strbuf to stringify
perf_probe_eventandprobe_trace_eventetc.Sure you want to do that? From time to time I try to reduce the strbuf usage, not grow it :-\
Aah, I got what you want.
Quoted 3 lines
That is one of the last users of
xrealloc(), via thatALLOC_GROW()thing.
Hmm I'm not sure what you considering, memory usage? or code reducing? I also would like to remove e_snprintf() use in perf probe by replacing with strbuf functions. I'd like to find better way.
Thank you,
Quoted 461 lines
- Arnaldo
Quoted 458 lines
Signed-off-by Masami Hiramatsu <[email protected]>Signed-off-by Masami Hiramatsu <[email protected]>---
Changes in v4:
- Update for the latest kernel.
- Remove "probe-event.c" from title and body, because this also changesprobe-finder.ctoo :)Changes in v3:
- Remove unneededstrbuf_release(). (Thanks Namhyung!)Changes in v2:
- Makeperf_probe_event__sprintf()simpler.--- tools/perf/util/probe-event.c | 246 ++++++++++++++-------------------------- tools/perf/util/probe-event.h | 2 tools/perf/util/probe-finder.c | 14 +- 3 files changed, 93 insertions(+), 169 deletions(-)tools/perf/util/probe-event.c +85
-161@@ -1618,69 +1618,51 @@ out: }/* Compose only probe arg */ -int synthesize_perf_probe_arg (struct perf_probe_arg *pa,char *buf,size_t len) +char *synthesize_perf_probe_arg (struct perf_probe_arg *pa) {struct perf_probe_arg_field *field = pa->field; -int ret; -char *tmp = buf; +struct strbuf buf; +char *ret; +strbuf_init (&buf,64 );if (pa->name && pa->var) - ret =e_snprintf (tmp, len,"%s=%s" , pa->name, pa->var); +strbuf_addf (&buf,"%s=%s" , pa->name, pa->var);else - ret =e_snprintf (tmp, len,"%s" , pa->name ? pa->name : pa->var); -if (ret <=0 ) - goto error; - tmp += ret; - len -= ret; +strbuf_addstr (&buf, pa->name ?: pa->var);while (field) {if (field->name[0 ] =='[' ) - ret =e_snprintf (tmp, len,"%s" , field->name); +strbuf_addstr (&buf, field->name);else - ret =e_snprintf (tmp, len,"%s%s" , - field->ref ?"->" :"." , field->name); -if (ret <=0 ) - goto error; - tmp += ret; - len -= ret; +strbuf_addf (&buf,"%s%s" , field->ref ?"->" :"." , + field->name); field = field->next; } -if (pa->type) { - ret =e_snprintf (tmp, len,":%s" , pa->type); -if (ret <=0 ) - goto error; - tmp += ret; - len -= ret; - } +if (pa->type) +strbuf_addf (&buf,":%s" , pa->type); + + ret =strbuf_detach (&buf,NULL ); -return tmp - buf; -error: -pr_debug ("Failed to synthesize perf probe argument: %d\n" , ret);return ret; }/* Compose only probe point (not argument) */ static char *synthesize_perf_probe_point (struct perf_probe_point *pp) { -char *buf, *tmp; -char offs[32 ] ="" , line[32 ] ="" , file[32 ] ="" ; -int ret, len; - - buf =zalloc (MAX_CMDLEN ); -if (buf ==NULL ) { - ret = -ENOMEM ; - goto error; - } -if (pp->offset) { - ret =e_snprintf (offs,32 ,"+%lu" , pp->offset); -if (ret <=0 ) - goto error; - } -if (pp->line) { - ret =e_snprintf (line,32 ,":%d" , pp->line); -if (ret <=0 ) - goto error; +struct strbuf buf; +char *tmp; +int len; + +strbuf_init (&buf,64 ); +if (pp->function) { +strbuf_addstr (&buf, pp->function); +if (pp->offset) +strbuf_addf (&buf,"+%lu" , pp->offset); +else if (pp->line) +strbuf_addf (&buf,":%d" , pp->line); +else if (pp->retprobe) +strbuf_addstr (&buf,"%return" ); }if (pp->file) { tmp = pp->file;@@ -1689,25 +1671,12 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) tmp =strchr (pp->file + len -30 ,'/' ); tmp = tmp ? tmp +1 : pp->file + len -30 ; } - ret =e_snprintf (file,32 ,"@%s" , tmp); -if (ret <=0 ) - goto error; +strbuf_addf (&buf,"@%s" , tmp); +if (!pp->function && pp->line) +strbuf_addf (&buf,":%d" , pp->line); } -if (pp->function) - ret =e_snprintf (buf,MAX_CMDLEN ,"%s%s%s%s%s" , pp->function, - offs, pp->retprobe ?"%return" :"" , line, - file); -else - ret =e_snprintf (buf,MAX_CMDLEN ,"%s%s" , file, line); -if (ret <=0 ) - goto error; - -return buf; -error: -pr_debug ("Failed to synthesize perf probe point: %d\n" , ret); -free (buf); -return NULL ; +return strbuf_detach (&buf,NULL ); }#if 0 @@ -1736,45 +1705,30 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev)#endif static int __synthesize_probe_trace_arg_ref (struct probe_trace_arg_ref *ref, -char **buf,size_t *buflen, -int depth) +struct strbuf *buf,int depth) { -int ret;if (ref->next) { depth =__synthesize_probe_trace_arg_ref (ref->next, buf, - buflen, depth +1 ); + depth +1 );if (depth <0 ) goto out; } - - ret =e_snprintf (*buf, *buflen,"%+ld(" , ref->offset); -if (ret <0 ) - depth = ret; -else { - *buf += ret; - *buflen -= ret; - } +strbuf_addf (buf,"%+ld(" , ref->offset); out:return depth; - }static int synthesize_probe_trace_arg (struct probe_trace_arg *arg, -char *buf,size_t buflen) +struct strbuf *buf) {struct probe_trace_arg_ref *ref = arg->ref; -int ret, depth =0 ; -char *tmp = buf; +int depth =0 ;/* Argument name or separator */ if (arg->name) - ret =e_snprintf (buf, buflen," %s=" , arg->name); +strbuf_addf (buf," %s=" , arg->name);else - ret =e_snprintf (buf, buflen," " ); -if (ret <0 ) -return ret; - buf += ret; - buflen -= ret; +strbuf_addch (buf,' ' );/* Special case: @XXX */ if (arg->value[0 ] =='@' && arg->ref)@@ -1782,60 +1736,41 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,/* Dereferencing arguments */ if (ref) { - depth =__synthesize_probe_trace_arg_ref (ref, &buf, - &buflen,1 ); + depth =__synthesize_probe_trace_arg_ref (ref, buf,1 );if (depth <0 )return depth; }/* Print argument value */ if (arg->value[0 ] =='@' && arg->ref) - ret =e_snprintf (buf, buflen,"%s%+ld" , arg->value, - arg->ref->offset); +strbuf_addf (buf,"%s%+ld" , arg->value, arg->ref->offset);else - ret =e_snprintf (buf, buflen,"%s" , arg->value); -if (ret <0 ) -return ret; - buf += ret; - buflen -= ret; +strbuf_addstr (buf, arg->value);/* Closing */ -while (depth--) { - ret =e_snprintf (buf, buflen,")" ); -if (ret <0 ) -return ret; - buf += ret; - buflen -= ret; - } +while (depth--) +strbuf_addch (buf,')' );/* Print argument type */ -if (arg->type) { - ret =e_snprintf (buf, buflen,":%s" , arg->type); -if (ret <=0 ) -return ret; - buf += ret; - } +if (arg->type) +strbuf_addf (buf,":%s" , arg->type); -return buf - tmp; +return 0 ; }char *synthesize_probe_trace_command (struct probe_trace_event *tev) {struct probe_trace_point *tp = &tev->point; -char *buf; -int i, len, ret; - - buf =zalloc (MAX_CMDLEN ); -if (buf ==NULL ) -return NULL ; - - len =e_snprintf (buf,MAX_CMDLEN ,"%c:%s/%s " , tp->retprobe ?'r' :'p' , - tev->group, tev->event); -if (len <=0 ) - goto error; +struct strbuf buf; +char *ret =NULL ; +int i;/* Uprobes must have tp->module */ if (tev->uprobes && !tp->module) - goto error; +return NULL ; + +strbuf_init (&buf,32 ); +strbuf_addf (&buf,"%c:%s/%s " , tp->retprobe ?'r' :'p' , + tev->group, tev->event);/* * If tp->address == 0, then this point must be a * absolute address uprobe. @@ -1849,34 +1784,23 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)/* Use the tp->address for uprobes */ if (tev->uprobes) - ret =e_snprintf (buf + len,MAX_CMDLEN - len,"%s:0x%lx" , - tp->module, tp->address); +strbuf_addf (&buf,"%s:0x%lx" , tp->module, tp->address);else if (!strncmp (tp->symbol,"0x" ,2 ))/* Absolute address. See try_to_find_absolute_address() */ - ret =e_snprintf (buf + len,MAX_CMDLEN - len,"%s%s0x%lx" , - tp->module ?:"" , tp->module ?":" :"" , - tp->address); +strbuf_addf (&buf,"%s%s0x%lx" , tp->module ?:"" , + tp->module ?":" :"" , tp->address);else - ret =e_snprintf (buf + len,MAX_CMDLEN - len,"%s%s%s+%lu" , - tp->module ?:"" , tp->module ?":" :"" , - tp->symbol, tp->offset); - -if (ret <=0 ) - goto error; - len += ret; +strbuf_addf (&buf,"%s%s%s+%lu" , tp->module ?:"" , + tp->module ?":" :"" , tp->symbol, tp->offset); -for (i =0 ; i < tev->nargs; i++) { - ret =synthesize_probe_trace_arg (&tev->args[i], buf + len, -MAX_CMDLEN - len); -if (ret <=0 ) +for (i =0 ; i < tev->nargs; i++) +if (synthesize_probe_trace_arg (&tev->args[i], &buf) <0 ) goto error; - len += ret; - } -return buf; + ret =strbuf_detach (&buf,NULL ); error: -free (buf); -return NULL ; +strbuf_release (&buf); +return ret; } static int find_perf_probe_point_from_map(struct probe_trace_point *tp,@@ -1958,7 +1882,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp,static int convert_to_perf_probe_event (struct probe_trace_event *tev,struct perf_probe_event *pev,bool is_kprobe) { -char buf[64 ] ="" ; +struct strbuf buf =STRBUF_INIT ;int i, ret;/* Convert event/group name */ @@ -1981,9 +1905,9 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,if (tev->args[i].name) pev->args[i].name =strdup (tev->args[i].name);else { - ret =synthesize_probe_trace_arg (&tev->args[i], - buf,64 ); - pev->args[i].name =strdup (buf); +strbuf_init (&buf,32 ); + ret =synthesize_probe_trace_arg (&tev->args[i], &buf); + pev->args[i].name =strbuf_detach (&buf,NULL ); }if (pev->args[i].name ==NULL && ret >=0 ) ret = -ENOMEM ;@@ -2161,37 +2085,37 @@ static int perf_probe_event__sprintf(const char *group, const char *event,const char *module, struct strbuf *result) { - int i, ret; -char buf[128 ]; -char *place; + int i; +char *buf; -/* Synthesize only event probe point */ - place =synthesize_perf_probe_point (&pev->point); -if (!place) -return -EINVAL ; +if (asprintf (&buf,"%s:%s" , group, event) <0 ) +return -errno; +strbuf_addf (result," %-20s (on " , buf); +free (buf); - ret =e_snprintf (buf,128 ,"%s:%s" , group, event); -if (ret <0 ) - goto out; +/* Synthesize only event probe point */ + buf =synthesize_perf_probe_point (&pev->point); +if (!buf) +return -ENOMEM ; +strbuf_addstr (result, buf); +free (buf); -strbuf_addf (result," %-20s (on %s" , buf, place);if (module)strbuf_addf (result," in %s" , module);if (pev->nargs >0 ) {strbuf_add (result," with" ,5 );for (i =0 ; i < pev->nargs; i++) { - ret =synthesize_perf_probe_arg (&pev->args[i], - buf,128 ); -if (ret <0 ) - goto out; + buf =synthesize_perf_probe_arg (&pev->args[i]); +if (!buf) +return -ENOMEM ;strbuf_addf (result," %s" , buf); +free (buf); } }strbuf_addch (result,')' ); -out: -free (place); -return ret; + +return 0 ; }/* Show an event */ tools/perf/util/probe-event.h +1
-1@@ -120,7 +120,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev);/* Events to command string */ char *synthesize_perf_probe_command (struct perf_probe_event *pev);char *synthesize_probe_trace_command (struct probe_trace_event *tev); -int synthesize_perf_probe_arg (struct perf_probe_arg *pa,char *buf,size_t len); +char *synthesize_perf_probe_arg (struct perf_probe_arg *pa);/* Check the perf_probe_event needs debuginfo */ bool perf_probe_event_need_dwarf (struct perf_probe_event *pev);tools/perf/util/probe-finder.c +7
-7@@ -553,7 +553,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)static int find_variable (Dwarf_Die *sc_die,struct probe_finder *pf) {Dwarf_Die vr_die; -char buf[32 ], *ptr; +char *buf, *ptr;int ret =0 ;/* Copy raw parameters */ @@ -563,13 +563,13 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)if (pf->pvar->name) pf->tvar->name =strdup (pf->pvar->name);else { - ret =synthesize_perf_probe_arg (pf->pvar, buf,32 ); -if (ret <0 ) -return ret; + buf =synthesize_perf_probe_arg (pf->pvar); +if (!buf) +return -ENOMEM ; ptr =strchr (buf,':' );/* Change type separator to _ */ if (ptr) *ptr ='_' ; - pf->tvar->name =strdup (buf); + pf->tvar->name = buf; }if (pf->tvar->name ==NULL )return -ENOMEM ;@@ -1334,8 +1334,8 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)if (ret2 ==0 ) {strlist__add (vl->vars,strbuf_detach (&buf,NULL )); - } -strbuf_release (&buf); + }else +strbuf_release (&buf); } }
Signature · 1 line
Masami Hiramatsu <[email protected]>
Arnaldo Carvalho de Melo
maintainerRe: [PATCH perf/core v4 01/19] perf probe: Use strbuf for making strings
Em Tue, Apr 26, 2016 at 11:40:47PM +0900, Masami Hiramatsu escreveu:
Quoted 15 lines
Quoted 8 lines · On Tue, 26 Apr 2016 10:36:57 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Tue, Apr 26, 2016 at 06:02:11PM +0900, Masami Hiramatsu escreveu:
Quoted 4 lines
From: Masami Hiramatsu <[email protected]>
Replace many fixed-length char array with strbuf to stringify
perf_probe_eventandprobe_trace_eventetc.Sure you want to do that? From time to time I try to reduce the strbuf usage, not grow it :-\
Aah, I got what you want.
Quoted 1 line
Quoted 6 lines
Quoted 2 lines
That is one of the last users of
xrealloc(), via thatALLOC_GROW()thing.Hmm I'm not sure what you considering, memory usage? or code reducing? I also would like to remove
e_snprintf()use in perf probe by replacing with strbuf functions. I'd like to find better way.
What I don't like is that xrealloc ends up calling die() :-\ It should instead propagate back the error.
In lots of cases I managed to use what is in glibc, asprintf(), that will allocate space and format in one go.
But strbuf has this addf() one that indeed is handy. So I think I'll take this patch as it is not for the simpler cases where asprintf() can be used.
- Arnaldo
Quoted 467 lines
Thank you,
Quoted 461 lines
- Arnaldo
Quoted 458 lines
Signed-off-by Masami Hiramatsu <[email protected]>Signed-off-by Masami Hiramatsu <[email protected]>---
Changes in v4:
- Update for the latest kernel.
- Remove "probe-event.c" from title and body, because this also changesprobe-finder.ctoo :)Changes in v3:
- Remove unneededstrbuf_release(). (Thanks Namhyung!)Changes in v2:
- Makeperf_probe_event__sprintf()simpler.--- tools/perf/util/probe-event.c | 246 ++++++++++++++-------------------------- tools/perf/util/probe-event.h | 2 tools/perf/util/probe-finder.c | 14 +- 3 files changed, 93 insertions(+), 169 deletions(-)tools/perf/util/probe-event.c +85
-161@@ -1618,69 +1618,51 @@ out: }/* Compose only probe arg */ -int synthesize_perf_probe_arg (struct perf_probe_arg *pa,char *buf,size_t len) +char *synthesize_perf_probe_arg (struct perf_probe_arg *pa) {struct perf_probe_arg_field *field = pa->field; -int ret; -char *tmp = buf; +struct strbuf buf; +char *ret; +strbuf_init (&buf,64 );if (pa->name && pa->var) - ret =e_snprintf (tmp, len,"%s=%s" , pa->name, pa->var); +strbuf_addf (&buf,"%s=%s" , pa->name, pa->var);else - ret =e_snprintf (tmp, len,"%s" , pa->name ? pa->name : pa->var); -if (ret <=0 ) - goto error; - tmp += ret; - len -= ret; +strbuf_addstr (&buf, pa->name ?: pa->var);while (field) {if (field->name[0 ] =='[' ) - ret =e_snprintf (tmp, len,"%s" , field->name); +strbuf_addstr (&buf, field->name);else - ret =e_snprintf (tmp, len,"%s%s" , - field->ref ?"->" :"." , field->name); -if (ret <=0 ) - goto error; - tmp += ret; - len -= ret; +strbuf_addf (&buf,"%s%s" , field->ref ?"->" :"." , + field->name); field = field->next; } -if (pa->type) { - ret =e_snprintf (tmp, len,":%s" , pa->type); -if (ret <=0 ) - goto error; - tmp += ret; - len -= ret; - } +if (pa->type) +strbuf_addf (&buf,":%s" , pa->type); + + ret =strbuf_detach (&buf,NULL ); -return tmp - buf; -error: -pr_debug ("Failed to synthesize perf probe argument: %d\n" , ret);return ret; }/* Compose only probe point (not argument) */ static char *synthesize_perf_probe_point (struct perf_probe_point *pp) { -char *buf, *tmp; -char offs[32 ] ="" , line[32 ] ="" , file[32 ] ="" ; -int ret, len; - - buf =zalloc (MAX_CMDLEN ); -if (buf ==NULL ) { - ret = -ENOMEM ; - goto error; - } -if (pp->offset) { - ret =e_snprintf (offs,32 ,"+%lu" , pp->offset); -if (ret <=0 ) - goto error; - } -if (pp->line) { - ret =e_snprintf (line,32 ,":%d" , pp->line); -if (ret <=0 ) - goto error; +struct strbuf buf; +char *tmp; +int len; + +strbuf_init (&buf,64 ); +if (pp->function) { +strbuf_addstr (&buf, pp->function); +if (pp->offset) +strbuf_addf (&buf,"+%lu" , pp->offset); +else if (pp->line) +strbuf_addf (&buf,":%d" , pp->line); +else if (pp->retprobe) +strbuf_addstr (&buf,"%return" ); }if (pp->file) { tmp = pp->file;@@ -1689,25 +1671,12 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) tmp =strchr (pp->file + len -30 ,'/' ); tmp = tmp ? tmp +1 : pp->file + len -30 ; } - ret =e_snprintf (file,32 ,"@%s" , tmp); -if (ret <=0 ) - goto error; +strbuf_addf (&buf,"@%s" , tmp); +if (!pp->function && pp->line) +strbuf_addf (&buf,":%d" , pp->line); } -if (pp->function) - ret =e_snprintf (buf,MAX_CMDLEN ,"%s%s%s%s%s" , pp->function, - offs, pp->retprobe ?"%return" :"" , line, - file); -else - ret =e_snprintf (buf,MAX_CMDLEN ,"%s%s" , file, line); -if (ret <=0 ) - goto error; - -return buf; -error: -pr_debug ("Failed to synthesize perf probe point: %d\n" , ret); -free (buf); -return NULL ; +return strbuf_detach (&buf,NULL ); }#if 0 @@ -1736,45 +1705,30 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev)#endif static int __synthesize_probe_trace_arg_ref (struct probe_trace_arg_ref *ref, -char **buf,size_t *buflen, -int depth) +struct strbuf *buf,int depth) { -int ret;if (ref->next) { depth =__synthesize_probe_trace_arg_ref (ref->next, buf, - buflen, depth +1 ); + depth +1 );if (depth <0 ) goto out; } - - ret =e_snprintf (*buf, *buflen,"%+ld(" , ref->offset); -if (ret <0 ) - depth = ret; -else { - *buf += ret; - *buflen -= ret; - } +strbuf_addf (buf,"%+ld(" , ref->offset); out:return depth; - }static int synthesize_probe_trace_arg (struct probe_trace_arg *arg, -char *buf,size_t buflen) +struct strbuf *buf) {struct probe_trace_arg_ref *ref = arg->ref; -int ret, depth =0 ; -char *tmp = buf; +int depth =0 ;/* Argument name or separator */ if (arg->name) - ret =e_snprintf (buf, buflen," %s=" , arg->name); +strbuf_addf (buf," %s=" , arg->name);else - ret =e_snprintf (buf, buflen," " ); -if (ret <0 ) -return ret; - buf += ret; - buflen -= ret; +strbuf_addch (buf,' ' );/* Special case: @XXX */ if (arg->value[0 ] =='@' && arg->ref)@@ -1782,60 +1736,41 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,/* Dereferencing arguments */ if (ref) { - depth =__synthesize_probe_trace_arg_ref (ref, &buf, - &buflen,1 ); + depth =__synthesize_probe_trace_arg_ref (ref, buf,1 );if (depth <0 )return depth; }/* Print argument value */ if (arg->value[0 ] =='@' && arg->ref) - ret =e_snprintf (buf, buflen,"%s%+ld" , arg->value, - arg->ref->offset); +strbuf_addf (buf,"%s%+ld" , arg->value, arg->ref->offset);else - ret =e_snprintf (buf, buflen,"%s" , arg->value); -if (ret <0 ) -return ret; - buf += ret; - buflen -= ret; +strbuf_addstr (buf, arg->value);/* Closing */ -while (depth--) { - ret =e_snprintf (buf, buflen,")" ); -if (ret <0 ) -return ret; - buf += ret; - buflen -= ret; - } +while (depth--) +strbuf_addch (buf,')' );/* Print argument type */ -if (arg->type) { - ret =e_snprintf (buf, buflen,":%s" , arg->type); -if (ret <=0 ) -return ret; - buf += ret; - } +if (arg->type) +strbuf_addf (buf,":%s" , arg->type); -return buf - tmp; +return 0 ; }char *synthesize_probe_trace_command (struct probe_trace_event *tev) {struct probe_trace_point *tp = &tev->point; -char *buf; -int i, len, ret; - - buf =zalloc (MAX_CMDLEN ); -if (buf ==NULL ) -return NULL ; - - len =e_snprintf (buf,MAX_CMDLEN ,"%c:%s/%s " , tp->retprobe ?'r' :'p' , - tev->group, tev->event); -if (len <=0 ) - goto error; +struct strbuf buf; +char *ret =NULL ; +int i;/* Uprobes must have tp->module */ if (tev->uprobes && !tp->module) - goto error; +return NULL ; + +strbuf_init (&buf,32 ); +strbuf_addf (&buf,"%c:%s/%s " , tp->retprobe ?'r' :'p' , + tev->group, tev->event);/* * If tp->address == 0, then this point must be a * absolute address uprobe. @@ -1849,34 +1784,23 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)/* Use the tp->address for uprobes */ if (tev->uprobes) - ret =e_snprintf (buf + len,MAX_CMDLEN - len,"%s:0x%lx" , - tp->module, tp->address); +strbuf_addf (&buf,"%s:0x%lx" , tp->module, tp->address);else if (!strncmp (tp->symbol,"0x" ,2 ))/* Absolute address. See try_to_find_absolute_address() */ - ret =e_snprintf (buf + len,MAX_CMDLEN - len,"%s%s0x%lx" , - tp->module ?:"" , tp->module ?":" :"" , - tp->address); +strbuf_addf (&buf,"%s%s0x%lx" , tp->module ?:"" , + tp->module ?":" :"" , tp->address);else - ret =e_snprintf (buf + len,MAX_CMDLEN - len,"%s%s%s+%lu" , - tp->module ?:"" , tp->module ?":" :"" , - tp->symbol, tp->offset); - -if (ret <=0 ) - goto error; - len += ret; +strbuf_addf (&buf,"%s%s%s+%lu" , tp->module ?:"" , + tp->module ?":" :"" , tp->symbol, tp->offset); -for (i =0 ; i < tev->nargs; i++) { - ret =synthesize_probe_trace_arg (&tev->args[i], buf + len, -MAX_CMDLEN - len); -if (ret <=0 ) +for (i =0 ; i < tev->nargs; i++) +if (synthesize_probe_trace_arg (&tev->args[i], &buf) <0 ) goto error; - len += ret; - } -return buf; + ret =strbuf_detach (&buf,NULL ); error: -free (buf); -return NULL ; +strbuf_release (&buf); +return ret; } static int find_perf_probe_point_from_map(struct probe_trace_point *tp,@@ -1958,7 +1882,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp,static int convert_to_perf_probe_event (struct probe_trace_event *tev,struct perf_probe_event *pev,bool is_kprobe) { -char buf[64 ] ="" ; +struct strbuf buf =STRBUF_INIT ;int i, ret;/* Convert event/group name */ @@ -1981,9 +1905,9 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,if (tev->args[i].name) pev->args[i].name =strdup (tev->args[i].name);else { - ret =synthesize_probe_trace_arg (&tev->args[i], - buf,64 ); - pev->args[i].name =strdup (buf); +strbuf_init (&buf,32 ); + ret =synthesize_probe_trace_arg (&tev->args[i], &buf); + pev->args[i].name =strbuf_detach (&buf,NULL ); }if (pev->args[i].name ==NULL && ret >=0 ) ret = -ENOMEM ;@@ -2161,37 +2085,37 @@ static int perf_probe_event__sprintf(const char *group, const char *event,const char *module, struct strbuf *result) { - int i, ret; -char buf[128 ]; -char *place; + int i; +char *buf; -/* Synthesize only event probe point */ - place =synthesize_perf_probe_point (&pev->point); -if (!place) -return -EINVAL ; +if (asprintf (&buf,"%s:%s" , group, event) <0 ) +return -errno; +strbuf_addf (result," %-20s (on " , buf); +free (buf); - ret =e_snprintf (buf,128 ,"%s:%s" , group, event); -if (ret <0 ) - goto out; +/* Synthesize only event probe point */ + buf =synthesize_perf_probe_point (&pev->point); +if (!buf) +return -ENOMEM ; +strbuf_addstr (result, buf); +free (buf); -strbuf_addf (result," %-20s (on %s" , buf, place);if (module)strbuf_addf (result," in %s" , module);if (pev->nargs >0 ) {strbuf_add (result," with" ,5 );for (i =0 ; i < pev->nargs; i++) { - ret =synthesize_perf_probe_arg (&pev->args[i], - buf,128 ); -if (ret <0 ) - goto out; + buf =synthesize_perf_probe_arg (&pev->args[i]); +if (!buf) +return -ENOMEM ;strbuf_addf (result," %s" , buf); +free (buf); } }strbuf_addch (result,')' ); -out: -free (place); -return ret; + +return 0 ; }/* Show an event */ tools/perf/util/probe-event.h +1
-1@@ -120,7 +120,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev);/* Events to command string */ char *synthesize_perf_probe_command (struct perf_probe_event *pev);char *synthesize_probe_trace_command (struct probe_trace_event *tev); -int synthesize_perf_probe_arg (struct perf_probe_arg *pa,char *buf,size_t len); +char *synthesize_perf_probe_arg (struct perf_probe_arg *pa);/* Check the perf_probe_event needs debuginfo */ bool perf_probe_event_need_dwarf (struct perf_probe_event *pev);tools/perf/util/probe-finder.c +7
-7@@ -553,7 +553,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)static int find_variable (Dwarf_Die *sc_die,struct probe_finder *pf) {Dwarf_Die vr_die; -char buf[32 ], *ptr; +char *buf, *ptr;int ret =0 ;/* Copy raw parameters */ @@ -563,13 +563,13 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)if (pf->pvar->name) pf->tvar->name =strdup (pf->pvar->name);else { - ret =synthesize_perf_probe_arg (pf->pvar, buf,32 ); -if (ret <0 ) -return ret; + buf =synthesize_perf_probe_arg (pf->pvar); +if (!buf) +return -ENOMEM ; ptr =strchr (buf,':' );/* Change type separator to _ */ if (ptr) *ptr ='_' ; - pf->tvar->name =strdup (buf); + pf->tvar->name = buf; }if (pf->tvar->name ==NULL )return -ENOMEM ;@@ -1334,8 +1334,8 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)if (ret2 ==0 ) {strlist__add (vl->vars,strbuf_detach (&buf,NULL )); - } -strbuf_release (&buf); + }else +strbuf_release (&buf); } }Signature · 1 line
Masami Hiramatsu <[email protected]>
Re: [PATCH perf/core v4 01/19] perf probe: Use strbuf for making strings
Quoted 26 lines · On Tue, 26 Apr 2016 11:59:34 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Tue, Apr 26, 2016 at 11:40:47PM +0900, Masami Hiramatsu escreveu:
Quoted 15 lines
Quoted 8 lines · On Tue, 26 Apr 2016 10:36:57 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Tue, Apr 26, 2016 at 06:02:11PM +0900, Masami Hiramatsu escreveu:
Quoted 4 lines
From: Masami Hiramatsu <[email protected]>
Replace many fixed-length char array with strbuf to stringify
perf_probe_eventandprobe_trace_eventetc.Sure you want to do that? From time to time I try to reduce the strbuf usage, not grow it :-\
Aah, I got what you want.
Quoted 1 line
Quoted 6 lines
Quoted 2 lines
That is one of the last users of
xrealloc(), via thatALLOC_GROW()thing.Hmm I'm not sure what you considering, memory usage? or code reducing? I also would like to remove
e_snprintf()use in perf probe by replacing with strbuf functions. I'd like to find better way.What I don't like is that xrealloc ends up calling
die():-\ It should instead propagate back the error.
Quoted 6 lines
In lots of cases I managed to use what is in glibc,
asprintf(), that will allocate space and format in one go.But strbuf has this
addf()one that indeed is handy. So I think I'll take this patch as it is not for the simpler cases whereasprintf()can be used.
OK, I'll try to remove die() and xrealloc() from the strbuf, since it seems most of users of strbuf() is perf-probe.
Thanks,
Signature · 1 line
Masami Hiramatsu <[email protected]>
PATCH v4 2/19 perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
In reply to Masami HiramatsuFrom: Masami Hiramatsu <[email protected]>
Use path/to/bin/buildid/elf instead of path/to/bin/buildid to store corresponding elf binary.
This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms. Note that the build-id based symlink changes to point to the path/to/bin/buildid, not path/to/bin/buildid/elf.
--- tools/perf/util/build-id.c | 65 +++++++++++++++++++++++++++++++------------- tools/perf/util/dso.h | 5 +++ tools/perf/util/symbol.c | 2 + 3 files changed, 52 insertions(+), 20 deletions(-)
tools/perf/util/build-id.c +46 -19
@@ -144,7 +144,8 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...)return ret; } -static char *build_id__filename (const char *sbuild_id,char *bf,size_t size) +static char *build_id_cache__linkname (const char *sbuild_id,char *bf, +size_t size) {char *tmp = bf; int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
@@ -154,15 +155,35 @@ static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)return bf; } +static const char *build_id_cache__basename (bool is_kallsyms,bool is_vdso) +{ +return is_kallsyms ?"kallsyms" : (is_vdso ?"vdso" :"elf" ); +} +char *dso__build_id_filename (const struct dso *dso,char *bf,size_t size) { -char build_id_hex[SBUILD_ID_SIZE ]; +bool is_kallsyms =dso__is_kallsyms ((struct dso *)dso); +bool is_vdso =dso__is_vdso ((struct dso *)dso); +char sbuild_id[SBUILD_ID_SIZE ]; +char *linkname; +bool alloc = (bf ==NULL ); +int ret;if (!dso->has_build_id)return NULL ; -build_id__sprintf (dso->build_id,sizeof (dso->build_id), build_id_hex); -return build_id__filename (build_id_hex, bf, size); +build_id__sprintf (dso->build_id,sizeof (dso->build_id), sbuild_id); + linkname =build_id_cache__linkname (sbuild_id,NULL ,0 ); +if (!linkname) +return NULL ; + + ret =asnprintf (&bf, size,"%s/%s" , linkname, +build_id_cache__basename (is_kallsyms, is_vdso)); +if (ret <0 || (!alloc && size < (unsigned int )ret)) + bf =NULL ; +free (linkname); + +return bf; }bool dso__build_id_is_kmod (const struct dso *dso,char *bf,size_t size)
@@ -341,7 +362,8 @@ void disable_buildid_cache(void) }static char *build_id_cache__dirname_from_path (const char *name, -bool is_kallsyms,bool is_vdso) +bool is_kallsyms,bool is_vdso, +const char *sbuild_id) {char *realname = (char *)name, *filename;bool slash = is_kallsyms || is_vdso;
@@ -352,8 +374,9 @@ static char *build_id_cache__dirname_from_path(const char *name,return NULL ; } -if (asprintf (&filename,"%s%s%s" , buildid_dir, slash ?"/" :"" , - is_vdso ?DSO__NAME_VDSO : realname) <0 ) +if (asprintf (&filename,"%s%s%s%s%s" , buildid_dir, slash ?"/" :"" , + is_vdso ?DSO__NAME_VDSO : realname, + sbuild_id ?"/" :"" , sbuild_id ?:"" ) <0 ) filename =NULL ;if (!slash)
@@ -372,7 +395,8 @@ int build_id_cache__list_build_ids(const char *pathname,int ret =0 ; list =strlist__new (NULL ,NULL ); - dir_name =build_id_cache__dirname_from_path (pathname, false, false); + dir_name =build_id_cache__dirname_from_path (pathname, false, false, +NULL );if (!list || !dir_name) { ret = -ENOMEM ; goto out;
@@ -407,7 +431,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, {const size_t size =PATH_MAX ;char *realname =NULL , *filename =NULL , *dir_name =NULL , - *linkname =zalloc (size), *targetname, *tmp; + *linkname =zalloc (size), *tmp;int err =-1 ;if (!is_kallsyms) {
@@ -416,14 +440,17 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; } - dir_name =build_id_cache__dirname_from_path (name, is_kallsyms, is_vdso); + dir_name =build_id_cache__dirname_from_path (name, is_kallsyms, + is_vdso, sbuild_id);if (!dir_name) goto out_free;if (mkdir_p (dir_name,0755 )) goto out_free; -if (asprintf (&filename,"%s/%s" , dir_name, sbuild_id) <0 ) { +/* Save the allocated buildid dirname */ +if (asprintf (&filename,"%s/%s" , dir_name, +build_id_cache__basename (is_kallsyms, is_vdso)) <0 ) { filename =NULL ; goto out_free; }
@@ -437,7 +464,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; } -if (!build_id__filename (sbuild_id, linkname, size)) +if (!build_id_cache__linkname (sbuild_id, linkname, size)) goto out_free; tmp =strrchr (linkname,'/' ); *tmp ='\0' ;
@@ -446,10 +473,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; *tmp ='/' ; - targetname = filename +strlen (buildid_dir) -5 ; -memcpy (targetname,"../.." ,5 ); + tmp = dir_name +strlen (buildid_dir) -5 ; +memcpy (tmp,"../.." ,5 ); -if (symlink (targetname, linkname) ==0 ) +if (symlink (tmp, linkname) ==0 ) err =0 ; out_free:if (!is_kallsyms)
@@ -474,7 +501,7 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,bool build_id_cache__cached (const char *sbuild_id) {bool ret = false; -char *filename =build_id__filename (sbuild_id,NULL ,0 ); +char *filename =build_id_cache__linkname (sbuild_id,NULL ,0 );if (filename && !access (filename,F_OK )) ret = true;
@@ -493,7 +520,7 @@ int build_id_cache__remove_s(const char *sbuild_id)if (filename ==NULL || linkname ==NULL ) goto out_free; -if (!build_id__filename (sbuild_id, linkname, size)) +if (!build_id_cache__linkname (sbuild_id, linkname, size)) goto out_free;if (access (linkname,F_OK ))
@@ -511,7 +538,7 @@ int build_id_cache__remove_s(const char *sbuild_id) tmp =strrchr (linkname,'/' ) +1 ;snprintf (tmp, size - (tmp - linkname),"%s" , filename); -if (unlink (linkname)) +if (rm_rf (linkname)) goto out_free; err =0 ;
@@ -523,7 +550,7 @@ out_free:static int dso__cache_build_id (struct dso *dso,struct machine *machine) { -bool is_kallsyms = dso->kernel && dso->long_name[0 ] !='/' ; +bool is_kallsyms =dso__is_kallsyms (dso);bool is_vdso =dso__is_vdso (dso);const char *name = dso->long_name;char nm[PATH_MAX ];
tools/perf/util/dso.h +5 -0
@@ -349,6 +349,11 @@ static inline bool dso__is_kcore(struct dso *dso) dso->binary_type ==DSO_BINARY_TYPE__GUEST_KCORE ; } +static inline bool dso__is_kallsyms (struct dso *dso) +{ +return dso->kernel && dso->long_name[0 ] !='/' ; +} +void dso__free_a2l (struct dso *dso);enum dso_type dso__type (struct dso *dso,struct machine *machine);
tools/perf/util/symbol.c +1 -1
@@ -1685,7 +1685,7 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)if (!find_matching_kcore (map, path,sizeof (path)))return strdup (path); -scnprintf (path,sizeof (path),"%s/[kernel.kallsyms]/%s" , +scnprintf (path,sizeof (path),"%s/[kernel.kallsyms]/%s/kallsyms" , buildid_dir, sbuild_id);if (access (path,F_OK )) {
Arnaldo Carvalho de Melo
maintainerRe: [PATCH perf/core v4 02/19] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
Em Tue, Apr 26, 2016 at 06:02:22PM +0900, Masami Hiramatsu escreveu:
Quoted 7 lines
From: Masami Hiramatsu <[email protected]>
Use path/to/bin/buildid/elf instead of path/to/bin/buildid to store corresponding elf binary.
This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms. Note that the build-id based symlink changes to point to the path/to/bin/buildid, not path/to/bin/buildid/elf.
Ok, but what happens to existing caches? Not a problem? I.e. the lookups are made from ~/.debug/.build-id/, so it will just follow that symlink and if the file was inserted in the cache before this change, it will find it there, ok.
If inserted later, ditto.
Now what do you mean by "Note that the build-id based symlink changes to point to the path/to/bin/buildid, not path/to/bin/buildid/elf."?
Probably the 'perf buildid-cache --purge" will just follow the symlink, so it'll work.
- Arnaldo
Quoted 210 lines
Signed-off-by Masami Hiramatsu <[email protected]>Signed-off-by Masami Hiramatsu <[email protected]>--- tools/perf/util/build-id.c | 65 +++++++++++++++++++++++++++++++------------- tools/perf/util/dso.h | 5 +++ tools/perf/util/symbol.c | 2 + 3 files changed, 52 insertions(+), 20 deletions(-)tools/perf/util/build-id.c +46
-19@@ -144,7 +144,8 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...)return ret; } -static char *build_id__filename (const char *sbuild_id,char *bf,size_t size) +static char *build_id_cache__linkname (const char *sbuild_id,char *bf, +size_t size) {char *tmp = bf; int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,@@ -154,15 +155,35 @@ static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)return bf; } +static const char *build_id_cache__basename (bool is_kallsyms,bool is_vdso) +{ +return is_kallsyms ?"kallsyms" : (is_vdso ?"vdso" :"elf" ); +} +char *dso__build_id_filename (const struct dso *dso,char *bf,size_t size) { -char build_id_hex[SBUILD_ID_SIZE ]; +bool is_kallsyms =dso__is_kallsyms ((struct dso *)dso); +bool is_vdso =dso__is_vdso ((struct dso *)dso); +char sbuild_id[SBUILD_ID_SIZE ]; +char *linkname; +bool alloc = (bf ==NULL ); +int ret;if (!dso->has_build_id)return NULL ; -build_id__sprintf (dso->build_id,sizeof (dso->build_id), build_id_hex); -return build_id__filename (build_id_hex, bf, size); +build_id__sprintf (dso->build_id,sizeof (dso->build_id), sbuild_id); + linkname =build_id_cache__linkname (sbuild_id,NULL ,0 ); +if (!linkname) +return NULL ; + + ret =asnprintf (&bf, size,"%s/%s" , linkname, +build_id_cache__basename (is_kallsyms, is_vdso)); +if (ret <0 || (!alloc && size < (unsigned int )ret)) + bf =NULL ; +free (linkname); + +return bf; }bool dso__build_id_is_kmod (const struct dso *dso,char *bf,size_t size)@@ -341,7 +362,8 @@ void disable_buildid_cache(void) }static char *build_id_cache__dirname_from_path (const char *name, -bool is_kallsyms,bool is_vdso) +bool is_kallsyms,bool is_vdso, +const char *sbuild_id) {char *realname = (char *)name, *filename;bool slash = is_kallsyms || is_vdso;@@ -352,8 +374,9 @@ static char *build_id_cache__dirname_from_path(const char *name,return NULL ; } -if (asprintf (&filename,"%s%s%s" , buildid_dir, slash ?"/" :"" , - is_vdso ?DSO__NAME_VDSO : realname) <0 ) +if (asprintf (&filename,"%s%s%s%s%s" , buildid_dir, slash ?"/" :"" , + is_vdso ?DSO__NAME_VDSO : realname, + sbuild_id ?"/" :"" , sbuild_id ?:"" ) <0 ) filename =NULL ;if (!slash)@@ -372,7 +395,8 @@ int build_id_cache__list_build_ids(const char *pathname,int ret =0 ; list =strlist__new (NULL ,NULL ); - dir_name =build_id_cache__dirname_from_path (pathname, false, false); + dir_name =build_id_cache__dirname_from_path (pathname, false, false, +NULL );if (!list || !dir_name) { ret = -ENOMEM ; goto out;@@ -407,7 +431,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, {const size_t size =PATH_MAX ;char *realname =NULL , *filename =NULL , *dir_name =NULL , - *linkname =zalloc (size), *targetname, *tmp; + *linkname =zalloc (size), *tmp;int err =-1 ;if (!is_kallsyms) {@@ -416,14 +440,17 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; } - dir_name =build_id_cache__dirname_from_path (name, is_kallsyms, is_vdso); + dir_name =build_id_cache__dirname_from_path (name, is_kallsyms, + is_vdso, sbuild_id);if (!dir_name) goto out_free;if (mkdir_p (dir_name,0755 )) goto out_free; -if (asprintf (&filename,"%s/%s" , dir_name, sbuild_id) <0 ) { +/* Save the allocated buildid dirname */ +if (asprintf (&filename,"%s/%s" , dir_name, +build_id_cache__basename (is_kallsyms, is_vdso)) <0 ) { filename =NULL ; goto out_free; }@@ -437,7 +464,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; } -if (!build_id__filename (sbuild_id, linkname, size)) +if (!build_id_cache__linkname (sbuild_id, linkname, size)) goto out_free; tmp =strrchr (linkname,'/' ); *tmp ='\0' ;@@ -446,10 +473,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; *tmp ='/' ; - targetname = filename +strlen (buildid_dir) -5 ; -memcpy (targetname,"../.." ,5 ); + tmp = dir_name +strlen (buildid_dir) -5 ; +memcpy (tmp,"../.." ,5 ); -if (symlink (targetname, linkname) ==0 ) +if (symlink (tmp, linkname) ==0 ) err =0 ; out_free:if (!is_kallsyms)@@ -474,7 +501,7 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,bool build_id_cache__cached (const char *sbuild_id) {bool ret = false; -char *filename =build_id__filename (sbuild_id,NULL ,0 ); +char *filename =build_id_cache__linkname (sbuild_id,NULL ,0 );if (filename && !access (filename,F_OK )) ret = true;@@ -493,7 +520,7 @@ int build_id_cache__remove_s(const char *sbuild_id)if (filename ==NULL || linkname ==NULL ) goto out_free; -if (!build_id__filename (sbuild_id, linkname, size)) +if (!build_id_cache__linkname (sbuild_id, linkname, size)) goto out_free;if (access (linkname,F_OK ))@@ -511,7 +538,7 @@ int build_id_cache__remove_s(const char *sbuild_id) tmp =strrchr (linkname,'/' ) +1 ;snprintf (tmp, size - (tmp - linkname),"%s" , filename); -if (unlink (linkname)) +if (rm_rf (linkname)) goto out_free; err =0 ;@@ -523,7 +550,7 @@ out_free:static int dso__cache_build_id (struct dso *dso,struct machine *machine) { -bool is_kallsyms = dso->kernel && dso->long_name[0 ] !='/' ; +bool is_kallsyms =dso__is_kallsyms (dso);bool is_vdso =dso__is_vdso (dso);const char *name = dso->long_name;char nm[PATH_MAX ];tools/perf/util/dso.h +5
-0@@ -349,6 +349,11 @@ static inline bool dso__is_kcore(struct dso *dso) dso->binary_type ==DSO_BINARY_TYPE__GUEST_KCORE ; } +static inline bool dso__is_kallsyms (struct dso *dso) +{ +return dso->kernel && dso->long_name[0 ] !='/' ; +} +void dso__free_a2l (struct dso *dso);enum dso_type dso__type (struct dso *dso,struct machine *machine);tools/perf/util/symbol.c +1
-1@@ -1685,7 +1685,7 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)if (!find_matching_kcore (map, path,sizeof (path)))return strdup (path); -scnprintf (path,sizeof (path),"%s/[kernel.kallsyms]/%s" , +scnprintf (path,sizeof (path),"%s/[kernel.kallsyms]/%s/kallsyms" , buildid_dir, sbuild_id);if (access (path,F_OK )) {
Re: [PATCH perf/core v4 02/19] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
Quoted 9 lines · On Tue, 26 Apr 2016 10:45:38 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Tue, Apr 26, 2016 at 06:02:22PM +0900, Masami Hiramatsu escreveu:
Quoted 7 lines
From: Masami Hiramatsu <[email protected]>
Use path/to/bin/buildid/elf instead of path/to/bin/buildid to store corresponding elf binary.
This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms. Note that the build-id based symlink changes to point to the path/to/bin/buildid, not path/to/bin/buildid/elf.
Quoted 4 lines
Ok, but what happens to existing caches? Not a problem? I.e. the lookups are made from ~/.debug/.build-id/, so it will just follow that symlink and if the file was inserted in the cache before this change, it will find it there, ok.
Right, that the next patch does. And I agree with you that it should be merged to this patch.
Quoted 5 lines
If inserted later, ditto.
Now what do you mean by "Note that the build-id based symlink changes to point to the path/to/bin/buildid, not path/to/bin/buildid/elf."?
Ah, this is just a note that someone directly accessing the cache. But anyway, it is just a design note.
Thank you,
Quoted 217 lines
Probably the 'perf buildid-cache --purge" will just follow the symlink, so it'll work.
- Arnaldo
Quoted 210 lines
Signed-off-by Masami Hiramatsu <[email protected]>Signed-off-by Masami Hiramatsu <[email protected]>--- tools/perf/util/build-id.c | 65 +++++++++++++++++++++++++++++++------------- tools/perf/util/dso.h | 5 +++ tools/perf/util/symbol.c | 2 + 3 files changed, 52 insertions(+), 20 deletions(-)tools/perf/util/build-id.c +46
-19@@ -144,7 +144,8 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...)return ret; } -static char *build_id__filename (const char *sbuild_id,char *bf,size_t size) +static char *build_id_cache__linkname (const char *sbuild_id,char *bf, +size_t size) {char *tmp = bf; int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,@@ -154,15 +155,35 @@ static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)return bf; } +static const char *build_id_cache__basename (bool is_kallsyms,bool is_vdso) +{ +return is_kallsyms ?"kallsyms" : (is_vdso ?"vdso" :"elf" ); +} +char *dso__build_id_filename (const struct dso *dso,char *bf,size_t size) { -char build_id_hex[SBUILD_ID_SIZE ]; +bool is_kallsyms =dso__is_kallsyms ((struct dso *)dso); +bool is_vdso =dso__is_vdso ((struct dso *)dso); +char sbuild_id[SBUILD_ID_SIZE ]; +char *linkname; +bool alloc = (bf ==NULL ); +int ret;if (!dso->has_build_id)return NULL ; -build_id__sprintf (dso->build_id,sizeof (dso->build_id), build_id_hex); -return build_id__filename (build_id_hex, bf, size); +build_id__sprintf (dso->build_id,sizeof (dso->build_id), sbuild_id); + linkname =build_id_cache__linkname (sbuild_id,NULL ,0 ); +if (!linkname) +return NULL ; + + ret =asnprintf (&bf, size,"%s/%s" , linkname, +build_id_cache__basename (is_kallsyms, is_vdso)); +if (ret <0 || (!alloc && size < (unsigned int )ret)) + bf =NULL ; +free (linkname); + +return bf; }bool dso__build_id_is_kmod (const struct dso *dso,char *bf,size_t size)@@ -341,7 +362,8 @@ void disable_buildid_cache(void) }static char *build_id_cache__dirname_from_path (const char *name, -bool is_kallsyms,bool is_vdso) +bool is_kallsyms,bool is_vdso, +const char *sbuild_id) {char *realname = (char *)name, *filename;bool slash = is_kallsyms || is_vdso;@@ -352,8 +374,9 @@ static char *build_id_cache__dirname_from_path(const char *name,return NULL ; } -if (asprintf (&filename,"%s%s%s" , buildid_dir, slash ?"/" :"" , - is_vdso ?DSO__NAME_VDSO : realname) <0 ) +if (asprintf (&filename,"%s%s%s%s%s" , buildid_dir, slash ?"/" :"" , + is_vdso ?DSO__NAME_VDSO : realname, + sbuild_id ?"/" :"" , sbuild_id ?:"" ) <0 ) filename =NULL ;if (!slash)@@ -372,7 +395,8 @@ int build_id_cache__list_build_ids(const char *pathname,int ret =0 ; list =strlist__new (NULL ,NULL ); - dir_name =build_id_cache__dirname_from_path (pathname, false, false); + dir_name =build_id_cache__dirname_from_path (pathname, false, false, +NULL );if (!list || !dir_name) { ret = -ENOMEM ; goto out;@@ -407,7 +431,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, {const size_t size =PATH_MAX ;char *realname =NULL , *filename =NULL , *dir_name =NULL , - *linkname =zalloc (size), *targetname, *tmp; + *linkname =zalloc (size), *tmp;int err =-1 ;if (!is_kallsyms) {@@ -416,14 +440,17 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; } - dir_name =build_id_cache__dirname_from_path (name, is_kallsyms, is_vdso); + dir_name =build_id_cache__dirname_from_path (name, is_kallsyms, + is_vdso, sbuild_id);if (!dir_name) goto out_free;if (mkdir_p (dir_name,0755 )) goto out_free; -if (asprintf (&filename,"%s/%s" , dir_name, sbuild_id) <0 ) { +/* Save the allocated buildid dirname */ +if (asprintf (&filename,"%s/%s" , dir_name, +build_id_cache__basename (is_kallsyms, is_vdso)) <0 ) { filename =NULL ; goto out_free; }@@ -437,7 +464,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; } -if (!build_id__filename (sbuild_id, linkname, size)) +if (!build_id_cache__linkname (sbuild_id, linkname, size)) goto out_free; tmp =strrchr (linkname,'/' ); *tmp ='\0' ;@@ -446,10 +473,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; *tmp ='/' ; - targetname = filename +strlen (buildid_dir) -5 ; -memcpy (targetname,"../.." ,5 ); + tmp = dir_name +strlen (buildid_dir) -5 ; +memcpy (tmp,"../.." ,5 ); -if (symlink (targetname, linkname) ==0 ) +if (symlink (tmp, linkname) ==0 ) err =0 ; out_free:if (!is_kallsyms)@@ -474,7 +501,7 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,bool build_id_cache__cached (const char *sbuild_id) {bool ret = false; -char *filename =build_id__filename (sbuild_id,NULL ,0 ); +char *filename =build_id_cache__linkname (sbuild_id,NULL ,0 );if (filename && !access (filename,F_OK )) ret = true;@@ -493,7 +520,7 @@ int build_id_cache__remove_s(const char *sbuild_id)if (filename ==NULL || linkname ==NULL ) goto out_free; -if (!build_id__filename (sbuild_id, linkname, size)) +if (!build_id_cache__linkname (sbuild_id, linkname, size)) goto out_free;if (access (linkname,F_OK ))@@ -511,7 +538,7 @@ int build_id_cache__remove_s(const char *sbuild_id) tmp =strrchr (linkname,'/' ) +1 ;snprintf (tmp, size - (tmp - linkname),"%s" , filename); -if (unlink (linkname)) +if (rm_rf (linkname)) goto out_free; err =0 ;@@ -523,7 +550,7 @@ out_free:static int dso__cache_build_id (struct dso *dso,struct machine *machine) { -bool is_kallsyms = dso->kernel && dso->long_name[0 ] !='/' ; +bool is_kallsyms =dso__is_kallsyms (dso);bool is_vdso =dso__is_vdso (dso);const char *name = dso->long_name;char nm[PATH_MAX ];tools/perf/util/dso.h +5
-0@@ -349,6 +349,11 @@ static inline bool dso__is_kcore(struct dso *dso) dso->binary_type ==DSO_BINARY_TYPE__GUEST_KCORE ; } +static inline bool dso__is_kallsyms (struct dso *dso) +{ +return dso->kernel && dso->long_name[0 ] !='/' ; +} +void dso__free_a2l (struct dso *dso);enum dso_type dso__type (struct dso *dso,struct machine *machine);tools/perf/util/symbol.c +1
-1@@ -1685,7 +1685,7 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)if (!find_matching_kcore (map, path,sizeof (path)))return strdup (path); -scnprintf (path,sizeof (path),"%s/[kernel.kallsyms]/%s" , +scnprintf (path,sizeof (path),"%s/[kernel.kallsyms]/%s/kallsyms" , buildid_dir, sbuild_id);if (access (path,F_OK )) {
Signature · 1 line
Masami Hiramatsu <[email protected]>
PATCH v4 3/19 perf buildid-cache: Fall back to the old style build-id cache
In reply to Masami HiramatsuFall back to the old style build-id cache (~/.debug/<path-to-bin>/<build-id>) if possible. Because there is old build-id cache under ~/.debug, perf has to check if the old entry is there instead of returning an error. Or, user have to remove ~/.debug completely.
This patch introduces fallback code to try using old-style buildid caches. To update the cached entry, you just need to add a cache. It automatically removes old cache entry and make a new one in new style (~/.debug/<path-to-bin>/<build-id>/[elf|vdso|kallsyms]).
IOW, without this patch, "perf buildid-cache --add" always gets errors when adding existing binaries.
----
# perf buildid-cache -a /usr/lib64/libc-2.20.so,/usr/bin/gcc Couldn't add /usr/bin/gcc: Not a directory Couldn't add /usr/lib64/libc-2.20.so: Not a directory ---- Moreover, --update option removes only symlink, thus the build-id cache is corrupted.
This fixes above issues.
--- tools/perf/util/build-id.c | 17 ++++++++++++++++- tools/perf/util/symbol.c | 13 +++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-)
tools/perf/util/build-id.c +16 -1
@@ -155,6 +155,12 @@ static char *build_id_cache__linkname(const char *sbuild_id, char *bf,return bf; } +static bool __is_regular_file (const char *pathname) +{ +struct stat sb; +return stat (pathname, &sb) ==0 &&S_ISREG (sb.st_mode); +} +static const char *build_id_cache__basename (bool is_kallsyms,bool is_vdso) {return is_kallsyms ?"kallsyms" : (is_vdso ?"vdso" :"elf" );
@@ -177,7 +183,11 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)if (!linkname)return NULL ; - ret =asnprintf (&bf, size,"%s/%s" , linkname, +/* Check if old style build_id cache */ +if (__is_regular_file (linkname)) + ret =asnprintf (&bf, size,"%s" , linkname); +else + ret =asnprintf (&bf, size,"%s/%s" , linkname,build_id_cache__basename (is_kallsyms, is_vdso));if (ret <0 || (!alloc && size < (unsigned int )ret)) bf =NULL ;
@@ -445,6 +455,11 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,if (!dir_name) goto out_free; +/* Remove old style build-id cache */ +if (__is_regular_file (dir_name)) +if (unlink (dir_name)) + goto out_free; +if (mkdir_p (dir_name,0755 )) goto out_free;
tools/perf/util/symbol.c +9 -4
@@ -1687,11 +1687,16 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)scnprintf (path,sizeof (path),"%s/[kernel.kallsyms]/%s/kallsyms" , buildid_dir, sbuild_id); - +/* Try old style kallsyms cache */ if (access (path,F_OK )) { -pr_err ("No kallsyms or vmlinux with build-id %s was found\n" , - sbuild_id); -return NULL ; +scnprintf (path,sizeof (path),"%s/[kernel.kallsyms]/%s" , + buildid_dir, sbuild_id); + +if (access (path,F_OK )) { +pr_err ("No kallsyms or vmlinux with build-id %s was found\n" , + sbuild_id); +return NULL ; + } }return strdup (path);
Arnaldo Carvalho de Melo
maintainerRe: [PATCH perf/core v4 03/19] perf buildid-cache: Fall back to the old style build-id cache
Em Tue, Apr 26, 2016 at 06:02:33PM +0900, Masami Hiramatsu escreveu:
Quoted 5 lines
Fall back to the old style build-id cache (~/.debug/<path-to-bin>/<build-id>) if possible. Because there is old build-id cache under ~/.debug, perf has to check if the old entry is there instead of returning an error. Or, user have to remove ~/.debug completely.
So, from the description this seems to address the issues I mentioned in the previous patch.
Probably it is a good idea not to introduce the problem in the first place? I.e. combine this and the previous patch, so that we don't have this bisection break?
- Arnaldo
Quoted 91 lines
This patch introduces fallback code to try using old-style buildid caches. To update the cached entry, you just need to add a cache. It automatically removes old cache entry and make a new one in new style (~/.debug/<path-to-bin>/<build-id>/[elf|vdso|kallsyms]).
IOW, without this patch, "perf buildid-cache --add" always gets errors when adding existing binaries.
----# perf buildid-cache -a /usr/lib64/libc-2.20.so,/usr/bin/gcc Couldn't add /usr/bin/gcc: Not a directory Couldn't add /usr/lib64/libc-2.20.so: Not a directory ---- Moreover, --update option removes only symlink, thus the build-id cache is corrupted.This fixes above issues.
Signed-off-by Masami Hiramatsu <[email protected]>--- tools/perf/util/build-id.c | 17 ++++++++++++++++- tools/perf/util/symbol.c | 13 +++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-)tools/perf/util/build-id.c +16
-1@@ -155,6 +155,12 @@ static char *build_id_cache__linkname(const char *sbuild_id, char *bf,return bf; } +static bool __is_regular_file (const char *pathname) +{ +struct stat sb; +return stat (pathname, &sb) ==0 &&S_ISREG (sb.st_mode); +} +static const char *build_id_cache__basename (bool is_kallsyms,bool is_vdso) {return is_kallsyms ?"kallsyms" : (is_vdso ?"vdso" :"elf" );@@ -177,7 +183,11 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)if (!linkname)return NULL ; - ret =asnprintf (&bf, size,"%s/%s" , linkname, +/* Check if old style build_id cache */ +if (__is_regular_file (linkname)) + ret =asnprintf (&bf, size,"%s" , linkname); +else + ret =asnprintf (&bf, size,"%s/%s" , linkname,build_id_cache__basename (is_kallsyms, is_vdso));if (ret <0 || (!alloc && size < (unsigned int )ret)) bf =NULL ;@@ -445,6 +455,11 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,if (!dir_name) goto out_free; +/* Remove old style build-id cache */ +if (__is_regular_file (dir_name)) +if (unlink (dir_name)) + goto out_free; +if (mkdir_p (dir_name,0755 )) goto out_free;tools/perf/util/symbol.c +9
-4@@ -1687,11 +1687,16 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)scnprintf (path,sizeof (path),"%s/[kernel.kallsyms]/%s/kallsyms" , buildid_dir, sbuild_id); - +/* Try old style kallsyms cache */ if (access (path,F_OK )) { -pr_err ("No kallsyms or vmlinux with build-id %s was found\n" , - sbuild_id); -return NULL ; +scnprintf (path,sizeof (path),"%s/[kernel.kallsyms]/%s" , + buildid_dir, sbuild_id); + +if (access (path,F_OK )) { +pr_err ("No kallsyms or vmlinux with build-id %s was found\n" , + sbuild_id); +return NULL ; + } }return strdup (path);
Re: [PATCH perf/core v4 03/19] perf buildid-cache: Fall back to the old style build-id cache
Quoted 9 lines · On Tue, 26 Apr 2016 10:47:49 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Tue, Apr 26, 2016 at 06:02:33PM +0900, Masami Hiramatsu escreveu:
Quoted 5 lines
Fall back to the old style build-id cache (~/.debug/<path-to-bin>/<build-id>) if possible. Because there is old build-id cache under ~/.debug, perf has to check if the old entry is there instead of returning an error. Or, user have to remove ~/.debug completely.
So, from the description this seems to address the issues I mentioned in the previous patch.
yes :)
Quoted 4 lines
Probably it is a good idea not to introduce the problem in the first place? I.e. combine this and the previous patch, so that we don't have this bisection break?
Yeah, I just try to keep original clean for review. I'll combine this with 02/19.
Thanks!
Quoted 94 lines
- Arnaldo
Quoted 91 lines
This patch introduces fallback code to try using old-style buildid caches. To update the cached entry, you just need to add a cache. It automatically removes old cache entry and make a new one in new style (~/.debug/<path-to-bin>/<build-id>/[elf|vdso|kallsyms]).
IOW, without this patch, "perf buildid-cache --add" always gets errors when adding existing binaries.
----# perf buildid-cache -a /usr/lib64/libc-2.20.so,/usr/bin/gcc Couldn't add /usr/bin/gcc: Not a directory Couldn't add /usr/lib64/libc-2.20.so: Not a directory ---- Moreover, --update option removes only symlink, thus the build-id cache is corrupted.This fixes above issues.
Signed-off-by Masami Hiramatsu <[email protected]>--- tools/perf/util/build-id.c | 17 ++++++++++++++++- tools/perf/util/symbol.c | 13 +++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-)tools/perf/util/build-id.c +16
-1@@ -155,6 +155,12 @@ static char *build_id_cache__linkname(const char *sbuild_id, char *bf,return bf; } +static bool __is_regular_file (const char *pathname) +{ +struct stat sb; +return stat (pathname, &sb) ==0 &&S_ISREG (sb.st_mode); +} +static const char *build_id_cache__basename (bool is_kallsyms,bool is_vdso) {return is_kallsyms ?"kallsyms" : (is_vdso ?"vdso" :"elf" );@@ -177,7 +183,11 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)if (!linkname)return NULL ; - ret =asnprintf (&bf, size,"%s/%s" , linkname, +/* Check if old style build_id cache */ +if (__is_regular_file (linkname)) + ret =asnprintf (&bf, size,"%s" , linkname); +else + ret =asnprintf (&bf, size,"%s/%s" , linkname,build_id_cache__basename (is_kallsyms, is_vdso));if (ret <0 || (!alloc && size < (unsigned int )ret)) bf =NULL ;@@ -445,6 +455,11 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,if (!dir_name) goto out_free; +/* Remove old style build-id cache */ +if (__is_regular_file (dir_name)) +if (unlink (dir_name)) + goto out_free; +if (mkdir_p (dir_name,0755 )) goto out_free;tools/perf/util/symbol.c +9
-4@@ -1687,11 +1687,16 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)scnprintf (path,sizeof (path),"%s/[kernel.kallsyms]/%s/kallsyms" , buildid_dir, sbuild_id); - +/* Try old style kallsyms cache */ if (access (path,F_OK )) { -pr_err ("No kallsyms or vmlinux with build-id %s was found\n" , - sbuild_id); -return NULL ; +scnprintf (path,sizeof (path),"%s/[kernel.kallsyms]/%s" , + buildid_dir, sbuild_id); + +if (access (path,F_OK )) { +pr_err ("No kallsyms or vmlinux with build-id %s was found\n" , + sbuild_id); +return NULL ; + } }return strdup (path);
Signature · 1 line
Masami Hiramatsu <[email protected]>
PATCH v4 4/19 perf: Add lsdir to read a directory
In reply to Masami HiramatsuFrom: Masami Hiramatsu <[email protected]>
As a utility function, add lsdir() which reads given directory and store entry name into a strlist. lsdir accepts a filter function so that user can filter out unneeded entries.
--- tools/perf/util/util.c | 34 ++++++++++++++++++++++++++++++++++ tools/perf/util/util.h | 4 ++++ 2 files changed, 38 insertions(+)
tools/perf/util/util.c +34 -0
@@ -117,6 +117,40 @@ int rm_rf(char *path)return rmdir (path); } +/* A filter which removes dot files */ +bool lsdir_no_dot_filter (const char *dirname__maybe_unused ,struct dirent *d) +{ +return d->d_name[0 ] !='.' ; +} + +/* lsdir reads a directory and store it in strlist */ +struct strlist *lsdir (const char *dirname, +bool (*filter)(const char *,struct dirent *)) +{ +struct strlist *list =NULL ; +DIR *dir; +struct dirent *d; + + dir =opendir (dirname); +if (!dir) +return NULL ; + + list =strlist__new (NULL ,NULL ); +if (!list) { + errno = -ENOMEM ; + goto out; + } + +while ((d =readdir (dir)) !=NULL ) { +if (!filter ||filter (dirname, d)) +strlist__add (list, d->d_name); + } + +out: +closedir (dir); +return list; +} +static int slow_copyfile (const char *from,const char *to) {int err =-1 ;
tools/perf/util/util.h +4 -0
@@ -79,6 +79,7 @@#include <termios.h> #include <linux/bitops.h> #include <termios.h> +#include "strlist.h" extern const char *graph_line;extern const char *graph_dotted_line;
@@ -222,6 +223,9 @@ static inline int sane_case(int x, int high)int mkdir_p (char *path,mode_t mode);int rm_rf (char *path); +struct strlist *lsdir (const char *dirname, +bool (*filter)(const char *,struct dirent *)); +bool lsdir_no_dot_filter (const char *dirname__maybe_unused ,struct dirent *d);int copyfile (const char *from,const char *to);int copyfile_mode (const char *from,const char *to,mode_t mode);int copyfile_offset (int fromfd,loff_t from_ofs,int tofd,loff_t to_ofs,u64 size);
Re: [PATCH perf/core v4 04/19] perf: Add lsdir to read a directory
Em Tue, Apr 26, 2016 at 06:02:42PM +0900, Masami Hiramatsu escreveu:
Quoted 9 lines
From: Masami Hiramatsu <[email protected]>
As a utility function, add
lsdir()which reads given directory and store entry name into a strlist. lsdir accepts a filter function so that user can filter out unneeded entries.Signed-off-by Masami Hiramatsu <[email protected]>Signed-off-by Masami Hiramatsu <[email protected]>
Thanks, applied.
- Arnaldo
Arnaldo Carvalho de Melo
maintainerRe: [PATCH perf/core v4 04/19] perf: Add lsdir to read a directory
Em Tue, Apr 26, 2016 at 10:40:20AM -0300, Arnaldo Carvalho de Melo escreveu:
Quoted 8 lines
Em Tue, Apr 26, 2016 at 06:02:42PM +0900, Masami Hiramatsu escreveu:
Quoted 7 lines
From: Masami Hiramatsu <[email protected]>
As a utility function, add
lsdir()which reads given directory and store entry name into a strlist. lsdir accepts a filter function so that user can filter out unneeded entries.
Quoted 4 lines
Quoted 2 lines
Signed-off-by Masami Hiramatsu <[email protected]>Signed-off-by Masami Hiramatsu <[email protected]>Thanks, applied.
Had to fix it to build on some distros, like ubuntu 12.04:
alldeps-ubuntu-12.04: FAILutil/util.h:228:38: error: declaration of 'dirname' shadows a global declaration [-Werror=shadow]
cc1: all warnings being treated as errors
mv: cannot stat `/tmp/build/perf/util/.db-export.o.tmp': No such file or directory make[3]: *** [/tmp/build/perf/util/db-export.o] Error 1
make[3]: *** Waiting for unfinished jobs....
make[2]: *** [util] Error 2
make[2]: *** [ui] Error 2
make[1]: *** [/tmp/build/perf/libperf-in.o] Error 2
make: *** [install-bin] Error 2
Re: [PATCH perf/core v4 04/19] perf: Add lsdir to read a directory
Quoted 16 lines · On Tue, 26 Apr 2016 11:07:42 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Tue, Apr 26, 2016 at 10:40:20AM -0300, Arnaldo Carvalho de Melo escreveu:
Quoted 8 lines
Em Tue, Apr 26, 2016 at 06:02:42PM +0900, Masami Hiramatsu escreveu:
Quoted 7 lines
From: Masami Hiramatsu <[email protected]>
As a utility function, add
lsdir()which reads given directory and store entry name into a strlist. lsdir accepts a filter function so that user can filter out unneeded entries.Quoted 4 lines
Quoted 2 lines
Signed-off-by Masami Hiramatsu <[email protected]>Signed-off-by Masami Hiramatsu <[email protected]>Thanks, applied.
Had to fix it to build on some distros, like ubuntu 12.04:
Quoted 11 lines
alldeps-ubuntu-12.04: FAIL
util/util.h:228:38: error: declaration of 'dirname' shadows a global declaration [-Werror=shadow]
cc1: all warnings being treated as errors
mv: cannot stat `/tmp/build/perf/util/.db-export.o.tmp': No such file or directory make[3]: *** [/tmp/build/perf/util/db-export.o] Error 1
make[3]: *** Waiting for unfinished jobs....
make[2]: *** [util] Error 2
make[2]: *** [ui] Error 2
make[1]: *** [/tmp/build/perf/libperf-in.o] Error
make: *** [install-bin] Error 2
Hmm, I didn't know that the dummy argument can shadow a global declaration. I might be better to rename "dirname" to "dir_name".
Thank you,
Signature · 1 line
Masami Hiramatsu <[email protected]>
Arnaldo Carvalho de Melo
maintainerRe: [PATCH perf/core v4 04/19] perf: Add lsdir to read a directory
Em Tue, Apr 26, 2016 at 11:52:29PM +0900, Masami Hiramatsu escreveu:
Quoted 31 lines
Quoted 16 lines · On Tue, 26 Apr 2016 11:07:42 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Tue, Apr 26, 2016 at 10:40:20AM -0300, Arnaldo Carvalho de Melo escreveu:
Quoted 8 lines
Em Tue, Apr 26, 2016 at 06:02:42PM +0900, Masami Hiramatsu escreveu:
Quoted 7 lines
From: Masami Hiramatsu <[email protected]>
As a utility function, add
lsdir()which reads given directory and store entry name into a strlist. lsdir accepts a filter function so that user can filter out unneeded entries.Quoted 4 lines
Quoted 2 lines
Signed-off-by Masami Hiramatsu <[email protected]>Signed-off-by Masami Hiramatsu <[email protected]>Thanks, applied.
Had to fix it to build on some distros, like ubuntu 12.04:
Quoted 11 lines
alldeps-ubuntu-12.04: FAIL
util/util.h:228:38: error: declaration of 'dirname' shadows a global declaration [-Werror=shadow]
cc1: all warnings being treated as errors
mv: cannot stat `/tmp/build/perf/util/.db-export.o.tmp': No such file or directory make[3]: *** [/tmp/build/perf/util/db-export.o] Error 1
make[3]: *** Waiting for unfinished jobs....
make[2]: *** [util] Error 2
make[2]: *** [ui] Error 2
make[1]: *** [/tmp/build/perf/libperf-in.o] Error
make: *** [install-bin] Error 2
Quoted 2 lines
Hmm, I didn't know that the dummy argument can shadow a global declaration. I might be better to rename "dirname" to "
dir_name".
I used 'name', its a short function and the name (lsdir) should indicate that name is indeed the directory name.
- Arnaldo
tip-bot for Masami Hiramatsu
merge bot[tip:perf/core] perf tools: Add lsdir() helper to read a directory
In reply to Masami Hiramatsuperf tools: Add lsdir() helper to read a directory
Commit-ID: e1ce726e1db2522b4848b3acffb7ece12439517c Gitweb: http://git.kernel.org/tip/e1ce726e1db2522b4848b3acffb7ece12439517c Author: Masami Hiramatsu <[email protected]> AuthorDate: Tue, 26 Apr 2016 18:02:42 +0900 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Tue, 26 Apr 2016 13:14:55 -0300
perf tools: Add lsdir() helper to read a directory
As a utility function, add lsdir() which reads given directory and store entry name into a strlist. lsdir accepts a filter function so that user can filter out unneeded entries.
--- tools/perf/util/util.c | 34 ++++++++++++++++++++++++++++++++++ tools/perf/util/util.h | 3 +++ 2 files changed, 37 insertions(+)
tools/perf/util/util.c +34 -0
@@ -117,6 +117,40 @@ int rm_rf(char *path)return rmdir (path); } +/* A filter which removes dot files */ +bool lsdir_no_dot_filter (const char *name__maybe_unused ,struct dirent *d) +{ +return d->d_name[0 ] !='.' ; +} + +/* lsdir reads a directory and store it in strlist */ +struct strlist *lsdir (const char *name, +bool (*filter)(const char *,struct dirent *)) +{ +struct strlist *list =NULL ; +DIR *dir; +struct dirent *d; + + dir =opendir (name); +if (!dir) +return NULL ; + + list =strlist__new (NULL ,NULL ); +if (!list) { + errno = -ENOMEM ; + goto out; + } + +while ((d =readdir (dir)) !=NULL ) { +if (!filter ||filter (name, d)) +strlist__add (list, d->d_name); + } + +out: +closedir (dir); +return list; +} +static int slow_copyfile (const char *from,const char *to) {int err =-1 ;
tools/perf/util/util.h +3 -0
@@ -79,6 +79,7 @@#include <termios.h> #include <linux/bitops.h> #include <termios.h> +#include "strlist.h" extern const char *graph_line;extern const char *graph_dotted_line;
@@ -222,6 +223,8 @@ static inline int sane_case(int x, int high)int mkdir_p (char *path,mode_t mode);int rm_rf (char *path); +struct strlist *lsdir (const char *name,bool (*filter)(const char *,struct dirent *)); +bool lsdir_no_dot_filter (const char *name,struct dirent *d);int copyfile (const char *from,const char *to);int copyfile_mode (const char *from,const char *to,mode_t mode);int copyfile_offset (int fromfd,loff_t from_ofs,int tofd,loff_t to_ofs,u64 size);
PATCH v4 5/19 perf-buildid-cache: Use lsdir for looking up buildid caches
In reply to Masami HiramatsuFrom: Masami Hiramatsu <[email protected]>
Use new lsdir() for looking up buildid caches. This changes logic a bit to ignore all dot files, since the build-id cache must not start with dot.
--- tools/perf/util/build-id.c | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-)
tools/perf/util/build-id.c +5 -25
@@ -400,38 +400,18 @@ int build_id_cache__list_build_ids(const char *pathname, {struct strlist *list;char *dir_name; -DIR *dir; -struct dirent *d;int ret =0 ; - list =strlist__new (NULL ,NULL ); dir_name =build_id_cache__dirname_from_path (pathname, false, false,NULL ); -if (!list || !dir_name) { - ret = -ENOMEM ; - goto out; - } +if (!dir_name) +return -ENOMEM ; -/* List up all dirents */ - dir =opendir (dir_name); -if (!dir) { + list =lsdir (dir_name, lsdir_no_dot_filter); +if (!list) ret = -errno; - goto out; - } - -while ((d =readdir (dir)) !=NULL ) { -if (!strcmp (d->d_name,"." ) || !strcmp (d->d_name,".." )) -continue ; -strlist__add (list, d->d_name); - } -closedir (dir); - -out: + *result = list;free (dir_name); -if (ret) -strlist__delete (list); -else - *result = list;return ret; }
PATCH v4 6/19 perf-probe: Let probe_file__add_event return 0 if succeeded
In reply to Masami HiramatsuSince other methods return 0 if succeeded (or filedesc), let probe_file__add_event() return 0 instead of the length of written bytes.
--- tools/perf/util/probe-file.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
tools/perf/util/probe-file.c +1 -2
@@ -220,8 +220,7 @@ int probe_file__add_event(int fd, struct probe_trace_event *tev)pr_debug ("Writing event: %s\n" , buf);if (!probe_event_dry_run) { - ret =write (fd, buf,strlen (buf)); -if (ret <=0 ) { +if (write (fd, buf,strlen (buf)) < (int )strlen (buf)) { ret = -errno;pr_warning ("Failed to write event: %s\n" ,strerror_r (errno, sbuf,sizeof (sbuf)));
Re: [PATCH perf/core v4 06/19] perf-probe: Let probe_file__add_event return 0 if succeeded
Em Tue, Apr 26, 2016 at 06:03:04PM +0900, Masami Hiramatsu escreveu:
Quoted 3 lines
Since other methods return 0 if succeeded (or filedesc), let
probe_file__add_event()return 0 instead of the length of written bytes.
Thanks, applied.
- Arnaldo
Quoted 19 lines
Signed-off-by Masami Hiramatsu <[email protected]>--- tools/perf/util/probe-file.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)tools/perf/util/probe-file.c +1
-2@@ -220,8 +220,7 @@ int probe_file__add_event(int fd, struct probe_trace_event *tev)pr_debug ("Writing event: %s\n" , buf);if (!probe_event_dry_run) { - ret =write (fd, buf,strlen (buf)); -if (ret <=0 ) { +if (write (fd, buf,strlen (buf)) < (int )strlen (buf)) { ret = -errno;pr_warning ("Failed to write event: %s\n" ,strerror_r (errno, sbuf,sizeof (sbuf)));
tip-bot for Masami Hiramatsu
merge bot[tip:perf/core] perf probe: Let probe_file__add_event return 0 if succeeded
In reply to Masami Hiramatsuperf probe: Let probe_file__add_event return 0 if succeeded
Commit-ID: 6ed0720a74d90eea51284c07592369d45d56f1f7 Gitweb: http://git.kernel.org/tip/6ed0720a74d90eea51284c07592369d45d56f1f7 Author: Masami Hiramatsu <[email protected]> AuthorDate: Tue, 26 Apr 2016 18:03:04 +0900 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Tue, 26 Apr 2016 13:14:58 -0300
perf probe: Let probe_file__add_event return 0 if succeeded
Since other methods return 0 if succeeded (or filedesc), let probe_file__add_event() return 0 instead of the length of written bytes.
--- tools/perf/util/probe-file.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
tools/perf/util/probe-file.c +1 -2
@@ -220,8 +220,7 @@ int probe_file__add_event(int fd, struct probe_trace_event *tev)pr_debug ("Writing event: %s\n" , buf);if (!probe_event_dry_run) { - ret =write (fd, buf,strlen (buf)); -if (ret <=0 ) { +if (write (fd, buf,strlen (buf)) < (int )strlen (buf)) { ret = -errno;pr_warning ("Failed to write event: %s\n" ,strerror_r (errno, sbuf,sizeof (sbuf)));
PATCH v4 7/19 perf probe: Add --cache option to cache the probe definitions
In reply to Masami HiramatsuFrom: Masami Hiramatsu <[email protected]>
Add --cache option to cache the probe definitions. This just saves the result of the dwarf analysis to probe cache.
---
Changes in v4:
- Remove cache saving failure message.
--- tools/perf/Documentation/perf-probe.txt | 4 tools/perf/builtin-probe.c | 1 tools/perf/util/build-id.c | 13 + tools/perf/util/build-id.h | 2 tools/perf/util/probe-event.c | 126 +++++++++++-- tools/perf/util/probe-event.h | 5 + tools/perf/util/probe-file.c | 299 +++++++++++++++++++++++++++++++ tools/perf/util/probe-file.h | 19 ++ 8 files changed, 441 insertions(+), 28 deletions(-)
tools/perf/Documentation/perf-probe.txt +4 -0
@@ -109,6 +109,10 @@ OPTIONS Dry run. With this option, --add and --del doesn't execute actual adding and removal operations. +--cache:: + Cache the probes (with --add option). Any events which successfully added + are also stored in the cache file. + --max-probes=NUM:: Set the maximum number of probe points for an event. Default is 128.
tools/perf/builtin-probe.c +1 -0
@@ -512,6 +512,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) "Enable symbol demangling"),OPT_BOOLEAN (0 ,"demangle-kernel" , &symbol_conf.demangle_kernel,"Enable kernel symbol demangling" ), +OPT_BOOLEAN (0 ,"cache" , &probe_conf.cache,"Manipulate probe cache" ), OPT_END() };int ret;
tools/perf/util/build-id.c +6 -7
@@ -371,9 +371,8 @@ void disable_buildid_cache(void) no_buildid_cache = true; } -static char *build_id_cache__dirname_from_path (const char *name, -bool is_kallsyms,bool is_vdso, -const char *sbuild_id) +char *build_id_cache__dirname_from_path (const char *sbuild_id,const char *name, +bool is_kallsyms,bool is_vdso) {char *realname = (char *)name, *filename;bool slash = is_kallsyms || is_vdso;
@@ -402,8 +401,8 @@ int build_id_cache__list_build_ids(const char *pathname,char *dir_name;int ret =0 ; - dir_name =build_id_cache__dirname_from_path (pathname, false, false, -NULL ); + dir_name =build_id_cache__dirname_from_path (NULL , pathname, + false, false);if (!dir_name)return -ENOMEM ;
@@ -430,8 +429,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; } - dir_name =build_id_cache__dirname_from_path (name, is_kallsyms, - is_vdso, sbuild_id); + dir_name =build_id_cache__dirname_from_path (sbuild_id, name, + is_kallsyms, is_vdso);if (!dir_name) goto out_free;
tools/perf/util/build-id.h +2 -0
@@ -28,6 +28,8 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);int perf_session__write_buildid_table (struct perf_session *session,int fd);int perf_session__cache_build_ids (struct perf_session *session); +char *build_id_cache__dirname_from_path (const char *sbuild_id,const char *name, +bool is_kallsyms,bool is_vdso);int build_id_cache__list_build_ids (const char *pathname,struct strlist **result);bool build_id_cache__cached (const char *sbuild_id);
tools/perf/util/probe-event.c +105 -21
176 lines not on this page · raw message
tools/perf/util/probe-event.h +5 -0
@@ -12,6 +12,7 @@ struct probe_conf {bool show_location_range;bool force_add;bool no_inlines; +bool cache;int max_probes; };extern struct probe_conf probe_conf;
@@ -121,6 +122,10 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev);char *synthesize_perf_probe_command (struct perf_probe_event *pev);char *synthesize_probe_trace_command (struct probe_trace_event *tev);char *synthesize_perf_probe_arg (struct perf_probe_arg *pa); +char *synthesize_perf_probe_point (struct perf_probe_point *pp); + +int perf_probe_event__copy (struct perf_probe_event *dst, +struct perf_probe_event *src);/* Check the perf_probe_event needs debuginfo */ bool perf_probe_event_need_dwarf (struct perf_probe_event *pev);
tools/perf/util/probe-file.c +299 -0
308 lines not on this page · raw message
tools/perf/util/probe-file.h +19 -0
@@ -18,5 +18,24 @@ int probe_file__get_events(int fd, struct strfilter *filter, struct strlist *plist);int probe_file__del_strlist (int fd,struct strlist *namelist); +/* Cache of probe definitions */ +struct probe_cache_entry { +struct list_head list; +struct perf_probe_event pev; +char *spev; +struct strlist *tevlist; +}; + +struct probe_cache { +int fd; +struct list_head list; +}; + +struct probe_cache *probe_cache__new (const char *target); +int probe_cache__add_entry (struct probe_cache *pcache, +struct perf_probe_event *pev, +struct probe_trace_event *tevs,int ntevs); +int probe_cache__commit (struct probe_cache *pcache); +void probe_cache__delete (struct probe_cache *pcache);#endif
PATCH v4 8/19 perf probe: Use cache entry if possible
In reply to Masami HiramatsuFrom: Masami Hiramatsu <[email protected]>
Before analyzing debuginfo, try to find a corresponding entry from probe cache always. This does not depend on --cache, the --cache enables to store/update cache, but looking up the cache is always enabled.
--- tools/perf/util/probe-event.c | 72 ++++++++++++++++++++++++++++++++++++++++- tools/perf/util/probe-file.c | 20 +++++++++++ tools/perf/util/probe-file.h | 5 ++- 3 files changed, 93 insertions(+), 4 deletions(-)
tools/perf/util/probe-event.c +70 -2
@@ -2388,17 +2388,24 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,char buf[64 ];int ret; +/* If probe_event or trace_event already have the name, reuse it */ if (pev->event) event = pev->event; -else +else if (tev->event) + event = tev->event; +else { +/* Or generate new one from probe point */ if (pev->point.function && (strncmp (pev->point.function,"0x" ,2 ) !=0 ) && !strisglob (pev->point.function)) event = pev->point.function;else event = tev->point.realname; + }if (pev->group) group = pev->group; +else if (tev->group) + group = tev->group;else group =PERFPROBE_GROUP ;
@@ -2445,7 +2452,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,for (i =0 ; i < ntevs; i++) { tev = &tevs[i];/* Skip if the symbol is out of .text or blacklisted */ -if (!tev->point.symbol) +if (!tev->point.symbol && !pev->uprobes)continue ;/* Set new name for tev (and update namelist) */
@@ -2746,6 +2753,62 @@ errout:bool __weak arch__prefers_symtab (void ) {return false; } +static int find_probe_trace_events_from_cache (struct perf_probe_event *pev, +struct probe_trace_event **tevs) +{ +struct probe_cache *cache; +struct probe_cache_entry *entry; +struct probe_trace_event *tev; +struct str_node *node; +int ret, i; + + cache =probe_cache__new (pev->target); +if (!cache) +return 0 ; + + entry =probe_cache__find (cache, pev); + +if (!entry && !pev->event && + (!pev->point.file && pev->point.function && !pev->point.retprobe && + !pev->point.line && !pev->point.offset && !pev->point.lazy_line)) { + entry =probe_cache__find_by_name (cache, pev->group, + pev->point.function); + } +if (!entry) { + ret =0 ; + goto out; + } + + ret =strlist__nr_entries (entry->tevlist); +if (ret > probe_conf.max_probes) { +pr_debug ("Too many entries matched in the cache of %s\n" , + pev->target ? :"kernel" ); + ret = -E2BIG ; + goto out; + } + + *tevs =zalloc (ret *sizeof (*tev)); +if (!*tevs) { + ret = -ENOMEM ; + goto out; + } + + i =0 ; +strlist__for_each (node, entry->tevlist) { + tev = &(*tevs)[i++]; + ret =parse_probe_trace_command (node->s, tev); +if (ret <0 ) + goto out; +/* Set the uprobes attribute as same as original */ + tev->uprobes = pev->uprobes; + } + ret = i; + +out: +probe_cache__delete (cache); +return ret; +} +static int convert_to_probe_trace_events (struct perf_probe_event *pev,struct probe_trace_event **tevs) {
@@ -2764,6 +2827,11 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,if (ret >0 )return ret; +/* At first, we need to lookup cache entry */ + ret =find_probe_trace_events_from_cache (pev, tevs); +if (ret >0 ) +return ret;/* Found in probe cache */ +if (arch__prefers_symtab () && !perf_probe_event_need_dwarf (pev)) { ret =find_probe_trace_events_from_map (pev, tevs);if (ret >0 )
tools/perf/util/probe-file.c +19 -1
@@ -506,7 +506,7 @@ static bool streql(const char *a, const char *b)return !strcmp (a, b); } -static struct probe_cache_entry * +struct probe_cache_entry *probe_cache__find (struct probe_cache *pcache,struct perf_probe_event *pev) {struct probe_cache_entry *entry =NULL ;
@@ -531,6 +531,24 @@ found:return entry; } +struct probe_cache_entry * +probe_cache__find_by_name (struct probe_cache *pcache, +const char *group,const char *event) +{ +struct probe_cache_entry *entry =NULL ; + +list_for_each_entry (entry, &pcache->list, list) { +/* Hit if same event name or same command-string */ +if (streql (entry->pev.group, group) && +streql (entry->pev.event, event)) + goto found; + } + entry =NULL ; + +found: +return entry; +} +int probe_cache__add_entry (struct probe_cache *pcache,struct perf_probe_event *pev,struct probe_trace_event *tevs,int ntevs)
tools/perf/util/probe-file.h +4 -1
@@ -37,5 +37,8 @@ int probe_cache__add_entry(struct probe_cache *pcache, struct probe_trace_event *tevs, int ntevs);int probe_cache__commit (struct probe_cache *pcache);void probe_cache__delete (struct probe_cache *pcache); - +struct probe_cache_entry *probe_cache__find (struct probe_cache *pcache, +struct perf_probe_event *pev); +struct probe_cache_entry *probe_cache__find_by_name (struct probe_cache *pcache, +const char *group,const char *event);#endif
PATCH v4 9/19 perf probe: Show all cached probes
In reply to Masami HiramatsuFrom: Masami Hiramatsu <[email protected]>
perf probe --list shows all cached probes when --cache is given. Each caches are shown with on which binary that probed. e.g.
-----
# perf probe --cache vfs_read \$params # perf probe --cache -x /lib64/libc-2.17.so getaddrinfo \$params # perf probe --cache --list /[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1): vfs_read $params /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc): getaddrinfo $params ----- Note that $params requires debuginfo.
--- tools/perf/Documentation/perf-probe.txt | 8 ++- tools/perf/builtin-probe.c | 2 - tools/perf/util/build-id.c | 79 ++++++++++++++++++++++++++++++- tools/perf/util/build-id.h | 3 + tools/perf/util/probe-event.c | 3 + tools/perf/util/probe-file.c | 67 ++++++++++++++++++++++++++ tools/perf/util/probe-file.h | 1 7 files changed, 156 insertions(+), 7 deletions(-)
tools/perf/Documentation/perf-probe.txt +6 -2
@@ -67,7 +67,10 @@ OPTIONS -l:: --list[=[GROUP:]EVENT]:: - List up current probe events. This can also accept filtering patterns of event names. + List up current probe events. This can also accept filtering patterns of + event names. + When this is used with --cache, perf shows all cached probes instead of + the live probes. -L:: --line=::
@@ -110,8 +113,9 @@ OPTIONS adding and removal operations. --cache:: - Cache the probes (with --add option). Any events which successfully added + (With --add) Cache the probes. Any events which successfully added are also stored in the cache file. + (With --list) Show cached probes. --max-probes=NUM:: Set the maximum number of probe points for an event. Default is 128.
tools/perf/builtin-probe.c +1 -1
@@ -44,7 +44,7 @@#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"#define DEFAULT_FUNC_FILTER "!_*" -#define DEFAULT_LIST_FILTER "*:*" +#define DEFAULT_LIST_FILTER "*"/* Session management structure */ static struct {
tools/perf/util/build-id.c +77 -2
97 lines not on this page · raw message
tools/perf/util/build-id.h +3 -0
@@ -28,8 +28,11 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);int perf_session__write_buildid_table (struct perf_session *session,int fd);int perf_session__cache_build_ids (struct perf_session *session); +char *build_id_cache__origname (const char *sbuild_id); +char *build_id_cache__linkname (const char *sbuild_id,char *bf,size_t size);char *build_id_cache__dirname_from_path (const char *sbuild_id,const char *name,bool is_kallsyms,bool is_vdso); +int build_id_cache__list_all (struct strlist **result);int build_id_cache__list_build_ids (const char *pathname,struct strlist **result);bool build_id_cache__cached (const char *sbuild_id);
tools/perf/util/probe-event.c +3 -0
@@ -2280,6 +2280,9 @@ int show_perf_probe_events(struct strfilter *filter)setup_pager (); +if (probe_conf.cache) +return probe_cache__show_all_caches (filter); + ret =init_probe_symbol_maps (false);if (ret <0 )return ret;
tools/perf/util/probe-file.c +65 -2
86 lines not on this page · raw message
tools/perf/util/probe-file.h +1 -0
@@ -41,4 +41,5 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev);struct probe_cache_entry *probe_cache__find_by_name (struct probe_cache *pcache,const char *group,const char *event); +int probe_cache__show_all_caches (struct strfilter *filter);#endif
PATCH v4 10/19 perf probe: Remove caches when --cache is given
In reply to Masami HiramatsuFrom: Masami Hiramatsu <[email protected]>
perf-probe --del removes caches when --cache is given. Note that the delete pattern is not same as normal events.
If you cached probes with event name, --del "eventname" works as expected. However, if you skipped it, the cached probes doesn't have actual event name. In that case
--del "probe-desc" is required (wildcard is acceptable).
For example a cache entry has the probe-desc "vfs_read $params", you can remove it with --del 'vfs_read*'.
-----
# perf probe --cache --list /[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1): vfs_read $params /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc): getaddrinfo $params
# perf probe --cache --del vfs_read\* Removed event: probe:vfs_read
# perf probe --cache --list /[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1): /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc): getaddrinfo $params -----
---
Changes in v4:
- move del_perf_probe_caches() into builtin-probe.c since command-line related delete procedure is there now.
--- tools/perf/Documentation/perf-probe.txt | 1 + tools/perf/builtin-probe.c | 27 +++++++++++++++++++++++++ tools/perf/util/probe-file.c | 33 +++++++++++++++++++++++-------- tools/perf/util/probe-file.h | 2 ++ 4 files changed, 55 insertions(+), 8 deletions(-)
tools/perf/Documentation/perf-probe.txt +1 -0
@@ -116,6 +116,7 @@ OPTIONS (With --add) Cache the probes. Any events which successfully added are also stored in the cache file. (With --list) Show cached probes. + (With --del) Remove cached probes. --max-probes=NUM:: Set the maximum number of probe points for an event. Default is 128.
tools/perf/builtin-probe.c +27 -0
@@ -363,6 +363,30 @@ out_cleanup:return ret; } +static int del_perf_probe_caches (struct strfilter *filter) +{ +struct probe_cache *cache; +struct strlist *bidlist; +struct str_node *nd; +int ret; + + ret =build_id_cache__list_all (&bidlist); +if (ret <0 ) { +pr_debug ("Failed to get buildids: %d\n" , ret); +return ret; + } + +strlist__for_each (nd, bidlist) { + cache =probe_cache__new (nd->s); +if (!cache) +continue ; +probe_cache__remove_entries (cache, filter); +probe_cache__commit (cache); +probe_cache__delete (cache); + } +return 0 ; +} +static int perf_del_probe_events (struct strfilter *filter) {int ret, ret2, ufd =-1 , kfd =-1 ;
@@ -375,6 +399,9 @@ static int perf_del_probe_events(struct strfilter *filter)pr_debug ("Delete filter: \'%s\'\n" , str); +if (probe_conf.cache) +return del_perf_probe_caches (filter); +/* Get current event names */ ret =probe_file__open_both (&kfd, &ufd,PF_FL_RW );if (ret <0 )
tools/perf/util/probe-file.c +25 -8
@@ -396,7 +396,6 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)return ret; } } - dir_name =build_id_cache__dirname_from_path (sbuildid, target, is_kallsyms, false); found:
@@ -652,19 +651,37 @@ out:return ret; } +static bool probe_cache_entry__compare (struct probe_cache_entry *entry, +struct strfilter *filter) +{ +char buf[128 ], *ptr = entry->spev; + +if (entry->pev.event) { +snprintf (buf,128 ,"%s:%s" , entry->pev.group, entry->pev.event); + ptr = buf; + } +return strfilter__compare (filter, ptr); +} + +int probe_cache__remove_entries (struct probe_cache *pcache, +struct strfilter *filter) +{ +struct probe_cache_entry *entry, *tmp; + +list_for_each_entry_safe (entry, tmp, &pcache->list, list) { +if (probe_cache_entry__compare (entry, filter)) +probe_cache_entry__delete (entry); + } +return 0 ; +} +static int probe_cache__show_entries (struct probe_cache *pcache,struct strfilter *filter) {struct probe_cache_entry *entry; -char buf[128 ], *ptr;list_for_each_entry (entry, &pcache->list, list) { -if (entry->pev.event) { - ptr = buf; -snprintf (buf,128 ,"%s:%s" , entry->pev.group, entry->pev.event); - }else - ptr = entry->spev; -if (strfilter__compare (filter, ptr)) +if (probe_cache_entry__compare (entry, filter))printf ("%s\n" , entry->spev); }return 0 ;
tools/perf/util/probe-file.h +2 -0
@@ -37,6 +37,8 @@ int probe_cache__add_entry(struct probe_cache *pcache, struct probe_trace_event *tevs, int ntevs);int probe_cache__commit (struct probe_cache *pcache);void probe_cache__delete (struct probe_cache *pcache); +int probe_cache__remove_entries (struct probe_cache *pcache, +struct strfilter *filter);struct probe_cache_entry *probe_cache__find (struct probe_cache *pcache,struct perf_probe_event *pev); struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
PATCH v4 11/19 perf/sdt: ELF support for SDT
In reply to Masami HiramatsuFrom: Hemant Kumar <[email protected]>
This patch serves the initial support to identify and list SDT events in binaries. When programs containing SDT markers are compiled, gcc with the help of assembler directives identifies them and places them in the section ".note.stapsdt". To find these markers from the binaries, one needs to traverse through this section and parse the relevant details like the name, type and location of the marker. Also, the original location could be skewed due to the effect of prelinking. If that is the case, the locations need to be adjusted.
The functions in this patch open a given ELF, find out the SDT section, parse the relevant details, adjust the location (if necessary) and populate them in a list.
A typical note entry in ".note.stapsdt" section is as follows :
|--nhdr.n_namesz--|
------------------------------------
| nhdr | "stapsdt" |
----- |----------------------------------|
| | <location> <base_address> |
| | <semaphore> |
nhdr.n_descsize | "provider_name" "note_name" |
| | <args> |
----- |----------------------------------|
| nhdr | "stapsdt" |
|...The above shows an excerpt from the section ".note.stapsdt". 'nhdr' is a structure which has the note name size (n_namesz), note description size (n_desc_sz) and note type (n_type). So, in order to parse the note note info, we need nhdr to tell us where to start from. As can be seen from <sys/sdt.h>, the name of the SDT notes given is "stapsdt". But this is not the identifier of the note.
After that, we go to description of the note to find out its location, the address of the ".stapsdt.base" section and the semaphore address. Then, we find the provider name and the SDT marker name and then follow the arguments.
--- tools/perf/util/symbol-elf.c | 252 ++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/symbol.h | 22 ++++ 2 files changed, 274 insertions(+)
tools/perf/util/symbol-elf.c +252 -0
@@ -1780,6 +1780,258 @@ void kcore_extract__delete(struct kcore_extract *kce)unlink (kce->extract_filename); } +/** +* populate_sdt_note : Parse raw data and identify SDT note +* @elf: elf of the opened file +* @data: raw data of a section with description offset applied +* @len: note description size +* @type: type of the note +* @sdt_notes: List to add the SDT note +* +* Responsible for parsing the @data in section .note.stapsdt in @elf and +* if its an SDT note, it appends to @sdt_notes list. +*/ +static int populate_sdt_note (Elf **elf,const char *data,size_t len, +struct list_head *sdt_notes) +{ +const char *provider, *name; +struct sdt_note *tmp =NULL ; +GElf_Ehdr ehdr; +GElf_Addr base_off =0 ; +GElf_Shdr shdr; +int ret = -EINVAL ; + +union { +Elf64_Addr a64[NR_ADDR ]; +Elf32_Addr a32[NR_ADDR ]; + } buf; + +Elf_Data dst = { + .d_buf = &buf, .d_type =ELF_T_ADDR , .d_version =EV_CURRENT , + .d_size =gelf_fsize ((*elf),ELF_T_ADDR ,NR_ADDR ,EV_CURRENT ), + .d_off =0 , .d_align =0 + }; +Elf_Data src = { + .d_buf = (void *) data, .d_type =ELF_T_ADDR , + .d_version =EV_CURRENT , .d_size = dst.d_size, .d_off =0 , + .d_align =0 + }; + + tmp = (struct sdt_note *)calloc (1 ,sizeof (struct sdt_note )); +if (!tmp) { + ret = -ENOMEM ; + goto out_err; + } + +INIT_LIST_HEAD (&tmp->note_list); + +if (len < dst.d_size +3 ) + goto out_free_note; + +/* Translation from file representation to memory representation */ +if (gelf_xlatetom (*elf, &dst, &src, +elf_getident (*elf,NULL )[EI_DATA ]) ==NULL ) { +pr_err ("gelf_xlatetom : %s\n" ,elf_errmsg (-1 )); + goto out_free_note; + } + +/* Populate the fields of sdt_note */ + provider = data + dst.d_size; + + name = (const char *)memchr (provider,'\0' , data + len - provider); +if (name++ ==NULL ) + goto out_free_note; + + tmp->provider =strdup (provider); +if (!tmp->provider) { + ret = -ENOMEM ; + goto out_free_note; + } + tmp->name =strdup (name); +if (!tmp->name) { + ret = -ENOMEM ; + goto out_free_prov; + } + +if (gelf_getclass (*elf) ==ELFCLASS32 ) { +memcpy (&tmp->addr, &buf,3 *sizeof (Elf32_Addr)); + tmp->bit32 = true; + }else { +memcpy (&tmp->addr, &buf,3 *sizeof (Elf64_Addr)); + tmp->bit32 = false; + } + +if (!gelf_getehdr (*elf, &ehdr)) { +pr_debug ("%s : cannot get elf header.\n" , __func__); + ret = -EBADF ; + goto out_free_name; + } + +/* Adjust the prelink effect : +* Find out the .stapsdt.base section. +* This scn will help us to handle prelinking (if present). +* Compare the retrieved file offset of the base section with the +* base address in the description of the SDT note. If its different, +* then accordingly, adjust the note location. +*/ +if (elf_section_by_name (*elf, &ehdr, &shdr,SDT_BASE_SCN ,NULL )) { + base_off = shdr.sh_offset; +if (base_off) { +if (tmp->bit32) + tmp->addr.a32[0 ] = tmp->addr.a32[0 ] + base_off - + tmp->addr.a32[1 ]; +else + tmp->addr.a64[0 ] = tmp->addr.a64[0 ] + base_off - + tmp->addr.a64[1 ]; + } + } + +list_add_tail (&tmp->note_list, sdt_notes); +return 0 ; + +out_free_name: +free (tmp->name); +out_free_prov: +free (tmp->provider); +out_free_note: +free (tmp); +out_err: +return ret; +} + +/** +* construct_sdt_notes_list : constructs a list of SDT notes +* @elf : elf to look into +* @sdt_notes : empty list_head +* +* Scans the sections in 'elf' for the section +* .note.stapsdt. It, then calls populate_sdt_note to find +* out the SDT events and populates the 'sdt_notes'. +*/ +static int construct_sdt_notes_list (Elf *elf,struct list_head *sdt_notes) +{ +GElf_Ehdr ehdr; +Elf_Scn *scn =NULL ; +Elf_Data *data; +GElf_Shdr shdr; +size_t shstrndx, next; +GElf_Nhdr nhdr; +size_t name_off, desc_off, offset; +int ret =0 ; + +if (gelf_getehdr (elf, &ehdr) ==NULL ) { + ret = -EBADF ; + goto out_ret; + } +if (elf_getshdrstrndx (elf, &shstrndx) !=0 ) { + ret = -EBADF ; + goto out_ret; + } + +/* Look for the required section */ + scn =elf_section_by_name (elf, &ehdr, &shdr,SDT_NOTE_SCN ,NULL ); +if (!scn) { + ret = -ENOENT ; + goto out_ret; + } + +if ((shdr.sh_type !=SHT_NOTE ) || (shdr.sh_flags &SHF_ALLOC )) { + ret = -ENOENT ; + goto out_ret; + } + + data =elf_getdata (scn,NULL ); + +/* Get the SDT notes */ +for (offset =0 ; (next =gelf_getnote (data, offset, &nhdr, &name_off, + &desc_off)) >0 ; offset = next) { +if (nhdr.n_namesz ==sizeof (SDT_NOTE_NAME ) && + !memcmp (data->d_buf + name_off,SDT_NOTE_NAME , +sizeof (SDT_NOTE_NAME ))) { +/* Check the type of the note */ +if (nhdr.n_type !=SDT_NOTE_TYPE ) + goto out_ret; + + ret =populate_sdt_note (&elf, ((data->d_buf) + desc_off), + nhdr.n_descsz, sdt_notes); +if (ret <0 ) + goto out_ret; + } + } +if (list_empty (sdt_notes)) + ret = -ENOENT ; + +out_ret: +return ret; +} + +/** +* get_sdt_note_list : Wrapper to construct a list of sdt notes +* @head : empty list_head +* @target : file to find SDT notes from +* +* This opens the file, initializes +* the ELF and then calls construct_sdt_notes_list. +*/ +int get_sdt_note_list (struct list_head *head,const char *target) +{ +Elf *elf; +int fd, ret; + + fd =open (target,O_RDONLY ); +if (fd <0 ) +return -EBADF ; + + elf =elf_begin (fd,PERF_ELF_C_READ_MMAP ,NULL ); +if (!elf) { + ret = -EBADF ; + goto out_close; + } + ret =construct_sdt_notes_list (elf, head); +elf_end (elf); +out_close: +close (fd); +return ret; +} + +/** +* cleanup_sdt_note_list : free the sdt notes' list +* @sdt_notes: sdt notes' list +* +* Free up the SDT notes in @sdt_notes. +* Returns the number of SDT notes free'd. +*/ +int cleanup_sdt_note_list (struct list_head *sdt_notes) +{ +struct sdt_note *tmp, *pos; +int nr_free =0 ; + +list_for_each_entry_safe (pos, tmp, sdt_notes, note_list) { +list_del (&pos->note_list); +free (pos->name); +free (pos->provider); +free (pos); + nr_free++; + } +return nr_free; +} + +/** +* sdt_notes__get_count: Counts the number of sdt events +* @start: list_head to sdt_notes list +* +* Returns the number of SDT notes in a list +*/ +int sdt_notes__get_count (struct list_head *start) +{ +struct sdt_note *sdt_ptr; +int count =0 ; + +list_for_each_entry (sdt_ptr, start, note_list) + count++; +return count; +} +void symbol__elf_init (void ) {elf_version (EV_CURRENT );
tools/perf/util/symbol.h +22 -0
@@ -331,4 +331,26 @@ void arch__elf_sym_adjust(GElf_Sym *sym);int arch__choose_best_symbol (struct symbol *syma,struct symbol *symb); +/* structure containing an SDT note's info */ +struct sdt_note { +char *name;/* name of the note*/ +char *provider;/* provider name */ +bool bit32;/* whether the location is 32 bits? */ +union {/* location, base and semaphore addrs */ +Elf64_Addr a64[3 ]; +Elf32_Addr a32[3 ]; + } addr; +struct list_head note_list;/* SDT notes' list */ +}; + +int get_sdt_note_list (struct list_head *head,const char *target); +int cleanup_sdt_note_list (struct list_head *sdt_notes); +int sdt_notes__get_count (struct list_head *start); + +#define SDT_BASE_SCN ".stapsdt.base" +#define SDT_NOTE_SCN ".note.stapsdt" +#define SDT_NOTE_TYPE 3 +#define SDT_NOTE_NAME "stapsdt" +#define NR_ADDR 3 +#endif /* __PERF_SYMBOL */
PATCH v4 12/19 perf probe: Add group name support
In reply to Masami HiramatsuFrom: Masami Hiramatsu <[email protected]>
Allow user to set group name for adding new event. Note that user must ensure that the group name doesn't conflict with existing group name carefully. E.g. Existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide kernel embedded events when loading modules.
---
Changes in v4:
- Update Documentation/perf-probe.txt too.
--- tools/perf/Documentation/perf-probe.txt | 10 ++++++---- tools/perf/util/probe-event.c | 23 ++++++++++++++--------- 2 files changed, 20 insertions(+), 13 deletions(-)
tools/perf/Documentation/perf-probe.txt +6 -4
@@ -143,16 +143,18 @@ PROBE SYNTAX Probe points are defined by following syntax. 1) Define event based on function name - [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...] + [[GROUP:]EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...] 2) Define event based on source file with line number - [EVENT=]SRC:ALN [ARG ...] + [[GROUP:]EVENT=]SRC:ALN [ARG ...] 3) Define event based on source file with lazy pattern - [EVENT=]SRC;PTN [ARG ...] + [[GROUP:]EVENT=]SRC;PTN [ARG ...] -'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'. +'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_<bin>' is used for uprobe. +Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the +modules. 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function. It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern. 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT).
tools/perf/util/probe-event.c +14 -9
@@ -1153,10 +1153,8 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)bool file_spec = false;/* * <Syntax> -* perf probe [EVENT=]SRC[:LN|;PTN] -* perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] -* -* TODO:Group name support +* perf probe [GRP:][EVENT=]SRC[:LN|;PTN] +* perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] */ if (!arg)return -EINVAL ;
@@ -1165,11 +1163,19 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)if (ptr && *ptr =='=' ) {/* Event name */ *ptr ='\0' ; tmp = ptr +1 ; -if (strchr (arg,':' )) { -semantic_error ("Group name is not supported yet.\n" ); -return -ENOTSUP ; - } + ptr =strchr (arg,':' ); +if (ptr) { + *ptr ='\0' ; +if (!is_c_func_name (arg)) + goto not_fname; + pev->group =strdup (arg); +if (!pev->group) +return -ENOMEM ; + arg = ptr +1 ; + }else + pev->group =NULL ;if (!is_c_func_name (arg)) { +not_fname:semantic_error ("%s is bad for event name -it must " "follow C symbol-naming rule.\n" , arg);return -EINVAL ;
@@ -1177,7 +1183,6 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) pev->event =strdup (arg);if (pev->event ==NULL )return -ENOMEM ; - pev->group =NULL ; arg = tmp; }
PATCH v4 13/19 perf-probe: Set default kprobe group name if it is not given
In reply to Masami HiramatsuFrom: Masami Hiramatsu <[email protected]>
Set kprobe group name as "probe" if it is not given.
--- tools/perf/util/probe-event.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
tools/perf/util/probe-event.c +7 -3
@@ -2822,9 +2822,13 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, {int ret; -if (pev->uprobes && !pev->group) { -/* Replace group name if not given */ - ret =convert_exec_to_group (pev->target, &pev->group); +if (!pev->group) { +/* Set group name if not given */ +if (!pev->uprobes) { + pev->group =strdup (PERFPROBE_GROUP ); + ret = pev->group ?0 : -ENOMEM ; + }else + ret =convert_exec_to_group (pev->target, &pev->group);if (ret !=0 ) {pr_warning ("Failed to make a group name.\n" );return ret;
Arnaldo Carvalho de Melo
maintainerRe: [PATCH perf/core v4 13/19] perf-probe: Set default kprobe group name if it is not given
Em Tue, Apr 26, 2016 at 06:04:13PM +0900, Masami Hiramatsu escreveu:
Quoted 3 lines
From: Masami Hiramatsu <[email protected]>
Set kprobe group name as "probe" if it is not given.
Looks good, applied,
- Arnaldo
Quoted 27 lines
Signed-off-by Masami Hiramatsu <[email protected]>Signed-off-by Masami Hiramatsu <[email protected]>--- tools/perf/util/probe-event.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)tools/perf/util/probe-event.c +7
-3@@ -2822,9 +2822,13 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, {int ret; -if (pev->uprobes && !pev->group) { -/* Replace group name if not given */ - ret =convert_exec_to_group (pev->target, &pev->group); +if (!pev->group) { +/* Set group name if not given */ +if (!pev->uprobes) { + pev->group =strdup (PERFPROBE_GROUP ); + ret = pev->group ?0 : -ENOMEM ; + }else + ret =convert_exec_to_group (pev->target, &pev->group);if (ret !=0 ) {pr_warning ("Failed to make a group name.\n" );return ret;
tip-bot for Masami Hiramatsu
merge bot[tip:perf/core] perf probe: Set default kprobe group name if it is not given
In reply to Masami Hiramatsuperf probe: Set default kprobe group name if it is not given
Commit-ID: 2a12ec13cc4ca8690ad2690c09bf8bff17c228d9 Gitweb: http://git.kernel.org/tip/2a12ec13cc4ca8690ad2690c09bf8bff17c228d9 Author: Masami Hiramatsu <[email protected]> AuthorDate: Tue, 26 Apr 2016 18:04:13 +0900 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Tue, 26 Apr 2016 13:14:58 -0300
perf probe: Set default kprobe group name if it is not given
Set kprobe group name as "probe" if it is not given.
--- tools/perf/util/probe-event.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
tools/perf/util/probe-event.c +7 -3
@@ -2748,9 +2748,13 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, {int ret; -if (pev->uprobes && !pev->group) { -/* Replace group name if not given */ - ret =convert_exec_to_group (pev->target, &pev->group); +if (!pev->group) { +/* Set group name if not given */ +if (!pev->uprobes) { + pev->group =strdup (PERFPROBE_GROUP ); + ret = pev->group ?0 : -ENOMEM ; + }else + ret =convert_exec_to_group (pev->target, &pev->group);if (ret !=0 ) {pr_warning ("Failed to make a group name.\n" );return ret;
PATCH v4 14/19 perf buildid-cache: Scan and import user SDT events to probe cache
In reply to Masami HiramatsuFrom: Masami Hiramatsu <[email protected]>
perf buildid-cache --add <binary> scans given binary and add the SDT events to probe cache. "sdt_" prefix is appended for all SDT providers to avoid event-name clash with other pre-defined events. It is possible to use the cached SDT events as other cached events, via perf probe --add "sdt_<provider>:<event>=<event>".
e.g.
----
# perf buildid-cache --add /lib/libc-2.17.so
# perf probe --cache --list | head -n 5
/usr/lib/libc-2.17.so (a6fb821bdf53660eb2c29f778757aef294d3d392):
sdt_libc:setjmp=setjmp
sdt_libc:longjmp=longjmp
sdt_libc:longjmp_target=longjmp_target
sdt_libc:memory_heap_new=memory_heap_new
# perf probe -x /usr/lib/libc-2.17.so \
-a sdt_libc:memory_heap_new=memory_heap_new
Added new event:
sdt_libc:memory_heap_new (on memory_heap_new
in /usr/lib/libc-2.17.so)You can now use it in all perf tools, such as:
perf record -e sdt_libc:memory_heap_new -aR sleep 1
# perf probe -l
sdt_libc:memory_heap_new (on new_heap+183 in /usr/lib/libc-2.17.so)
----Note that SDT event entries in probe-cache file is somewhat different from normal cached events. Normal one starts with "#", but SDTs are starting with "%".
---
Changes in v4:
- Fix a bug to copy correct group name to entries.
- Fix to consolidate same-name entries.
--- tools/perf/util/build-id.c | 27 +++++++++++++++-- tools/perf/util/probe-file.c | 67 ++++++++++++++++++++++++++++++++++++++++-- tools/perf/util/probe-file.h | 2 + 3 files changed, 90 insertions(+), 6 deletions(-)
tools/perf/util/build-id.c +24 -3
@@ -17,6 +17,7 @@#include "tool.h" #include "header.h" #include "vdso.h" +#include "probe-file.h" static bool no_buildid_cache;
@@ -490,6 +491,23 @@ int build_id_cache__list_build_ids(const char *pathname,return ret; } +#ifdef HAVE_LIBELF_SUPPORT +static void build_id_cache__add_sdt_cache (const char *sbuild_id, +const char *realname) +{ +struct probe_cache *cache; + + cache =probe_cache__new (sbuild_id); +if (!cache) +return ; +if (probe_cache__scan_sdt (cache, realname) >=0 ) +probe_cache__commit (cache); +probe_cache__delete (cache); +} +#else +#define build_id_cache__add_sdt_cache (sbuild_id, realname) do { } while (0) +#endif +int build_id_cache__add_s (const char *sbuild_id,const char *name,bool is_kallsyms,bool is_vdso) {
@@ -533,20 +551,23 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; } +/* Make a symbolic link */ if (!build_id_cache__linkname (sbuild_id, linkname, size)) goto out_free; + tmp =strrchr (linkname,'/' ); *tmp ='\0' ; -if (access (linkname,X_OK ) &&mkdir_p (linkname,0755 )) goto out_free; - *tmp ='/' ; tmp = dir_name +strlen (buildid_dir) -5 ;memcpy (tmp,"../.." ,5 ); -if (symlink (tmp, linkname) ==0 ) err =0 ; + +/* Update SDT cache */ +build_id_cache__add_sdt_cache (sbuild_id, realname); + out_free:if (!is_kallsyms)free (realname);
tools/perf/util/probe-file.c +64 -3
87 lines not on this page · raw message
tools/perf/util/probe-file.h +2 -0
@@ -21,6 +21,7 @@ int probe_file__del_strlist(int fd, struct strlist *namelist);/* Cache of probe definitions */ struct probe_cache_entry {struct list_head list; +bool sdt;struct perf_probe_event pev;char *spev;struct strlist *tevlist;
@@ -35,6 +36,7 @@ struct probe_cache *probe_cache__new(const char *target);int probe_cache__add_entry (struct probe_cache *pcache,struct perf_probe_event *pev,struct probe_trace_event *tevs,int ntevs); +int probe_cache__scan_sdt (struct probe_cache *pcache,const char *pathname);int probe_cache__commit (struct probe_cache *pcache);void probe_cache__delete (struct probe_cache *pcache); int probe_cache__remove_entries(struct probe_cache *pcache,
Re: [PATCH perf/core v4 14/19] perf buildid-cache: Scan and import user SDT events to probe cache
Quoted 23 lines · Masami Hiramatsu
From: Masami Hiramatsu <[email protected]>
perf buildid-cache --add <binary> scans given binary and add the SDT events to probe cache. "
sdt_" prefix is appended for all SDT providers to avoid event-name clash with other pre-defined events. It is possible to use the cached SDT events as other cached events, via perf probe --add "sdt_<provider>:<event>=<event>".e.g.
----# perf buildid-cache --add /lib/libc-2.17.so # perf probe --cache --list | head -n 5 /usr/lib/libc-2.17.so (a6fb821bdf53660eb2c29f778757aef294d3d392): sdt_libc:setjmp=setjmp sdt_libc:longjmp=longjmp sdt_libc:longjmp_target=longjmp_target sdt_libc:memory_heap_new=memory_heap_new # perf probe -x /usr/lib/libc-2.17.so \ -a sdt_libc:memory_heap_new=memory_heap_new Added new event: sdt_libc:memory_heap_new (on memory_heap_new in /usr/lib/libc-2.17.so)
Quoted 7 lines
You can now use it in all perf tools, such as:
perf record -e sdt_libc:memory_heap_new -aR sleep 1
# perf probe -l sdt_libc:memory_heap_new (on new_heap+183 in /usr/lib/libc-2.17.so) ----
Patch looks good to me. Have a few questions below :
What about the same binary path having different build-ids. For e.g a binary say, "test" has some markers, we add it to the cache. And, then the file gets rebuilt again with different build-id now. And we try to add to the cache again. It shows multiple entries in the cache :
# perf probe --cache --list /home/hemant/test (157380727e2b3854395aa915dfc91dbccc02058b): sdt_user_test:marker1=marker1 /home/hemant/test (64c0a018636e6d5145b09fc65839c1a4a7899f18): sdt_user_test:marker1=marker1 /home/hemant/test (c9e34759ae95b68fa385831041c5d9e0dd1697fb): sdt_user_test:marker1=marker1 ...
But, perf list sdt shows only one entry (which it should) :
# perf list sdt
List of pre-defined events (to be used in -e):
sdt_user_test:marker1 [SDT event]
perf probe also works as expected :
# perf probe -x /home/hemant/test %sdt_user_test:marker1 Added new event: sdt_user_test:marker1 (on %marker1 in /home/hemant/test)
You can now use it in all perf tools, such as:
perf record -e sdt_user_test:marker1 -aR sleep 1
So, the question is, do we delete the previous entries for "test" from the cache once we get a newer version of "test"?
Quoted 7 lines
Note that SDT event entries in probe-cache file is somewhat different from normal cached events. Normal one starts with "#", but SDTs are starting with "%".
Signed-off-by Masami Hiramatsu <[email protected]>Signed-off-by Masami Hiramatsu <[email protected]>---
[SNIP]
tools/perf/util/probe-file.c out_err: · line 634
Quoted 6 lines
tools/perf/util/probe-file.c +6
-0+list_for_each_entry (note, &sdtlist, note_list) { + ret =snprintf (sdtgrp,64 ,"sdt_%s" , note->provider); +if (ret <0 ) +break ; +/* Try to find same-name entry */ + entry =probe_cache__find_by_name (pcache, sdtgrp, note->name);
Wouldn't it be better to compare the build-id rather than the event name? So, if there is a new sdt event added to a binary, its build-id will change. And, if there is no change, the build-id remains the same.
Only if there is a change in the build-id, we can go for searching the event name. This two level check can help optimizing the search.
Quoted 65 lines
tools/perf/util/probe-file.c +33
-2+if (!entry) { + entry =probe_cache_entry__new (NULL ); +if (!entry) { + ret = -ENOMEM ; +break ; + } + entry->sdt = true; + ret =asprintf (&entry->spev,"%s:%s=%s" , sdtgrp, + note->name, note->name); +if (ret <0 ) +break ; + entry->pev.event =strdup (note->name); + entry->pev.group =strdup (sdtgrp); +list_add_tail (&entry->list, &pcache->list); + } + ret =asprintf (&buf,"p:%s/%s %s:0x%llx" , + sdtgrp, note->name, pathname, +sdt_note__get_addr (note)); +if (ret <0 ) +break ; +strlist__add (entry->tevlist, buf); +free (buf); + entry =NULL ; + } +if (entry) +probe_cache_entry__delete (entry); +cleanup_sdt_note_list (&sdtlist); +return ret; +} +static int probe_cache_entry__write (struct probe_cache_entry *entry,int fd) {struct str_node *snode;struct iovec iov[3 ]; +const char *prefix = entry->sdt ?"%" :"#" ;int ret; -pr_debug ("Writing cache: #%s\n" , entry->spev); - iov[0 ].iov_base = (void *)"#" ; iov[0 ].iov_len =1 ; +pr_debug ("Writing cache: %s%s\n" , prefix, entry->spev); + iov[0 ].iov_base = (void *)prefix; iov[0 ].iov_len =1 ; iov[1 ].iov_base = entry->spev; iov[1 ].iov_len =strlen (entry->spev); iov[2 ].iov_base = (void *)"\n" ; iov[2 ].iov_len =1 ; ret =writev (fd, iov,3 );tools/perf/util/probe-file.h +2
-0@@ -21,6 +21,7 @@ int probe_file__del_strlist(int fd, struct strlist *namelist);/* Cache of probe definitions */ struct probe_cache_entry {struct list_head list; +bool sdt;struct perf_probe_event pev;char *spev;struct strlist *tevlist;@@ -35,6 +36,7 @@ struct probe_cache *probe_cache__new(const char *target);int probe_cache__add_entry (struct probe_cache *pcache,struct perf_probe_event *pev,struct probe_trace_event *tevs,int ntevs); +int probe_cache__scan_sdt (struct probe_cache *pcache,const char *pathname);int probe_cache__commit (struct probe_cache *pcache);void probe_cache__delete (struct probe_cache *pcache); int probe_cache__remove_entries(struct probe_cache *pcache,
Signature · 2 lines
Thanks, Hemant Kumar
Arnaldo Carvalho de Melo
maintainerRe: [PATCH perf/core v4 14/19] perf buildid-cache: Scan and import user SDT events to probe cache
Em Wed, Apr 27, 2016 at 08:49:08PM +0530, Hemant Kumar escreveu:
Quoted 61 lines · Masami Hiramatsu
Quoted 23 lines
From: Masami Hiramatsu <[email protected]>
perf buildid-cache --add <binary> scans given binary and add the SDT events to probe cache. "
sdt_" prefix is appended for all SDT providers to avoid event-name clash with other pre-defined events. It is possible to use the cached SDT events as other cached events, via perf probe --add "sdt_<provider>:<event>=<event>".e.g.
----# perf buildid-cache --add /lib/libc-2.17.so # perf probe --cache --list | head -n 5 /usr/lib/libc-2.17.so (a6fb821bdf53660eb2c29f778757aef294d3d392): sdt_libc:setjmp=setjmp sdt_libc:longjmp=longjmp sdt_libc:longjmp_target=longjmp_target sdt_libc:memory_heap_new=memory_heap_new # perf probe -x /usr/lib/libc-2.17.so \ -a sdt_libc:memory_heap_new=memory_heap_new Added new event: sdt_libc:memory_heap_new (on memory_heap_new in /usr/lib/libc-2.17.so)Quoted 7 lines
You can now use it in all perf tools, such as:
perf record -e sdt_libc:memory_heap_new -aR sleep 1
# perf probe -l sdt_libc:memory_heap_new (on new_heap+183 in /usr/lib/libc-2.17.so) ----Patch looks good to me. Have a few questions below :
What about the same binary path having different build-ids. For e.g a binary say, "test" has some markers, we add it to the cache. And, then the file gets rebuilt again with different build-id now. And we try to add to the cache again. It shows multiple entries in the cache :
# perf probe --cache --list /home/hemant/test (157380727e2b3854395aa915dfc91dbccc02058b): sdt_user_test:marker1=marker1 /home/hemant/test (64c0a018636e6d5145b09fc65839c1a4a7899f18): sdt_user_test:marker1=marker1 /home/hemant/test (c9e34759ae95b68fa385831041c5d9e0dd1697fb): sdt_user_test:marker1=marker1 ...But, perf list sdt shows only one entry (which it should) :
# perf list sdtList of pre-defined events (to be used in -e):
sdt_user_test:marker1 [SDT event]
perf probe also works as expected :
# perf probe -x /home/hemant/test %sdt_user_test:marker1 Added new event: sdt_user_test:marker1 (on %marker1 in /home/hemant/test)
Quoted 6 lines
You can now use it in all perf tools, such as:
perf record -e sdt_user_test:marker1 -aR sleep 1
So, the question is, do we delete the previous entries for "test" from the cache once we get a newer version of "test"?
No, we shouldn't, since those entries may be used for other tasks that involves using the exact DSO used for a particular perf.data session.
Humm, but you are talking about what cache? The "probe cache" or the "build-id cache"? My previous statement was about the build-id cache.
For the probe cache, humm, probably we want to keep it as well, we may have moved that 'test' file to some other place, renamed it, etc, but it continues being accessible by its content-based identifier (the build-id) and could be used in ways we don't envision right now.
I.e. the same principle used for the build-id cache should be used for this probe cache, where we store things by build-id.
We need to prune this from time to time and for this we have:
perf buildid-cache purge
But that right now is unflexible, we should have a way to ask to control how much is purged :-\
- Arnaldo
- Arnaldo
Quoted 91 lines
Quoted 7 lines
Note that SDT event entries in probe-cache file is somewhat different from normal cached events. Normal one starts with "#", but SDTs are starting with "%".
Signed-off-by Masami Hiramatsu <[email protected]>Signed-off-by Masami Hiramatsu <[email protected]>---
[SNIP]
tools/perf/util/probe-file.c out_err: · line 634
Quoted 6 lines
tools/perf/util/probe-file.c +6
-0+list_for_each_entry (note, &sdtlist, note_list) { + ret =snprintf (sdtgrp,64 ,"sdt_%s" , note->provider); +if (ret <0 ) +break ; +/* Try to find same-name entry */ + entry =probe_cache__find_by_name (pcache, sdtgrp, note->name);Wouldn't it be better to compare the build-id rather than the event name? So, if there is a new sdt event added to a binary, its build-id will change. And, if there is no change, the build-id remains the same.
Only if there is a change in the build-id, we can go for searching the event name. This two level check can help optimizing the search.
Quoted 65 lines
tools/perf/util/probe-file.c +33
-2+if (!entry) { + entry =probe_cache_entry__new (NULL ); +if (!entry) { + ret = -ENOMEM ; +break ; + } + entry->sdt = true; + ret =asprintf (&entry->spev,"%s:%s=%s" , sdtgrp, + note->name, note->name); +if (ret <0 ) +break ; + entry->pev.event =strdup (note->name); + entry->pev.group =strdup (sdtgrp); +list_add_tail (&entry->list, &pcache->list); + } + ret =asprintf (&buf,"p:%s/%s %s:0x%llx" , + sdtgrp, note->name, pathname, +sdt_note__get_addr (note)); +if (ret <0 ) +break ; +strlist__add (entry->tevlist, buf); +free (buf); + entry =NULL ; + } +if (entry) +probe_cache_entry__delete (entry); +cleanup_sdt_note_list (&sdtlist); +return ret; +} +static int probe_cache_entry__write (struct probe_cache_entry *entry,int fd) {struct str_node *snode;struct iovec iov[3 ]; +const char *prefix = entry->sdt ?"%" :"#" ;int ret; -pr_debug ("Writing cache: #%s\n" , entry->spev); - iov[0 ].iov_base = (void *)"#" ; iov[0 ].iov_len =1 ; +pr_debug ("Writing cache: %s%s\n" , prefix, entry->spev); + iov[0 ].iov_base = (void *)prefix; iov[0 ].iov_len =1 ; iov[1 ].iov_base = entry->spev; iov[1 ].iov_len =strlen (entry->spev); iov[2 ].iov_base = (void *)"\n" ; iov[2 ].iov_len =1 ; ret =writev (fd, iov,3 );tools/perf/util/probe-file.h +2
-0@@ -21,6 +21,7 @@ int probe_file__del_strlist(int fd, struct strlist *namelist);/* Cache of probe definitions */ struct probe_cache_entry {struct list_head list; +bool sdt;struct perf_probe_event pev;char *spev;struct strlist *tevlist;@@ -35,6 +36,7 @@ struct probe_cache *probe_cache__new(const char *target);int probe_cache__add_entry (struct probe_cache *pcache,struct perf_probe_event *pev,struct probe_trace_event *tevs,int ntevs); +int probe_cache__scan_sdt (struct probe_cache *pcache,const char *pathname);int probe_cache__commit (struct probe_cache *pcache);void probe_cache__delete (struct probe_cache *pcache); int probe_cache__remove_entries(struct probe_cache *pcache,Signature · 2 lines
Thanks, Hemant Kumar
Re: [PATCH perf/core v4 14/19] perf buildid-cache: Scan and import user SDT events to probe cache
Quoted 64 lines · On Wed, 27 Apr 2016 12:28:16 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Wed, Apr 27, 2016 at 08:49:08PM +0530, Hemant Kumar escreveu:
Quoted 63 lines · Masami Hiramatsu
Quoted 23 lines
From: Masami Hiramatsu <[email protected]>
perf buildid-cache --add <binary> scans given binary and add the SDT events to probe cache. "
sdt_" prefix is appended for all SDT providers to avoid event-name clash with other pre-defined events. It is possible to use the cached SDT events as other cached events, via perf probe --add "sdt_<provider>:<event>=<event>".e.g.
----# perf buildid-cache --add /lib/libc-2.17.so # perf probe --cache --list | head -n 5 /usr/lib/libc-2.17.so (a6fb821bdf53660eb2c29f778757aef294d3d392): sdt_libc:setjmp=setjmp sdt_libc:longjmp=longjmp sdt_libc:longjmp_target=longjmp_target sdt_libc:memory_heap_new=memory_heap_new # perf probe -x /usr/lib/libc-2.17.so \ -a sdt_libc:memory_heap_new=memory_heap_new Added new event: sdt_libc:memory_heap_new (on memory_heap_new in /usr/lib/libc-2.17.so)Quoted 7 lines
You can now use it in all perf tools, such as:
perf record -e sdt_libc:memory_heap_new -aR sleep 1
# perf probe -l sdt_libc:memory_heap_new (on new_heap+183 in /usr/lib/libc-2.17.so) ----Patch looks good to me. Have a few questions below :
What about the same binary path having different build-ids. For e.g a binary say, "test" has some markers, we add it to the cache. And, then the file gets rebuilt again with different build-id now. And we try to add to the cache again. It shows multiple entries in the cache :
# perf probe --cache --list /home/hemant/test (157380727e2b3854395aa915dfc91dbccc02058b): sdt_user_test:marker1=marker1 /home/hemant/test (64c0a018636e6d5145b09fc65839c1a4a7899f18): sdt_user_test:marker1=marker1 /home/hemant/test (c9e34759ae95b68fa385831041c5d9e0dd1697fb): sdt_user_test:marker1=marker1 ...But, perf list sdt shows only one entry (which it should) :
# perf list sdtList of pre-defined events (to be used in -e):
sdt_user_test:marker1 [SDT event]
perf probe also works as expected :
# perf probe -x /home/hemant/test %sdt_user_test:marker1 Added new event: sdt_user_test:marker1 (on %marker1 in /home/hemant/test)You can now use it in all perf tools, such as:
Quoted 7 lines
Quoted 4 lines
perf record -e sdt_user_test:marker1 -aR sleep 1
So, the question is, do we delete the previous entries for "test" from the cache once we get a newer version of "test"?
No, we shouldn't, since those entries may be used for other tasks that involves using the exact DSO used for a particular perf.data session.
Agreed. And you can do it by using perf buildid-cache as below;
# perf buildid-cache --purge /home/hemant/test # perf buildid-cache --add /home/hemant/test
This actually removes all old binary caches, and it maybe not what you want. Or, you can try removing cached events too.
# perf probe --cache -d %sdt_user_test:\* # perf buildid-cache --add /home/hemant/test
Quoted 11 lines
Humm, but you are talking about what cache? The "probe cache" or the "build-id cache"? My previous statement was about the build-id cache.
For the probe cache, humm, probably we want to keep it as well, we may have moved that 'test' file to some other place, renamed it, etc, but it continues being accessible by its content-based identifier (the build-id) and could be used in ways we don't envision right now.
I.e. the same principle used for the build-id cache should be used for this probe cache, where we store things by build-id.
Quoted 6 lines
We need to prune this from time to time and for this we have:
perf buildid-cache purge
But that right now is unflexible, we should have a way to ask to control how much is purged :-\
Agreed, current buildid-cache --update does just rescan current binary, but maybe it should also remove old caches.
Quoted 11 lines
Quoted 11 lines
[SNIP]
tools/perf/util/probe-file.c out_err: · line 634
Quoted 6 lines
tools/perf/util/probe-file.c +6
-0+list_for_each_entry (note, &sdtlist, note_list) { + ret =snprintf (sdtgrp,64 ,"sdt_%s" , note->provider); +if (ret <0 ) +break ; +/* Try to find same-name entry */ + entry =probe_cache__find_by_name (pcache, sdtgrp, note->name);Wouldn't it be better to compare the build-id rather than the event name? So, if there is a new sdt event added to a binary, its build-id will change. And, if there is no change, the build-id remains the same.
This is not such purpose, but just for folding same name SDTs(but different addresses) on same binary.
Quoted 3 lines
Quoted 3 lines
Only if there is a change in the build-id, we can go for searching the event name. This two level check can help optimizing the search.
That have been done in build-id.c :)
Thank you,
Signature · 1 line
Masami Hiramatsu <[email protected]>
Re: [PATCH perf/core v4 14/19] perf buildid-cache: Scan and import user SDT events to probe cache
Quoted 73 lines · Masami Hiramatsu
Quoted 60 lines · On Wed, 27 Apr 2016 12:28:16 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Wed, Apr 27, 2016 at 08:49:08PM +0530, Hemant Kumar escreveu:
Quoted 59 lines · Masami Hiramatsu
Quoted 23 lines
From: Masami Hiramatsu <[email protected]>
perf buildid-cache --add <binary> scans given binary and add the SDT events to probe cache. "
sdt_" prefix is appended for all SDT providers to avoid event-name clash with other pre-defined events. It is possible to use the cached SDT events as other cached events, via perf probe --add "sdt_<provider>:<event>=<event>".e.g.
----# perf buildid-cache --add /lib/libc-2.17.so # perf probe --cache --list | head -n 5 /usr/lib/libc-2.17.so (a6fb821bdf53660eb2c29f778757aef294d3d392): sdt_libc:setjmp=setjmp sdt_libc:longjmp=longjmp sdt_libc:longjmp_target=longjmp_target sdt_libc:memory_heap_new=memory_heap_new # perf probe -x /usr/lib/libc-2.17.so \ -a sdt_libc:memory_heap_new=memory_heap_new Added new event: sdt_libc:memory_heap_new (on memory_heap_new in /usr/lib/libc-2.17.so)Quoted 7 lines
You can now use it in all perf tools, such as:
perf record -e sdt_libc:memory_heap_new -aR sleep 1
# perf probe -l sdt_libc:memory_heap_new (on new_heap+183 in /usr/lib/libc-2.17.so) ----Patch looks good to me. Have a few questions below :
What about the same binary path having different build-ids. For e.g a binary say, "test" has some markers, we add it to the cache. And, then the file gets rebuilt again with different build-id now. And we try to add to the cache again. It shows multiple entries in the cache :
# perf probe --cache --list /home/hemant/test (157380727e2b3854395aa915dfc91dbccc02058b): sdt_user_test:marker1=marker1 /home/hemant/test (64c0a018636e6d5145b09fc65839c1a4a7899f18): sdt_user_test:marker1=marker1 /home/hemant/test (c9e34759ae95b68fa385831041c5d9e0dd1697fb): sdt_user_test:marker1=marker1 ...But, perf list sdt shows only one entry (which it should) :
# perf list sdtList of pre-defined events (to be used in -e):
sdt_user_test:marker1 [SDT event]
perf probe also works as expected :
# perf probe -x /home/hemant/test %sdt_user_test:marker1 Added new event: sdt_user_test:marker1 (on %marker1 in /home/hemant/test)Quoted 8 lines
Quoted 6 lines
You can now use it in all perf tools, such as:
perf record -e sdt_user_test:marker1 -aR sleep 1
So, the question is, do we delete the previous entries for "test" from the cache once we get a newer version of "test"?
No, we shouldn't, since those entries may be used for other tasks that involves using the exact DSO used for a particular perf.data session.
Agreed. And you can do it by using perf buildid-cache as below;
Quoted 7 lines
# perf buildid-cache --purge /home/hemant/test # perf buildid-cache --add /home/hemant/testThis actually removes all old binary caches, and it maybe not what you want. Or, you can try removing cached events too.
# perf probe --cache -d %sdt_user_test:\*
Yeah, it does work for me, but without the '%'.
Quoted 13 lines
# perf buildid-cache --add /home/hemant/testQuoted 11 lines
Humm, but you are talking about what cache? The "probe cache" or the "build-id cache"? My previous statement was about the build-id cache.
For the probe cache, humm, probably we want to keep it as well, we may have moved that 'test' file to some other place, renamed it, etc, but it continues being accessible by its content-based identifier (the build-id) and could be used in ways we don't envision right now.
I.e. the same principle used for the build-id cache should be used for this probe cache, where we store things by build-id.
Quoted 8 lines
Quoted 6 lines
We need to prune this from time to time and for this we have:
perf buildid-cache purge
But that right now is unflexible, we should have a way to ask to control how much is purged :-\
Agreed, current buildid-cache --update does just rescan current binary, but maybe it should also remove old caches.
Ok.
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
[SNIP]
tools/perf/util/probe-file.c out_err: · line 634
Quoted 6 lines
tools/perf/util/probe-file.c +6
-0+list_for_each_entry (note, &sdtlist, note_list) { + ret =snprintf (sdtgrp,64 ,"sdt_%s" , note->provider); +if (ret <0 ) +break ; +/* Try to find same-name entry */ + entry =probe_cache__find_by_name (pcache, sdtgrp, note->name);Wouldn't it be better to compare the build-id rather than the event name? So, if there is a new sdt event added to a binary, its build-id will change. And, if there is no change, the build-id remains the same.
Quoted 2 lines
This is not such purpose, but just for folding same name SDTs(but different addresses) on same binary.
I get it. But, I was wondering whether that can be used for comparison as well.
Quoted 3 lines
Quoted 2 lines
Quoted 2 lines
Only if there is a change in the build-id, we can go for searching the event name. This two level check can help optimizing the search.
That have been done in
build-id.c:)
Ok, probably missed it.
Quoted 2 lines
Thank you,
Thanks for the explanation.
Signature · 2 lines
Thanks, Hemant Kumar
Re: [PATCH perf/core v4 14/19] perf buildid-cache: Scan and import user SDT events to probe cache
In reply to Arnaldo Carvalho de MeloQuoted 64 lines · Arnaldo Carvalho de Melo
Em Wed, Apr 27, 2016 at 08:49:08PM +0530, Hemant Kumar escreveu:
Quoted 63 lines · Masami Hiramatsu
Quoted 23 lines
From: Masami Hiramatsu <[email protected]>
perf buildid-cache --add <binary> scans given binary and add the SDT events to probe cache. "
sdt_" prefix is appended for all SDT providers to avoid event-name clash with other pre-defined events. It is possible to use the cached SDT events as other cached events, via perf probe --add "sdt_<provider>:<event>=<event>".e.g.
----# perf buildid-cache --add /lib/libc-2.17.so # perf probe --cache --list | head -n 5 /usr/lib/libc-2.17.so (a6fb821bdf53660eb2c29f778757aef294d3d392): sdt_libc:setjmp=setjmp sdt_libc:longjmp=longjmp sdt_libc:longjmp_target=longjmp_target sdt_libc:memory_heap_new=memory_heap_new # perf probe -x /usr/lib/libc-2.17.so \ -a sdt_libc:memory_heap_new=memory_heap_new Added new event: sdt_libc:memory_heap_new (on memory_heap_new in /usr/lib/libc-2.17.so)Quoted 7 lines
You can now use it in all perf tools, such as:
perf record -e sdt_libc:memory_heap_new -aR sleep 1
# perf probe -l sdt_libc:memory_heap_new (on new_heap+183 in /usr/lib/libc-2.17.so) ----Patch looks good to me. Have a few questions below :
What about the same binary path having different build-ids. For e.g a binary say, "test" has some markers, we add it to the cache. And, then the file gets rebuilt again with different build-id now. And we try to add to the cache again. It shows multiple entries in the cache :
# perf probe --cache --list /home/hemant/test (157380727e2b3854395aa915dfc91dbccc02058b): sdt_user_test:marker1=marker1 /home/hemant/test (64c0a018636e6d5145b09fc65839c1a4a7899f18): sdt_user_test:marker1=marker1 /home/hemant/test (c9e34759ae95b68fa385831041c5d9e0dd1697fb): sdt_user_test:marker1=marker1 ...But, perf list sdt shows only one entry (which it should) :
# perf list sdtList of pre-defined events (to be used in -e):
sdt_user_test:marker1 [SDT event]
perf probe also works as expected :
# perf probe -x /home/hemant/test %sdt_user_test:marker1 Added new event: sdt_user_test:marker1 (on %marker1 in /home/hemant/test)You can now use it in all perf tools, such as:
perf record -e sdt_user_test:marker1 -aR sleep 1
Quoted 7 lines
Quoted 2 lines
So, the question is, do we delete the previous entries for "test" from the cache once we get a newer version of "test"?
No, we shouldn't, since those entries may be used for other tasks that involves using the exact DSO used for a particular perf.data session.
Humm, but you are talking about what cache? The "probe cache" or the "build-id cache"? My previous statement was about the build-id cache.
I was talking about the "probe cache".
Quoted 4 lines
For the probe cache, humm, probably we want to keep it as well, we may have moved that 'test' file to some other place, renamed it, etc, but it continues being accessible by its content-based identifier (the build-id) and could be used in ways we don't envision right now.
Agreed. Makes sense.
Quoted 9 lines
I.e. the same principle used for the build-id cache should be used for this probe cache, where we store things by build-id.
We need to prune this from time to time and for this we have:
perf buildid-cache purge
But that right now is unflexible, we should have a way to ask to control how much is purged :-\
Right.
Signature · 2 lines
Thanks, Hemant Kumar
PATCH v4 15/19 perf probe: Accept %sdt and %cached event name
In reply to Masami HiramatsuFrom: Masami Hiramatsu <[email protected]>
To improbe usability, support %[PROVIDER:]SDTEVENT format to add new probes on SDT and cached events.
e.g.
----
# perf probe -x /lib/libc-2.17.so %lll_lock_wait_private
Added new event:
sdt_libc:lll_lock_wait_private (on %lll_lock_wait_private in
/usr/lib/libc-2.17.so)You can now use it in all perf tools, such as:
perf record -e sdt_libc:lll_lock_wait_private -aR sleep 1
# perf probe -l | more
sdt_libc:lll_lock_wait_private (on __lll_lock_wait_private+21
in /usr/lib/libc-2.17.so)
----Note that this is not only for SDT events, but also normal events with event-name.
e.g. define "myevent" on cache (-n doesn't add the real probe)
----
# perf probe -x ./perf --cache -n --add 'myevent=dso__load $params' ---- Reuse the "myevent" from cache as below. ---- # perf probe -x ./perf %myevent ----
TODO:
Wildcard is not supported yet.
--- tools/perf/Documentation/perf-probe.txt | 3 + tools/perf/util/probe-event.c | 78 ++++++++++++++++++++++--------- tools/perf/util/probe-event.h | 1 tools/perf/util/probe-file.c | 9 ++++ 4 files changed, 69 insertions(+), 22 deletions(-)
tools/perf/Documentation/perf-probe.txt +3 -0
@@ -151,6 +151,8 @@ Probe points are defined by following syntax. 3) Define event based on source file with lazy pattern [[GROUP:]EVENT=]SRC;PTN [ARG ...] + 4) Pre-defined SDT events + %[PROVIDER:]SDTEVENT 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_<bin>' is used for uprobe. Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the
@@ -158,6 +160,7 @@ modules. 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function. It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern. 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT). +'SDTEVENT' and 'PROVIDER' is the pre-defined event name which is defined by user SDT (Statically Defined Tracing) or the pre-cached probes with event name. PROBE ARGUMENT --------------
tools/perf/util/probe-event.c +56 -22
114 lines not on this page · raw message
tools/perf/util/probe-event.h +1 -0
@@ -85,6 +85,7 @@ struct perf_probe_event {char *group;/* Group name */ struct perf_probe_point point;/* Probe point */ int nargs;/* Number of arguments */ +bool sdt;/* SDT/cached event flag */ bool uprobes;/* Uprobe event flag */ char *target;/* Target binary */ struct perf_probe_arg *args;/* Arguments */
tools/perf/util/probe-file.c +9 -0
@@ -529,6 +529,15 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)return NULL ;list_for_each_entry (entry, &pcache->list, list) { +if (pev->sdt) { +if (entry->pev.event && +streql (entry->pev.event, pev->event) && + (!pev->group || +streql (entry->pev.group, pev->group))) + goto found; + +continue ; + }/* Hit if same event name or same command-string */ if ((pev->event && (streql(entry->pev.group, pev->group) &&
PATCH v4 16/19 perf-list: Show SDT and pre-cached events
In reply to Masami HiramatsuFrom: Masami Hiramatsu <[email protected]>
Show SDT and pre-cached events by perf-list with "sdt". This also shows the binary and build-id where the events are placed only when there are same name events on different binaries. e.g.
----
# perf list sdt
List of pre-defined events (to be used in -e):
sdt_libc:lll_futex_wake [SDT event]
sdt_libc:lll_lock_wait_private [SDT event]
sdt_libc:longjmp [SDT event]
sdt_libc:longjmp_target [SDT event]
...
sdt_libstdcxx:rethrow@/usr/bin/gcc(0cc207fc4b27) [SDT event]
sdt_libstdcxx:rethrow@/usr/lib64/libstdc++.so.6.0.20(91c7a88fdf49)
sdt_libstdcxx:throw@/usr/bin/gcc(0cc207fc4b27) [SDT event]
sdt_libstdcxx:throw@/usr/lib64/libstdc++.so.6.0.20(91c7a88fdf49)----
The binary path and build-id are shown in below format;
<GROUP>:<EVENT>@<PATH>(<BUILD-ID>)
---
Changes in v4:
- Update patch description.
- Change event list format.
--- tools/perf/builtin-list.c | 4 ++ tools/perf/util/parse-events.c | 83 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/parse-events.h | 2 + 3 files changed, 89 insertions(+)
tools/perf/builtin-list.c +4 -0
@@ -62,6 +62,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)print_hwcache_events (NULL , raw_dump); else if (strcmp(argv[i], "pmu") == 0) print_pmu_events(NULL, raw_dump); + else if (strcmp(argv[i], "sdt") == 0) + print_sdt_events(NULL, NULL, raw_dump); else if ((sep = strchr(argv[i], ':')) != NULL) {int sep_idx;
@@ -76,6 +78,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) s[sep_idx] ='\0' ;print_tracepoint_events (s, s + sep_idx +1 , raw_dump); +print_sdt_events (s, s + sep_idx +1 , raw_dump);free (s); }else {if (asprintf (&s,"*%s*" , argv[i]) <0 ) {
@@ -89,6 +92,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)print_hwcache_events (s, raw_dump);print_pmu_events (s, raw_dump);print_tracepoint_events (NULL , s, raw_dump); +print_sdt_events (NULL , s, raw_dump);free (s); } }
tools/perf/util/parse-events.c +83 -0
101 lines not on this page · raw message
tools/perf/util/parse-events.h +2 -0
@@ -182,6 +182,8 @@ void print_symbol_events(const char *event_glob, unsigned type,void print_tracepoint_events (const char *subsys_glob,const char *event_glob,bool name_only);int print_hwcache_events (const char *event_glob,bool name_only); +void print_sdt_events (const char *subsys_glob,const char *event_glob, +bool name_only);int is_valid_tracepoint (const char *event_string);int valid_event_mount (const char *eventfs);
PATCH v4 17/19 perf-list: Skip SDTs placed in invalid binaries
In reply to Masami HiramatsuFrom: Masami Hiramatsu <[email protected]>
Skip SDTs placed in invalid (non-exist, or older version) binaries. Note that perf-probe --cache --list and perf-probe --cache --del still handle all the caches including invalid binaries.
---
Changes in v4:
- Rename a parameter 'valid' to 'validonly' :)
--- tools/perf/builtin-probe.c | 2 +- tools/perf/util/build-id.c | 27 ++++++++++++++++++++++++++- tools/perf/util/build-id.h | 2 +- tools/perf/util/parse-events.c | 2 +- tools/perf/util/probe-file.c | 2 +- 5 files changed, 30 insertions(+), 5 deletions(-)
tools/perf/builtin-probe.c +1 -1
@@ -370,7 +370,7 @@ static int del_perf_probe_caches(struct strfilter *filter)struct str_node *nd;int ret; - ret =build_id_cache__list_all (&bidlist); + ret =build_id_cache__list_all (&bidlist, false);if (ret <0 ) {pr_debug ("Failed to get buildids: %d\n" , ret);return ret;
tools/perf/util/build-id.c +26 -1
@@ -184,6 +184,25 @@ out:return ret; } +static bool build_id_cache__valid_id (char *sbuild_id) +{ +char real_sbuild_id[SBUILD_ID_SIZE ] ="" ; +char *pathname; +bool ret; + + pathname =build_id_cache__origname (sbuild_id); +if (!pathname) +return false; + +if (filename__sprintf_build_id (pathname, real_sbuild_id) <0 ) + ret = false; +else + ret = (strcmp (sbuild_id, real_sbuild_id) ==0 ); +free (pathname); + +return ret; +} +static const char *build_id_cache__basename (bool is_kallsyms,bool is_vdso) {return is_kallsyms ?"kallsyms" : (is_vdso ?"vdso" :"elf" );
@@ -394,7 +413,7 @@ void disable_buildid_cache(void) no_buildid_cache = true; } -int build_id_cache__list_all (struct strlist **result) +int build_id_cache__list_all (struct strlist **result,bool validonly) {struct strlist *toplist, *list, *bidlist;struct str_node *nd, *nd2;
@@ -402,6 +421,10 @@ int build_id_cache__list_all(struct strlist **result)char sbuild_id[SBUILD_ID_SIZE ];int ret =0 ; +/* for filename__ functions */ +if (validonly) +symbol__init (NULL ); +/* Open the top-level directory */ if (asprintf (&topdir,"%s/.build-id/" , buildid_dir) <0 )return -errno;
@@ -431,6 +454,8 @@ int build_id_cache__list_all(struct strlist **result) nd->s, nd2->s);continue ; } +if (validonly && !build_id_cache__valid_id (sbuild_id)) +continue ;strlist__add (bidlist, sbuild_id); }strlist__delete (list);
tools/perf/util/build-id.h +1 -1
@@ -32,7 +32,7 @@ char *build_id_cache__origname(const char *sbuild_id);char *build_id_cache__linkname (const char *sbuild_id,char *bf,size_t size);char *build_id_cache__dirname_from_path (const char *sbuild_id,const char *name,bool is_kallsyms,bool is_vdso); -int build_id_cache__list_all (struct strlist **result); +int build_id_cache__list_all (struct strlist **result,bool validonly);int build_id_cache__list_build_ids (const char *pathname,struct strlist **result);bool build_id_cache__cached (const char *sbuild_id);
tools/perf/util/parse-events.c +1 -1
@@ -1994,7 +1994,7 @@ void print_sdt_events(const char *subsys_glob, const char *event_glob,pr_debug ("Failed to allocate new strlist for SDT\n" );return ; } - ret =build_id_cache__list_all (&bidlist); + ret =build_id_cache__list_all (&bidlist, true);if (ret <0 ) {pr_debug ("Failed to get buildids: %d\n" , ret);return ;
tools/perf/util/probe-file.c +1 -1
@@ -770,7 +770,7 @@ int probe_cache__show_all_caches(struct strfilter *filter)pr_debug ("list cache with filter: %s\n" , buf);free (buf); - ret =build_id_cache__list_all (&bidlist); + ret =build_id_cache__list_all (&bidlist, false);if (ret <0 ) {pr_debug ("Failed to get buildids: %d\n" , ret);return ret == -ENOENT ?0 : ret;
PATCH v4 18/19 perf probe: Allow wildcard for cached events
In reply to Masami HiramatsuAllo glob wildcard for reusing cached/SDT events. This also automatically find the target binaries, e.g.
# perf probe -a %sdt_libc:\*
This example adds probes for all SDT in libc.
Note that the SDTs must have been scanned by perf buildid-cache.
--- tools/perf/util/probe-event.c | 153 ++++++++++++++++++++++++++++++++++++++++- tools/perf/util/probe-event.h | 1 tools/perf/util/probe-file.c | 33 ++++++++- tools/perf/util/probe-file.h | 5 + 4 files changed, 183 insertions(+), 9 deletions(-)
tools/perf/util/probe-event.c +148 -5
@@ -236,7 +236,7 @@ static void clear_perf_probe_point(struct perf_probe_point *pp)free (pp->lazy_line); } -static void clear_probe_trace_events (struct probe_trace_event *tevs,int ntevs) +void clear_probe_trace_events (struct probe_trace_event *tevs,int ntevs) {int i;
@@ -1151,7 +1151,7 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev) ptr =strchr (*arg,':' );if (ptr) { *ptr ='\0' ; -if (!is_c_func_name (*arg)) +if (!pev->sdt && !is_c_func_name (*arg)) goto ng_name; pev->group =strdup (*arg);if (!pev->group)
@@ -1159,7 +1159,7 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev) *arg = ptr +1 ; }else pev->group =NULL ; -if (!is_c_func_name (*arg)) { +if (!pev->sdt && !is_c_func_name (*arg)) { ng_name:semantic_error ("%s is bad for event name -it must " "follow C symbol-naming rule.\n" , *arg);
@@ -1585,6 +1585,11 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev) p =strchr (argv[1 ],':' );if (p) { tp->module =strndup (argv[1 ], p - argv[1 ]); +if (!tp->module) { + ret = -ENOMEM ; + goto out; + } + tev->uprobes = (tp->module[0 ] =='/' ); p++; }else p = argv[1 ];
@@ -2430,7 +2435,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,int ret;/* If probe_event or trace_event already have the name, reuse it */ -if (pev->event) +if (pev->event && !pev->sdt) event = pev->event;else if (tev->event) event = tev->event;
@@ -2443,7 +2448,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,else event = tev->point.realname; } -if (pev->group) +if (pev->group && !pev->sdt) group = pev->group;else if (tev->group) group = tev->group;
@@ -2794,6 +2799,137 @@ errout:bool __weak arch__prefers_symtab (void ) {return false; } +/* Concatinate two arrays */ +static void *memcat (void *a,size_t sz_a,void *b,size_t sz_b) +{ +void *ret; + + ret =malloc (sz_a + sz_b); +if (ret) { +memcpy (ret, a, sz_a); +memcpy (ret + sz_a, b, sz_b); + } +return ret; +} + +static int +concat_probe_trace_events (struct probe_trace_event **tevs,int *ntevs, +struct probe_trace_event **tevs2,int ntevs2) +{ +struct probe_trace_event *new_tevs; +int ret =0 ; + +if (ntevs ==0 ) { + *tevs = *tevs2; + *ntevs = ntevs2; + *tevs2 =NULL ; +return 0 ; + } + +if (*ntevs + ntevs2 > probe_conf.max_probes) + ret = -E2BIG ; +else { +/* Concatinate the array of probe_trace_event */ + new_tevs =memcat (*tevs, (*ntevs) *sizeof (**tevs), + *tevs2, ntevs2 *sizeof (**tevs2)); +if (!new_tevs) + ret = -ENOMEM ; +else { +free (*tevs); + *tevs = new_tevs; + *ntevs += ntevs2; + } + } +if (ret <0 ) +clear_probe_trace_events (*tevs2, ntevs2); +zfree (tevs2); + +return ret; +} + +/* Try to find probe_trace_event from given probe caches */ +static int find_cached_events (struct perf_probe_event *pev, +struct probe_trace_event **tevs, +const char *target) +{ +struct probe_cache *cache; +struct probe_cache_entry *entry; +struct probe_trace_event *tmp_tevs =NULL ; +int ntevs =0 ; +int ret =0 ; + + cache =probe_cache__new (target); +if (!cache) +return -ENOENT ; + +for_each_probe_cache_entry (entry, cache) { +/* Skip the cache entry which has no name */ +if (!entry->pev.event || !entry->pev.group) +continue ; +if (strglobmatch (entry->pev.group, pev->group) && +strglobmatch (entry->pev.event, pev->event)) { + ret =probe_cache_entry__get_event (entry, &tmp_tevs); +if (ret >0 ) + ret =concat_probe_trace_events (tevs, &ntevs, + &tmp_tevs, ret); +if (ret <0 ) +break ; + } + } +probe_cache__delete (cache); +if (ret <0 ) { +clear_probe_trace_events (*tevs, ntevs); +zfree (tevs); + }else { + ret = ntevs; +if (target[0 ] =='/' ) + pev->uprobes = true; + } + +return ret; +} + +/* Try to find probe_trace_event from all probe caches */ +static int find_cached_events_all (struct perf_probe_event *pev, +struct probe_trace_event **tevs) +{ +struct probe_trace_event *tmp_tevs =NULL ; +struct strlist *bidlist; +struct str_node *nd; +char *pathname; +int ntevs =0 ; +int ret; + +/* Get the buildid list of all valid caches */ + ret =build_id_cache__list_all (&bidlist, true); +if (ret <0 ) { +pr_debug ("Failed to get buildids: %d\n" , ret); +return ret; + } + + ret =0 ; +strlist__for_each (nd, bidlist) { + pathname =build_id_cache__origname (nd->s); + ret =find_cached_events (pev, &tmp_tevs, pathname); +if (ret >0 ) + ret =concat_probe_trace_events (tevs, &ntevs, + &tmp_tevs, ret); +/* In the case of cnt == 0, we just skip it */ +free (pathname); +if (ret <0 ) +break ; + } +strlist__delete (bidlist); + +if (ret <0 ) { +clear_probe_trace_events (*tevs, ntevs); +zfree (tevs); + }else + ret = ntevs; + +return ret; +} +static int find_probe_trace_events_from_cache (struct perf_probe_event *pev,struct probe_trace_event **tevs) {
@@ -2803,6 +2939,13 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,struct str_node *node;int ret, i; +if (pev->sdt) { +/* For SDT/cached events, we use special search functions */ +if (!pev->target) +return find_cached_events_all (pev, tevs); +else +return find_cached_events (pev, tevs, pev->target); + } cache =probe_cache__new (pev->target);if (!cache)return 0 ;
tools/perf/util/probe-event.h +1 -0
@@ -134,6 +134,7 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);/* Release event contents */ void clear_perf_probe_event (struct perf_probe_event *pev);void clear_probe_trace_event (struct probe_trace_event *tev); +void clear_probe_trace_events (struct probe_trace_event *tevs,int ntevs);/* Command string to line-range */ int parse_line_range_desc (const char *cmd,struct line_range *lr);
tools/perf/util/probe-file.c +29 -4
@@ -360,6 +360,31 @@ probe_cache_entry__new(struct perf_probe_event *pev)return ret; } +int probe_cache_entry__get_event (struct probe_cache_entry *entry, +struct probe_trace_event **tevs) +{ +struct probe_trace_event *tev; +struct str_node *node; +int ret, i; + + ret =strlist__nr_entries (entry->tevlist); +if (ret > probe_conf.max_probes) +return -E2BIG ; + + *tevs =zalloc (ret *sizeof (*tev)); +if (!*tevs) +return -ENOMEM ; + + i =0 ; +strlist__for_each (node, entry->tevlist) { + tev = &(*tevs)[i++]; + ret =parse_probe_trace_command (node->s, tev); +if (ret <0 ) +break ; + } +return i; +} +/* For the kernel probe caches, pass target = NULL */ static int probe_cache__open (struct probe_cache *pcache,const char *target) {
@@ -528,7 +553,7 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)if (!cmd)return NULL ; -list_for_each_entry (entry, &pcache->list, list) { +for_each_probe_cache_entry (entry, pcache) {if (pev->sdt) { if (entry->pev.event && streql(entry->pev.event, pev->event) &&
@@ -558,7 +583,7 @@ probe_cache__find_by_name(struct probe_cache *pcache, {struct probe_cache_entry *entry =NULL ; -list_for_each_entry (entry, &pcache->list, list) { +for_each_probe_cache_entry (entry, pcache) {/* Hit if same event name or same command-string */ if (streql (entry->pev.group, group) &&streql (entry->pev.event, event))
@@ -711,7 +736,7 @@ int probe_cache__commit(struct probe_cache *pcache)if (ret <0 ) goto out; -list_for_each_entry (entry, &pcache->list, list) { +for_each_probe_cache_entry (entry, pcache) { ret =probe_cache_entry__write (entry, pcache->fd);pr_debug ("Cache committed: %d\n" , ret);if (ret <0 )
@@ -750,7 +775,7 @@ static int probe_cache__show_entries(struct probe_cache *pcache, {struct probe_cache_entry *entry; -list_for_each_entry (entry, &pcache->list, list) { +for_each_probe_cache_entry (entry, pcache) {if (probe_cache_entry__compare (entry, filter))printf ("%s\n" , entry->spev); }
tools/perf/util/probe-file.h +5 -0
@@ -32,6 +32,11 @@ struct probe_cache {struct list_head list; }; +int probe_cache_entry__get_event (struct probe_cache_entry *entry, +struct probe_trace_event **tevs); +#define for_each_probe_cache_entry (entry, pcache) \ + list_for_each_entry(entry, &pcache->list, list) +struct probe_cache *probe_cache__new (const char *target); int probe_cache__add_entry(struct probe_cache *pcache, struct perf_probe_event *pev,
Re: [PATCH perf/core v4 18/19] perf probe: Allow wildcard for cached events
Quoted 7 lines · Masami Hiramatsu
Allo glob wildcard for reusing cached/SDT events. This also automatically find the target binaries, e.g.
# perf probe -a %sdt_libc:\*This example adds probes for all SDT in libc.
Note that the SDTs must have been scanned by perf buildid-cache.
There is a segfault after applying this patch :
# perf probe -x /home/hemant/test %marker1 Segmentation fault (core dumped)
The problem is there is no group name with this marker and strglobmatch tries to match entry->pev.group with pev->group (which is NULL).
Quoted 132 lines
Signed-off-by Masami Hiramatsu <[email protected]>--- tools/perf/util/probe-event.c | 153 ++++++++++++++++++++++++++++++++++++++++- tools/perf/util/probe-event.h | 1 tools/perf/util/probe-file.c | 33 ++++++++- tools/perf/util/probe-file.h | 5 + 4 files changed, 183 insertions(+), 9 deletions(-)tools/perf/util/probe-event.c +69
-5@@ -236,7 +236,7 @@ static void clear_perf_probe_point(struct perf_probe_point *pp)free (pp->lazy_line); } -static void clear_probe_trace_events (struct probe_trace_event *tevs,int ntevs) +void clear_probe_trace_events (struct probe_trace_event *tevs,int ntevs) {int i;@@ -1151,7 +1151,7 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev) ptr =strchr (*arg,':' );if (ptr) { *ptr ='\0' ; -if (!is_c_func_name (*arg)) +if (!pev->sdt && !is_c_func_name (*arg)) goto ng_name; pev->group =strdup (*arg);if (!pev->group)@@ -1159,7 +1159,7 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev) *arg = ptr +1 ; }else pev->group =NULL ; -if (!is_c_func_name (*arg)) { +if (!pev->sdt && !is_c_func_name (*arg)) { ng_name:semantic_error ("%s is bad for event name -it must " "follow C symbol-naming rule.\n" , *arg);@@ -1585,6 +1585,11 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev) p =strchr (argv[1 ],':' );if (p) { tp->module =strndup (argv[1 ], p - argv[1 ]); +if (!tp->module) { + ret = -ENOMEM ; + goto out; + } + tev->uprobes = (tp->module[0 ] =='/' ); p++; }else p = argv[1 ];@@ -2430,7 +2435,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,int ret;/* If probe_event or trace_event already have the name, reuse it */ -if (pev->event) +if (pev->event && !pev->sdt) event = pev->event;else if (tev->event) event = tev->event;@@ -2443,7 +2448,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,else event = tev->point.realname; } -if (pev->group) +if (pev->group && !pev->sdt) group = pev->group;else if (tev->group) group = tev->group;@@ -2794,6 +2799,137 @@ errout:bool __weak arch__prefers_symtab (void ) {return false; } +/* Concatinate two arrays */ +static void *memcat (void *a,size_t sz_a,void *b,size_t sz_b) +{ +void *ret; + + ret =malloc (sz_a + sz_b); +if (ret) { +memcpy (ret, a, sz_a); +memcpy (ret + sz_a, b, sz_b); + } +return ret; +} + +static int +concat_probe_trace_events (struct probe_trace_event **tevs,int *ntevs, +struct probe_trace_event **tevs2,int ntevs2) +{ +struct probe_trace_event *new_tevs; +int ret =0 ; + +if (ntevs ==0 ) { + *tevs = *tevs2; + *ntevs = ntevs2; + *tevs2 =NULL ; +return 0 ; + } + +if (*ntevs + ntevs2 > probe_conf.max_probes) + ret = -E2BIG ; +else { +/* Concatinate the array of probe_trace_event */ + new_tevs =memcat (*tevs, (*ntevs) *sizeof (**tevs), + *tevs2, ntevs2 *sizeof (**tevs2)); +if (!new_tevs) + ret = -ENOMEM ; +else { +free (*tevs); + *tevs = new_tevs; + *ntevs += ntevs2; + } + } +if (ret <0 ) +clear_probe_trace_events (*tevs2, ntevs2); +zfree (tevs2); + +return ret; +} + +/* Try to find probe_trace_event from given probe caches */ +static int find_cached_events (struct perf_probe_event *pev, +struct probe_trace_event **tevs, +const char *target) +{ +struct probe_cache *cache; +struct probe_cache_entry *entry; +struct probe_trace_event *tmp_tevs =NULL ; +int ntevs =0 ; +int ret =0 ; +
tools/perf/util/probe-event.c errout: · line 2870
Quoted 10 lines
tools/perf/util/probe-event.c +10
-0+ cache =probe_cache__new (target); +if (!cache) +return -ENOENT ; + +for_each_probe_cache_entry (entry, cache) { +/* Skip the cache entry which has no name */ +if (!entry->pev.event || !entry->pev.group) +continue ; +if (strglobmatch (entry->pev.group, pev->group) && +strglobmatch (entry->pev.event, pev->event)) {
Due to the above issue, we can change the above condition to :
if (strglobmatch(entry->pev.event, pev->event) {
if (!pev->group || (pev->group && strglobmatch(entry->pev.group,
pev->group)))
// Do stuff
}Quoted 180 lines
tools/perf/util/probe-event.c +69
-0+ ret =probe_cache_entry__get_event (entry, &tmp_tevs); +if (ret >0 ) + ret =concat_probe_trace_events (tevs, &ntevs, + &tmp_tevs, ret); +if (ret <0 ) +break ; + } + } +probe_cache__delete (cache); +if (ret <0 ) { +clear_probe_trace_events (*tevs, ntevs); +zfree (tevs); + }else { + ret = ntevs; +if (target[0 ] =='/' ) + pev->uprobes = true; + } + +return ret; +} + +/* Try to find probe_trace_event from all probe caches */ +static int find_cached_events_all (struct perf_probe_event *pev, +struct probe_trace_event **tevs) +{ +struct probe_trace_event *tmp_tevs =NULL ; +struct strlist *bidlist; +struct str_node *nd; +char *pathname; +int ntevs =0 ; +int ret; + +/* Get the buildid list of all valid caches */ + ret =build_id_cache__list_all (&bidlist, true); +if (ret <0 ) { +pr_debug ("Failed to get buildids: %d\n" , ret); +return ret; + } + + ret =0 ; +strlist__for_each (nd, bidlist) { + pathname =build_id_cache__origname (nd->s); + ret =find_cached_events (pev, &tmp_tevs, pathname); +if (ret >0 ) + ret =concat_probe_trace_events (tevs, &ntevs, + &tmp_tevs, ret); +/* In the case of cnt == 0, we just skip it */ +free (pathname); +if (ret <0 ) +break ; + } +strlist__delete (bidlist); + +if (ret <0 ) { +clear_probe_trace_events (*tevs, ntevs); +zfree (tevs); + }else + ret = ntevs; + +return ret; +} +static int find_probe_trace_events_from_cache (struct perf_probe_event *pev,struct probe_trace_event **tevs) {@@ -2803,6 +2939,13 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,struct str_node *node;int ret, i; +if (pev->sdt) { +/* For SDT/cached events, we use special search functions */ +if (!pev->target) +return find_cached_events_all (pev, tevs); +else +return find_cached_events (pev, tevs, pev->target); + } cache =probe_cache__new (pev->target);if (!cache)return 0 ;tools/perf/util/probe-event.h +1
-0@@ -134,6 +134,7 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);/* Release event contents */ void clear_perf_probe_event (struct perf_probe_event *pev);void clear_probe_trace_event (struct probe_trace_event *tev); +void clear_probe_trace_events (struct probe_trace_event *tevs,int ntevs);/* Command string to line-range */ int parse_line_range_desc (const char *cmd,struct line_range *lr);tools/perf/util/probe-file.c +29
-4@@ -360,6 +360,31 @@ probe_cache_entry__new(struct perf_probe_event *pev)return ret; } +int probe_cache_entry__get_event (struct probe_cache_entry *entry, +struct probe_trace_event **tevs) +{ +struct probe_trace_event *tev; +struct str_node *node; +int ret, i; + + ret =strlist__nr_entries (entry->tevlist); +if (ret > probe_conf.max_probes) +return -E2BIG ; + + *tevs =zalloc (ret *sizeof (*tev)); +if (!*tevs) +return -ENOMEM ; + + i =0 ; +strlist__for_each (node, entry->tevlist) { + tev = &(*tevs)[i++]; + ret =parse_probe_trace_command (node->s, tev); +if (ret <0 ) +break ; + } +return i; +} +/* For the kernel probe caches, pass target = NULL */ static int probe_cache__open (struct probe_cache *pcache,const char *target) {@@ -528,7 +553,7 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)if (!cmd)return NULL ; -list_for_each_entry (entry, &pcache->list, list) { +for_each_probe_cache_entry (entry, pcache) {if (pev->sdt) { if (entry->pev.event && streql(entry->pev.event, pev->event) &&@@ -558,7 +583,7 @@ probe_cache__find_by_name(struct probe_cache *pcache, {struct probe_cache_entry *entry =NULL ; -list_for_each_entry (entry, &pcache->list, list) { +for_each_probe_cache_entry (entry, pcache) {/* Hit if same event name or same command-string */ if (streql (entry->pev.group, group) &&streql (entry->pev.event, event))@@ -711,7 +736,7 @@ int probe_cache__commit(struct probe_cache *pcache)if (ret <0 ) goto out; -list_for_each_entry (entry, &pcache->list, list) { +for_each_probe_cache_entry (entry, pcache) { ret =probe_cache_entry__write (entry, pcache->fd);pr_debug ("Cache committed: %d\n" , ret);if (ret <0 )@@ -750,7 +775,7 @@ static int probe_cache__show_entries(struct probe_cache *pcache, {struct probe_cache_entry *entry; -list_for_each_entry (entry, &pcache->list, list) { +for_each_probe_cache_entry (entry, pcache) {if (probe_cache_entry__compare (entry, filter))printf ("%s\n" , entry->spev); }tools/perf/util/probe-file.h +5
-0@@ -32,6 +32,11 @@ struct probe_cache {struct list_head list; }; +int probe_cache_entry__get_event (struct probe_cache_entry *entry, +struct probe_trace_event **tevs); +#define for_each_probe_cache_entry (entry, pcache) \ + list_for_each_entry(entry, &pcache->list, list) +struct probe_cache *probe_cache__new (const char *target); int probe_cache__add_entry(struct probe_cache *pcache, struct perf_probe_event *pev,
Signature · 2 lines
Thanks, Hemant Kumar
Re: [PATCH perf/core v4 18/19] perf probe: Allow wildcard for cached events
Quoted 11 lines · On Wed, 27 Apr 2016 21:04:53 +0530 Hemant Kumar <[email protected]>…
Quoted 7 lines · Masami Hiramatsu
Allo glob wildcard for reusing cached/SDT events. This also automatically find the target binaries, e.g.
# perf probe -a %sdt_libc:\*This example adds probes for all SDT in libc.
Note that the SDTs must have been scanned by perf buildid-cache.
Quoted 8 lines
There is a segfault after applying this patch :
# perf probe -x /home/hemant/test %marker1 Segmentation fault (core dumped)The problem is there is no group name with this marker and strglobmatch tries to match
entry->pev.groupwithpev->group(which is NULL).
Thank you for testing!
[...]
Quoted 23 lines
Quoted 11 lines
tools/perf/util/probe-event.c +11
-0+/* Try to find probe_trace_event from given probe caches */ +static int find_cached_events (struct perf_probe_event *pev, +struct probe_trace_event **tevs, +const char *target) +{ +struct probe_cache *cache; +struct probe_cache_entry *entry; +struct probe_trace_event *tmp_tevs =NULL ; +int ntevs =0 ; +int ret =0 ; +tools/perf/util/probe-event.c errout: · line 2870
Quoted 10 lines
tools/perf/util/probe-event.c +10
-0+ cache =probe_cache__new (target); +if (!cache) +return -ENOENT ; + +for_each_probe_cache_entry (entry, cache) { +/* Skip the cache entry which has no name */ +if (!entry->pev.event || !entry->pev.group) +continue ; +if (strglobmatch (entry->pev.group, pev->group) && +strglobmatch (entry->pev.event, pev->event)) {Due to the above issue, we can change the above condition to :
Quoted 5 lines
if (strglobmatch(entry->pev.event, pev->event) {
if (!pev->group || (pev->group && strglobmatch(entry->pev.group,
pev->group)))
// Do stuff
}OK, I'll fix that.
thanks!!
Signature · 1 line
Masami Hiramatsu <[email protected]>
PATCH v4 19/19 perf probe: Support @BUILDID or @FILE suffix for SDT events
In reply to Masami HiramatsuSupport @BUILDID or @FILE suffix for SDT events. This allows perf to add probes on SDTs/pre-cached events on given FILE or the file which has given BUILDID (also, this complements BUILDID.)
For example, both gcc and libstdc++ has same SDTs as below. If you would like to add a probe on sdt_libstdcxx:catch on gcc, you can do as below.
----
# perf list sdt | tail -n 6
sdt_libstdcxx:catch@/usr/bin/gcc(0cc207fc4b27) [SDT event]
sdt_libstdcxx:catch@/usr/lib64/libstdc++.so.6.0.20(91c7a88fdf49)
sdt_libstdcxx:rethrow@/usr/bin/gcc(0cc207fc4b27) [SDT event]
sdt_libstdcxx:rethrow@/usr/lib64/libstdc++.so.6.0.20(91c7a88fdf49)
sdt_libstdcxx:throw@/usr/bin/gcc(0cc207fc4b27) [SDT event]
sdt_libstdcxx:throw@/usr/lib64/libstdc++.so.6.0.20(91c7a88fdf49)
# perf probe -a sdt_libstdcxx:catch@0cc
Added new event:
sdt_libstdcxx:catch (on %catch in /usr/bin/gcc)You can now use it in all perf tools, such as:
perf record -e sdt_libstdcxx:catch -aR sleep 1
----
--- tools/perf/util/build-id.c | 40 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/build-id.h | 1 + tools/perf/util/probe-event.c | 17 +++++++++++++++-- 3 files changed, 56 insertions(+), 2 deletions(-)
tools/perf/util/build-id.c +40 -0
@@ -472,6 +472,46 @@ out:return ret; } +static bool str_is_build_id (const char *maybe_sbuild_id,size_t len) +{ +size_t i; + +for (i =0 ; i < len; i++) { +if (!isxdigit (maybe_sbuild_id[i])) +return false; + } +return true; +} + +/* Return the valid complete build-id */ +char *build_id_cache__complement (const char *incomplete_sbuild_id) +{ +struct strlist *list; +struct str_node *nd, *cand =NULL ; +char *sbuild_id =NULL ; +size_t len =strlen (incomplete_sbuild_id); + +if (len >=SBUILD_ID_SIZE || + !str_is_build_id (incomplete_sbuild_id, len) || +build_id_cache__list_all (&list, true) <0 ) +return NULL ; + +strlist__for_each (nd, list) { +if (strncmp (nd->s, incomplete_sbuild_id, len) !=0 ) +continue ; +if (cand) {/* Error: There are more than 2 candidates. */ + cand =NULL ; +break ; + } + cand = nd; + } +if (cand) + sbuild_id =strdup (cand->s); +strlist__delete (list); + +return sbuild_id; +} +char *build_id_cache__dirname_from_path (const char *sbuild_id,const char *name,bool is_kallsyms,bool is_vdso) {
tools/perf/util/build-id.h +1 -0
@@ -33,6 +33,7 @@ char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);char *build_id_cache__dirname_from_path (const char *sbuild_id,const char *name,bool is_kallsyms,bool is_vdso);int build_id_cache__list_all (struct strlist **result,bool validonly); +char *build_id_cache__complement (const char *incomplete_sbuild_id);int build_id_cache__list_build_ids (const char *pathname,struct strlist **result);bool build_id_cache__cached (const char *sbuild_id);
tools/perf/util/probe-event.c +15 -2
@@ -1198,8 +1198,21 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) ptr =strpbrk (arg,";=@+%" );if (pev->sdt) {if (ptr) { -semantic_error ("%s must contain only an SDT event name.\n" , arg); -return -EINVAL ; +if (*ptr !='@' ) { +semantic_error ("%s must contain only an SDT event name.\n" , arg); +return -EINVAL ; + } +/* This must be a target file name or build id */ + tmp =build_id_cache__complement (ptr +1 ); +if (tmp) { + pev->target =build_id_cache__origname (tmp); +free (tmp); + }else + pev->target =strdup (ptr +1 ); +if (!pev->target) +return -ENOMEM ; + pev->uprobes =1 ; + *ptr ='\0' ; } ret =parse_perf_probe_event_name (&arg, pev);if (ret ==0 ) {
Hi Masami,
Quoted 4 lines · Masami Hiramatsu
Hi,
Here is the 4th version of the patchset for probe-cache and initial SDT support which are going to be perf-cache finally.
Applied your patches and tested them. I have a few questions/ suggestions on some of the patches.
Quoted 78 lines
The previous version is here; https://lkml.org/lkml/2015/8/15/52
This version fixes some bugs and improve wildcard support ( including automatic target binary selection, we don't need -x option for SDT/pre-cached events any more :) ), and drops perf-record support currently because it seems more work on cleanup side.
BTW, since I couldn't find
list_dirfunction in Arnaldo's mail, so this series still have a patch to addlsdir().Note that all SDT events have "
sdt_" prefix on the provider name, because of easier to distinguish between other named caches.TODOs:
- (perf record) Support SDT event recording directly
- (perf record) Support @FILE/@BUILDID suffix to record specific SDTs.
- (perf record) Try to unregister SDT events after record.
- (ftrace) Support multiple SDTs on single event.Done:
- (perf probe) Allow glob matching for pre-cached events.
- (perf probe) Removes -x option when using pre-cached events.
- (perf probe) Support @FILE/@BUILDID suffix for pre-cached events.
- (perf buildid-cache) Fallback to old style buildid-cache.Thank you,
---
Hemant Kumar (1):
perf/sdt: ELF support for SDTMasami Hiramatsu (18):
perf probe: Use strbuf for making strings
perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid perf buildid-cache: Fall back to the old style build-id cache
perf: Add lsdir to read a directory
perf-buildid-cache: Use lsdir for looking up buildid caches
perf-probe: Letprobe_file__add_eventreturn 0 if succeeded
perf probe: Add --cache option to cache the probe definitions perf probe: Use cache entry if possible
perf probe: Show all cached probes
perf probe: Remove caches when --cache is given
perf probe: Add group name support
perf-probe: Set default kprobe group name if it is not given perf buildid-cache: Scan and import user SDT events to probe cache perf probe: Accept %sdt and %cached event name
perf-list: Show SDT and pre-cached events
perf-list: Skip SDTs placed in invalid binaries
perf probe: Allow wildcard for cached events
perf probe: Support @BUILDID or @FILE suffix for SDT eventstools/perf/Documentation/perf-probe.txt | 24 + tools/perf/builtin-list.c | 4 tools/perf/builtin-probe.c | 30 + tools/perf/util/build-id.c | 278 ++++++++++-- tools/perf/util/build-id.h | 6 tools/perf/util/dso.h | 5 tools/perf/util/parse-events.c | 83 ++++ tools/perf/util/parse-events.h | 2 tools/perf/util/probe-event.c | 692 ++++++++++++++++++++++--------- tools/perf/util/probe-event.h | 9 tools/perf/util/probe-file.c | 495 ++++++++++++++++++++++ tools/perf/util/probe-file.h | 32 + tools/perf/util/probe-finder.c | 14 - tools/perf/util/symbol-elf.c | 252 +++++++++++ tools/perf/util/symbol.c | 15 - tools/perf/util/symbol.h | 22 + tools/perf/util/util.c | 34 ++ tools/perf/util/util.h | 4 18 files changed, 1725 insertions(+), 276 deletions(-)--
Masami Hiramatsu
Signature · 2 lines
Thanks, Hemant Kumar