perf probe: Search SDT/cached event from all probe caches
authorMasami Hiramatsu <mhiramat@kernel.org>
Tue, 12 Jul 2016 10:05:28 +0000 (19:05 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 14 Jul 2016 02:09:07 +0000 (23:09 -0300)
Search SDT/cached event from all probe caches if user doesn't pass any
binary. With this, we don't have to specify target binary for SDT and
named cached events (which start with %).

E.g. without this, a target binary must be passed with -x.

  # perf probe -x /usr/lib64/libc-2.20.so -a %sdt_libc:\*

With this change, we don't need it anymore.

  # perf probe -a %sdt_libc:\*

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/146831792812.17065.2353705982669445313.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/probe-event.c

index 7b96e687568eedcb25ec098f247ad2d6a9c7f647..c63e3b8704fe96f3d3de2ade6157cec1607bba9a 100644 (file)
@@ -2557,41 +2557,60 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,
        return 0;
 }
 
-static int __add_probe_trace_events(struct perf_probe_event *pev,
-                                    struct probe_trace_event *tevs,
-                                    int ntevs, bool allow_suffix)
+static int __open_probe_file_and_namelist(bool uprobe,
+                                         struct strlist **namelist)
 {
-       int i, fd, ret;
-       struct probe_trace_event *tev = NULL;
-       struct probe_cache *cache = NULL;
-       struct strlist *namelist;
+       int fd;
 
-       fd = probe_file__open(PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0));
+       fd = probe_file__open(PF_FL_RW | (uprobe ? PF_FL_UPROBE : 0));
        if (fd < 0)
                return fd;
 
        /* Get current event names */
-       namelist = probe_file__get_namelist(fd);
-       if (!namelist) {
+       *namelist = probe_file__get_namelist(fd);
+       if (!(*namelist)) {
                pr_debug("Failed to get current event list.\n");
-               ret = -ENOMEM;
-               goto close_out;
+               close(fd);
+               return -ENOMEM;
        }
+       return fd;
+}
+
+static int __add_probe_trace_events(struct perf_probe_event *pev,
+                                    struct probe_trace_event *tevs,
+                                    int ntevs, bool allow_suffix)
+{
+       int i, fd[2] = {-1, -1}, up, ret;
+       struct probe_trace_event *tev = NULL;
+       struct probe_cache *cache = NULL;
+       struct strlist *namelist[2] = {NULL, NULL};
+
+       up = pev->uprobes ? 1 : 0;
+       fd[up] = __open_probe_file_and_namelist(up, &namelist[up]);
+       if (fd[up] < 0)
+               return fd[up];
 
        ret = 0;
        for (i = 0; i < ntevs; i++) {
                tev = &tevs[i];
+               up = tev->uprobes ? 1 : 0;
+               if (fd[up] == -1) {     /* Open the kprobe/uprobe_events */
+                       fd[up] = __open_probe_file_and_namelist(up,
+                                                               &namelist[up]);
+                       if (fd[up] < 0)
+                               goto close_out;
+               }
                /* Skip if the symbol is out of .text or blacklisted */
                if (!tev->point.symbol && !pev->uprobes)
                        continue;
 
                /* Set new name for tev (and update namelist) */
-               ret = probe_trace_event__set_name(tev, pev, namelist,
+               ret = probe_trace_event__set_name(tev, pev, namelist[up],
                                                  allow_suffix);
                if (ret < 0)
                        break;
 
-               ret = probe_file__add_event(fd, tev);
+               ret = probe_file__add_event(fd[up], tev);
                if (ret < 0)
                        break;
 
@@ -2614,9 +2633,12 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
                probe_cache__delete(cache);
        }
 
-       strlist__delete(namelist);
 close_out:
-       close(fd);
+       for (up = 0; up < 2; up++) {
+               strlist__delete(namelist[up]);
+               if (fd[up] >= 0)
+                       close(fd[up]);
+       }
        return ret;
 }
 
@@ -2989,6 +3011,48 @@ static int find_cached_events(struct perf_probe_event *pev,
        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 */
+       bidlist = build_id_cache__list_all(true);
+       if (!bidlist) {
+               ret = -errno;
+               pr_debug("Failed to get buildids: %d\n", ret);
+               return ret;
+       }
+
+       ret = 0;
+       strlist__for_each_entry(nd, bidlist) {
+               pathname = build_id_cache__origname(nd->s);
+               ret = find_cached_events(pev, &tmp_tevs, pathname);
+               /* In the case of cnt == 0, we just skip it */
+               if (ret > 0)
+                       ret = concat_probe_trace_events(tevs, &ntevs,
+                                                       &tmp_tevs, ret);
+               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)
 {
@@ -2998,10 +3062,13 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
        struct str_node *node;
        int ret, i;
 
-       if (pev->sdt)
+       if (pev->sdt) {
                /* For SDT/cached events, we use special search functions */
-               return find_cached_events(pev, tevs, pev->target);
-
+               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;