perf probe: Accept %sdt and %cached event name
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Tue, 12 Jul 2016 10:04:43 +0000 (19:04 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 14 Jul 2016 02:09:05 +0000 (23:09 -0300)
To improve 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
  ----

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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/146831788372.17065.3645054540325909346.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/Documentation/perf-probe.txt
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h
tools/perf/util/probe-file.c

index 7a258e9532527adbac74cef6478d465107097747..39e387042098d4c70a1ea2c6555784e6839ffaff 100644 (file)
@@ -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 or cached event with name
+     %[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,11 @@ 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.
+Note that before using the SDT event, the target binary (on which SDT events are defined) must be scanned by linkperf:perf-buildid-cache[1] to make SDT events as cached events.
+
+For details of the SDT, see below.
+https://sourceware.org/gdb/onlinedocs/gdb/Static-Probe-Points.html
 
 PROBE ARGUMENT
 --------------
@@ -237,4 +244,4 @@ Add probes at malloc() function on libc
 
 SEE ALSO
 --------
-linkperf:perf-trace[1], linkperf:perf-record[1]
+linkperf:perf-trace[1], linkperf:perf-record[1], linkperf:perf-buildid-cache[1]
index fef9768df4290e049278752526b358dde586df8e..85f25d41cf8dd8f03febeb11cde9b84145211317 100644 (file)
@@ -1197,6 +1197,34 @@ err:
        return err;
 }
 
+static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev)
+{
+       char *ptr;
+
+       ptr = strchr(*arg, ':');
+       if (ptr) {
+               *ptr = '\0';
+               if (!is_c_func_name(*arg))
+                       goto ng_name;
+               pev->group = strdup(*arg);
+               if (!pev->group)
+                       return -ENOMEM;
+               *arg = ptr + 1;
+       } else
+               pev->group = NULL;
+       if (!is_c_func_name(*arg)) {
+ng_name:
+               semantic_error("%s is bad for event name -it must "
+                              "follow C symbol-naming rule.\n", *arg);
+               return -EINVAL;
+       }
+       pev->event = strdup(*arg);
+       if (pev->event == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+
 /* Parse probepoint definition. */
 static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 {
@@ -1204,38 +1232,43 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
        char *ptr, *tmp;
        char c, nc = 0;
        bool file_spec = false;
+       int ret;
+
        /*
         * <Syntax>
         * perf probe [GRP:][EVENT=]SRC[:LN|;PTN]
         * perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
+        * perf probe %[GRP:]SDT_EVENT
         */
        if (!arg)
                return -EINVAL;
 
+       if (arg[0] == '%') {
+               pev->sdt = true;
+               arg++;
+       }
+
        ptr = strpbrk(arg, ";=@+%");
-       if (ptr && *ptr == '=') {       /* Event name */
-               *ptr = '\0';
-               tmp = ptr + 1;
-               ptr = strchr(arg, ':');
+       if (pev->sdt) {
                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);
+                       semantic_error("%s must contain only an SDT event name.\n", arg);
                        return -EINVAL;
                }
-               pev->event = strdup(arg);
-               if (pev->event == NULL)
-                       return -ENOMEM;
+               ret = parse_perf_probe_event_name(&arg, pev);
+               if (ret == 0) {
+                       if (asprintf(&pev->point.function, "%%%s", pev->event) < 0)
+                               ret = -errno;
+               }
+               return ret;
+       }
+
+       if (ptr && *ptr == '=') {       /* Event name */
+               *ptr = '\0';
+               tmp = ptr + 1;
+               ret = parse_perf_probe_event_name(&arg, pev);
+               if (ret < 0)
+                       return ret;
+
                arg = tmp;
        }
 
@@ -2876,7 +2909,8 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
 
        entry = probe_cache__find(cache, pev);
        if (!entry) {
-               ret = 0;
+               /* SDT must be in the cache */
+               ret = pev->sdt ? -ENOENT : 0;
                goto out;
        }
 
@@ -2915,7 +2949,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 {
        int ret;
 
-       if (!pev->group) {
+       if (!pev->group && !pev->sdt) {
                /* Set group name if not given */
                if (!pev->uprobes) {
                        pev->group = strdup(PERFPROBE_GROUP);
@@ -2934,8 +2968,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 
        /* 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 (ret > 0 || pev->sdt)        /* SDT can be found only in the cache */
+               return ret == 0 ? -ENOENT : ret; /* Found in probe cache */
 
        if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) {
                ret = find_probe_trace_events_from_map(pev, tevs);
index 432b690d3f177ae73de222b390e472218ea296be..e18ea9fe63857cb7a9b382dac563fd2c8cdfbd85 100644 (file)
@@ -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 */
index e705a742ee1ed8e8b1814b3b093f46dfa64713b8..fc16b172579f0a239d17f09d122f4e7a75d10d77 100644 (file)
@@ -547,6 +547,15 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
                return NULL;
 
        list_for_each_entry(entry, &pcache->entries, node) {
+               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) &&