From: Masami Hiramatsu <masami.hiramatsu...@hitachi.com>

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
  ----

Signed-off-by: Masami Hiramatsu <masami.hiramatsu...@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhira...@kernel.org>
---
 Changes in v10:
  - Update Documentation/perf-probe.txt to add a link about SDT.
 Changes in v7:
  - Fix a bug to return an error if no SDT/cached events found in cache.
---
 tools/perf/Documentation/perf-probe.txt |    9 +++
 tools/perf/util/probe-event.c           |   82 ++++++++++++++++++++++---------
 tools/perf/util/probe-event.h           |    1 
 tools/perf/util/probe-file.c            |    9 +++
 4 files changed, 76 insertions(+), 25 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt 
b/tools/perf/Documentation/perf-probe.txt
index 7a258e9..39e3870 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -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]
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index ed50f15..4aa2cf7 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1199,6 +1199,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)
 {
@@ -1206,38 +1234,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);
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 432b690..e18ea9f 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -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 */
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 0f544bd..0e22ef7 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -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) &&

Reply via email to