Commit 36a009fe authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Arnaldo Carvalho de Melo

perf probe: Accept %sdt and %cached event name

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: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Tested-by: default avatarArnaldo 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@devboxSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent f6eb0518
...@@ -151,6 +151,8 @@ Probe points are defined by following syntax. ...@@ -151,6 +151,8 @@ Probe points are defined by following syntax.
3) Define event based on source file with lazy pattern 3) Define event based on source file with lazy pattern
[[GROUP:]EVENT=]SRC;PTN [ARG ...] [[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. '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 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. ...@@ -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. '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. 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). '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 PROBE ARGUMENT
-------------- --------------
...@@ -237,4 +244,4 @@ Add probes at malloc() function on libc ...@@ -237,4 +244,4 @@ Add probes at malloc() function on libc
SEE ALSO SEE ALSO
-------- --------
linkperf:perf-trace[1], linkperf:perf-record[1] linkperf:perf-trace[1], linkperf:perf-record[1], linkperf:perf-buildid-cache[1]
...@@ -1197,6 +1197,34 @@ int parse_line_range_desc(const char *arg, struct line_range *lr) ...@@ -1197,6 +1197,34 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
return 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. */ /* Parse probepoint definition. */
static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) 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) ...@@ -1204,38 +1232,43 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
char *ptr, *tmp; char *ptr, *tmp;
char c, nc = 0; char c, nc = 0;
bool file_spec = false; bool file_spec = false;
int ret;
/* /*
* <Syntax> * <Syntax>
* perf probe [GRP:][EVENT=]SRC[:LN|;PTN] * perf probe [GRP:][EVENT=]SRC[:LN|;PTN]
* perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] * perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
* perf probe %[GRP:]SDT_EVENT
*/ */
if (!arg) if (!arg)
return -EINVAL; return -EINVAL;
if (arg[0] == '%') {
pev->sdt = true;
arg++;
}
ptr = strpbrk(arg, ";=@+%"); ptr = strpbrk(arg, ";=@+%");
if (ptr && *ptr == '=') { /* Event name */ if (pev->sdt) {
*ptr = '\0';
tmp = ptr + 1;
ptr = strchr(arg, ':');
if (ptr) { if (ptr) {
*ptr = '\0'; semantic_error("%s must contain only an SDT event name.\n", arg);
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; return -EINVAL;
} }
pev->event = strdup(arg); ret = parse_perf_probe_event_name(&arg, pev);
if (pev->event == NULL) if (ret == 0) {
return -ENOMEM; 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; arg = tmp;
} }
...@@ -2876,7 +2909,8 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, ...@@ -2876,7 +2909,8 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
entry = probe_cache__find(cache, pev); entry = probe_cache__find(cache, pev);
if (!entry) { if (!entry) {
ret = 0; /* SDT must be in the cache */
ret = pev->sdt ? -ENOENT : 0;
goto out; goto out;
} }
...@@ -2915,7 +2949,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, ...@@ -2915,7 +2949,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
{ {
int ret; int ret;
if (!pev->group) { if (!pev->group && !pev->sdt) {
/* Set group name if not given */ /* Set group name if not given */
if (!pev->uprobes) { if (!pev->uprobes) {
pev->group = strdup(PERFPROBE_GROUP); pev->group = strdup(PERFPROBE_GROUP);
...@@ -2934,8 +2968,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, ...@@ -2934,8 +2968,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
/* At first, we need to lookup cache entry */ /* At first, we need to lookup cache entry */
ret = find_probe_trace_events_from_cache(pev, tevs); ret = find_probe_trace_events_from_cache(pev, tevs);
if (ret > 0) if (ret > 0 || pev->sdt) /* SDT can be found only in the cache */
return ret; /* Found in probe cache */ return ret == 0 ? -ENOENT : ret; /* Found in probe cache */
if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) { if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) {
ret = find_probe_trace_events_from_map(pev, tevs); ret = find_probe_trace_events_from_map(pev, tevs);
......
...@@ -85,6 +85,7 @@ struct perf_probe_event { ...@@ -85,6 +85,7 @@ struct perf_probe_event {
char *group; /* Group name */ char *group; /* Group name */
struct perf_probe_point point; /* Probe point */ struct perf_probe_point point; /* Probe point */
int nargs; /* Number of arguments */ int nargs; /* Number of arguments */
bool sdt; /* SDT/cached event flag */
bool uprobes; /* Uprobe event flag */ bool uprobes; /* Uprobe event flag */
char *target; /* Target binary */ char *target; /* Target binary */
struct perf_probe_arg *args; /* Arguments */ struct perf_probe_arg *args; /* Arguments */
......
...@@ -547,6 +547,15 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev) ...@@ -547,6 +547,15 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
return NULL; return NULL;
list_for_each_entry(entry, &pcache->entries, node) { 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 */ /* Hit if same event name or same command-string */
if ((pev->event && if ((pev->event &&
(streql(entry->pev.group, pev->group) && (streql(entry->pev.group, pev->group) &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment