From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751326AbcGMTg3 (ORCPT ); Wed, 13 Jul 2016 15:36:29 -0400 Received: from mail.kernel.org ([198.145.29.136]:56692 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751123AbcGMTgY (ORCPT ); Wed, 13 Jul 2016 15:36:24 -0400 Date: Wed, 13 Jul 2016 16:36:14 -0300 From: Arnaldo Carvalho de Melo To: Masami Hiramatsu Cc: linux-kernel@vger.kernel.org, Namhyung Kim , Peter Zijlstra , Ingo Molnar , Hemant Kumar , Ananth N Mavinakayanahalli , Brendan Gregg Subject: Re: [PATCH perf/core 05/10] perf probe: Allow wildcard for cached events Message-ID: <20160713193614.GG27879@kernel.org> References: <146831786245.17065.7237942149862581005.stgit@devbox> <146831791813.17065.17846564230840594888.stgit@devbox> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <146831791813.17065.17846564230840594888.stgit@devbox> X-Url: http://acmel.wordpress.com User-Agent: Mutt/1.6.1 (2016-04-27) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Em Tue, Jul 12, 2016 at 07:05:18PM +0900, Masami Hiramatsu escreveu: > Allo glob wildcard for reusing cached/SDT events. E.g. > > # perf probe -x /usr/lib64/libc-2.20.so -a %sdt_libc:\* The example message for this could be improved to also use a wildcard :-) > This example adds probes for all SDT in libc. > Note that the SDTs must have been scanned by perf buildid-cache. > > Signed-off-by: Masami Hiramatsu > --- > Changes in v12: > - Rename strlist__for_each to strlist__for_each_entry. > Changes in v10: > - Split off bugfix, adding interface, and target search patches. > - Do not export clear_probe_trace_events(). > Changes in v7: > - Continue to search caches if a build-id cache has no probe cache. > - Make probe_cache__open() to accept DSO__NAME_KALLSYMS for kernel. > - Fix to add probes correctly when a wildcard matchs both of > uprobes and kprobes. > Changes in v5.1: > - Fix a SEGV bug when a group name is omitted. (Thanks Hemant!) > --- > tools/perf/util/probe-event.c | 107 +++++++++++++++++++++++++++++++++++++++-- > tools/perf/util/probe-file.c | 38 ++++++++++++--- > tools/perf/util/probe-file.h | 3 + > 3 files changed, 138 insertions(+), 10 deletions(-) > > diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c > index 3642cca..1aeac09 100644 > --- a/tools/perf/util/probe-event.c > +++ b/tools/perf/util/probe-event.c > @@ -1204,7 +1204,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) > @@ -1212,7 +1212,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); > @@ -1644,6 +1644,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev) > ret = -ENOMEM; > goto out; > } > + tev->uprobes = (tp->module[0] == '/'); > p++; > } else > p = argv[1]; > @@ -2518,7 +2519,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; > @@ -2531,7 +2532,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; > @@ -2894,6 +2895,100 @@ 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. Return the number > + * of cached events found, if an error occurs return the error. > + */ > +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); > + /* Return 0 ("not found") if the target has no probe cache. */ > + if (!cache) > + return 0; > + > + for_each_probe_cache_entry(entry, cache) { > + /* Skip the cache entry which has no name */ > + if (!entry->pev.event || !entry->pev.group) > + continue; > + if ((!pev->group || 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 (ntevs > 0 && target && target[0] == '/') > + pev->uprobes = true; > + } > + > + return ret; > +} > + > static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, > struct probe_trace_event **tevs) > { > @@ -2903,6 +2998,10 @@ 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 */ > + return find_cached_events(pev, tevs, pev->target); > + > cache = probe_cache__new(pev->target); > if (!cache) > return 0; > diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c > index 9152ad2..78a84f5 100644 > --- a/tools/perf/util/probe-file.c > +++ b/tools/perf/util/probe-file.c > @@ -362,13 +362,38 @@ probe_cache_entry__new(struct perf_probe_event *pev) > return entry; > } > > -/* For the kernel probe caches, pass target = NULL */ > +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_entry(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 or DSO__NAME_KALLSYMS */ > static int probe_cache__open(struct probe_cache *pcache, const char *target) > { > char cpath[PATH_MAX]; > char sbuildid[SBUILD_ID_SIZE]; > char *dir_name = NULL; > - bool is_kallsyms = !target; > + bool is_kallsyms = false; > int ret, fd; > > if (target && build_id_cache__cached(target)) { > @@ -378,12 +403,13 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) > goto found; > } > > - if (target) > - ret = filename__sprintf_build_id(target, sbuildid); > - else { > + if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) { > target = DSO__NAME_KALLSYMS; > + is_kallsyms = true; > ret = sysfs__sprintf_build_id("/", sbuildid); > - } > + } else > + ret = filename__sprintf_build_id(target, sbuildid); > + > if (ret < 0) { > pr_debug("Failed to get build-id from %s.\n", target); > return ret; > diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h > index d513b34..cafbe1d 100644 > --- a/tools/perf/util/probe-file.h > +++ b/tools/perf/util/probe-file.h > @@ -34,6 +34,9 @@ int probe_file__get_events(int fd, struct strfilter *filter, > struct strlist *plist); > int probe_file__del_strlist(int fd, struct strlist *namelist); > > +int probe_cache_entry__get_event(struct probe_cache_entry *entry, > + struct probe_trace_event **tevs); > + > struct probe_cache *probe_cache__new(const char *target); > int probe_cache__add_entry(struct probe_cache *pcache, > struct perf_probe_event *pev,