This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[tip:perf/core] perf probe: Add --list option for listing current probe events
- From: tip-bot for Masami Hiramatsu <mhiramat at redhat dot com>
- To: linux-tip-commits at vger dot kernel dot org
- Cc: acme at redhat dot com, mingo at redhat dot com, peterz at infradead dot org, fweisbec at gmail dot com, dle-develop at lists dot sourceforge dot net, rostedt at goodmis dot org, jbaron at redhat dot com, tglx at linutronix dot de, mhiramat at redhat dot com, systemtap at sources dot redhat dot com, linux-kernel at vger dot kernel dot org, hpa at zytor dot com, fche at redhat dot com, jkenisto at us dot ibm dot com, hch at infradead dot org, ananth at in dot ibm dot com, srikar at linux dot vnet dot ibm dot com, mingo at elte dot hu, prasad at linux dot vnet dot ibm dot com
- Date: Tue, 1 Dec 2009 07:32:57 GMT
- Subject: [tip:perf/core] perf probe: Add --list option for listing current probe events
- Git-commit-id: 4de189fe6e5ad8241f6f8709d2e2ba4c3aeae33a
- References: <20091201002017.10235.76575.stgit@harusame>
- Reply-to: mingo at redhat dot com, acme at redhat dot com, peterz at infradead dot org, fweisbec at gmail dot com, dle-develop at lists dot sourceforge dot net, rostedt at goodmis dot org, jbaron at redhat dot com, tglx at linutronix dot de, mhiramat at redhat dot com, systemtap at sources dot redhat dot com, linux-kernel at vger dot kernel dot org, hpa at zytor dot com, fche at redhat dot com, jkenisto at us dot ibm dot com, hch at infradead dot org, ananth at in dot ibm dot com, srikar at linux dot vnet dot ibm dot com, prasad at linux dot vnet dot ibm dot com, mingo at elte dot hu
Commit-ID: 4de189fe6e5ad8241f6f8709d2e2ba4c3aeae33a
Gitweb: http://git.kernel.org/tip/4de189fe6e5ad8241f6f8709d2e2ba4c3aeae33a
Author: Masami Hiramatsu <mhiramat@redhat.com>
AuthorDate: Mon, 30 Nov 2009 19:20:17 -0500
Committer: Ingo Molnar <mingo@elte.hu>
CommitDate: Tue, 1 Dec 2009 08:20:02 +0100
perf probe: Add --list option for listing current probe events
Add --list option for listing currently defined probe events
in the kernel. This shows events in below format;
[group:event] <perf-probe probe-definition>
for example:
[probe:schedule_0] schedule+30 cpu
Note that source file/line information is not supported yet.
So even if you added a probe by line, it will be shown in
<symbol+offset>.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Jim Keniston <jkenisto@us.ibm.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Frank Ch. Eigler <fche@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jason Baron <jbaron@redhat.com>
Cc: K.Prasad <prasad@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20091201002017.10235.76575.stgit@harusame>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
tools/perf/builtin-probe.c | 12 ++-
tools/perf/util/probe-event.c | 231 ++++++++++++++++++++++++++++++++++++++---
tools/perf/util/probe-event.h | 5 +
3 files changed, 230 insertions(+), 18 deletions(-)
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index bf20df2..b5d15cf 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -62,6 +62,8 @@ static struct {
struct probe_point probes[MAX_PROBES];
} session;
+static bool listing;
+
/* Parse an event definition. Note that any error must die. */
static void parse_probe_event(const char *str)
{
@@ -119,6 +121,7 @@ static int open_default_vmlinux(void)
static const char * const probe_usage[] = {
"perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
"perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
+ "perf probe --list",
NULL
};
@@ -129,6 +132,7 @@ static const struct option options[] = {
OPT_STRING('k', "vmlinux", &session.vmlinux, "file",
"vmlinux/module pathname"),
#endif
+ OPT_BOOLEAN('l', "list", &listing, "list up current probes"),
OPT_CALLBACK('a', "add", NULL,
#ifdef NO_LIBDWARF
"FUNC[+OFFS|%return] [ARG ...]",
@@ -164,9 +168,15 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
for (i = 0; i < argc; i++)
parse_probe_event(argv[i]);
- if (session.nr_probe == 0)
+ if ((session.nr_probe == 0 && !listing) ||
+ (session.nr_probe != 0 && listing))
usage_with_options(probe_usage, options);
+ if (listing) {
+ show_perf_probe_events();
+ return 0;
+ }
+
if (session.need_dwarf)
#ifdef NO_LIBDWARF
die("Debuginfo-analysis is not supported");
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index e3a683a..7f4f288 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -29,10 +29,13 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
#undef _GNU_SOURCE
#include "event.h"
#include "string.h"
+#include "strlist.h"
#include "debug.h"
#include "parse-events.h" /* For debugfs_path */
#include "probe-event.h"
@@ -43,6 +46,19 @@
#define semantic_error(msg ...) die("Semantic error :" msg)
+/* If there is no space to write, returns -E2BIG. */
+static int e_snprintf(char *str, size_t size, const char *format, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, format);
+ ret = vsnprintf(str, size, format, ap);
+ va_end(ap);
+ if (ret >= (int)size)
+ ret = -E2BIG;
+ return ret;
+}
+
/* Parse probepoint definition. */
static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
{
@@ -166,6 +182,103 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
return need_dwarf;
}
+/* Parse kprobe_events event into struct probe_point */
+void parse_trace_kprobe_event(const char *str, char **group, char **event,
+ struct probe_point *pp)
+{
+ char pr;
+ char *p;
+ int ret, i, argc;
+ char **argv;
+
+ pr_debug("Parsing kprobe_events: %s\n", str);
+ argv = argv_split(str, &argc);
+ if (!argv)
+ die("argv_split failed.");
+ if (argc < 2)
+ semantic_error("Too less arguments.");
+
+ /* Scan event and group name. */
+ ret = sscanf(argv[0], "%c:%m[^/ \t]/%m[^ \t]",
+ &pr, group, event);
+ if (ret != 3)
+ semantic_error("Failed to parse event name: %s", argv[0]);
+ pr_debug("Group:%s Event:%s probe:%c\n", *group, *event, pr);
+
+ if (!pp)
+ goto end;
+
+ pp->retprobe = (pr == 'r');
+
+ /* Scan function name and offset */
+ ret = sscanf(argv[1], "%m[^+]+%d", &pp->function, &pp->offset);
+ if (ret == 1)
+ pp->offset = 0;
+
+ /* kprobe_events doesn't have this information */
+ pp->line = 0;
+ pp->file = NULL;
+
+ pp->nr_args = argc - 2;
+ pp->args = zalloc(sizeof(char *) * pp->nr_args);
+ for (i = 0; i < pp->nr_args; i++) {
+ p = strchr(argv[i + 2], '=');
+ if (p) /* We don't need which register is assigned. */
+ *p = '\0';
+ pp->args[i] = strdup(argv[i + 2]);
+ if (!pp->args[i])
+ die("Failed to copy argument.");
+ }
+
+end:
+ argv_free(argv);
+}
+
+int synthesize_perf_probe_event(struct probe_point *pp)
+{
+ char *buf;
+ char offs[64] = "", line[64] = "";
+ int i, len, ret;
+
+ pp->probes[0] = buf = zalloc(MAX_CMDLEN);
+ if (!buf)
+ die("Failed to allocate memory by zalloc.");
+ if (pp->offset) {
+ ret = e_snprintf(offs, 64, "+%d", pp->offset);
+ if (ret <= 0)
+ goto error;
+ }
+ if (pp->line) {
+ ret = e_snprintf(line, 64, ":%d", pp->line);
+ if (ret <= 0)
+ goto error;
+ }
+
+ if (pp->function)
+ ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
+ offs, pp->retprobe ? "%return" : "", line);
+ else
+ ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->file, line);
+ if (ret <= 0)
+ goto error;
+ len = ret;
+
+ for (i = 0; i < pp->nr_args; i++) {
+ ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
+ pp->args[i]);
+ if (ret <= 0)
+ goto error;
+ len += ret;
+ }
+ pp->found = 1;
+
+ return pp->found;
+error:
+ free(pp->probes[0]);
+
+ return ret;
+}
+
int synthesize_trace_kprobe_event(struct probe_point *pp)
{
char *buf;
@@ -174,15 +287,15 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
pp->probes[0] = buf = zalloc(MAX_CMDLEN);
if (!buf)
die("Failed to allocate memory by zalloc.");
- ret = snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
- if (ret <= 0 || ret >= MAX_CMDLEN)
+ ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
+ if (ret <= 0)
goto error;
len = ret;
for (i = 0; i < pp->nr_args; i++) {
- ret = snprintf(&buf[len], MAX_CMDLEN - len, " %s",
- pp->args[i]);
- if (ret <= 0 || ret >= MAX_CMDLEN - len)
+ ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
+ pp->args[i]);
+ if (ret <= 0)
goto error;
len += ret;
}
@@ -191,12 +304,105 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
return pp->found;
error:
free(pp->probes[0]);
- if (ret > 0)
- ret = -E2BIG;
return ret;
}
+static int open_kprobe_events(int flags, int mode)
+{
+ char buf[PATH_MAX];
+ int ret;
+
+ ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
+ if (ret < 0)
+ die("Failed to make kprobe_events path.");
+
+ ret = open(buf, flags, mode);
+ if (ret < 0) {
+ if (errno == ENOENT)
+ die("kprobe_events file does not exist -"
+ " please rebuild with CONFIG_KPROBE_TRACER.");
+ else
+ die("Could not open kprobe_events file: %s",
+ strerror(errno));
+ }
+ return ret;
+}
+
+/* Get raw string list of current kprobe_events */
+static struct strlist *get_trace_kprobe_event_rawlist(int fd)
+{
+ int ret, idx;
+ FILE *fp;
+ char buf[MAX_CMDLEN];
+ char *p;
+ struct strlist *sl;
+
+ sl = strlist__new(true, NULL);
+
+ fp = fdopen(dup(fd), "r");
+ while (!feof(fp)) {
+ p = fgets(buf, MAX_CMDLEN, fp);
+ if (!p)
+ break;
+
+ idx = strlen(p) - 1;
+ if (p[idx] == '\n')
+ p[idx] = '\0';
+ ret = strlist__add(sl, buf);
+ if (ret < 0)
+ die("strlist__add failed: %s", strerror(-ret));
+ }
+ fclose(fp);
+
+ return sl;
+}
+
+/* Free and zero clear probe_point */
+static void clear_probe_point(struct probe_point *pp)
+{
+ int i;
+
+ if (pp->function)
+ free(pp->function);
+ if (pp->file)
+ free(pp->file);
+ for (i = 0; i < pp->nr_args; i++)
+ free(pp->args[i]);
+ if (pp->args)
+ free(pp->args);
+ for (i = 0; i < pp->found; i++)
+ free(pp->probes[i]);
+ memset(pp, 0, sizeof(pp));
+}
+
+/* List up current perf-probe events */
+void show_perf_probe_events(void)
+{
+ unsigned int i;
+ int fd;
+ char *group, *event;
+ struct probe_point pp;
+ struct strlist *rawlist;
+ struct str_node *ent;
+
+ fd = open_kprobe_events(O_RDONLY, 0);
+ rawlist = get_trace_kprobe_event_rawlist(fd);
+ close(fd);
+
+ for (i = 0; i < strlist__nr_entries(rawlist); i++) {
+ ent = strlist__entry(rawlist, i);
+ parse_trace_kprobe_event(ent->s, &group, &event, &pp);
+ synthesize_perf_probe_event(&pp);
+ printf("[%s:%s]\t%s\n", group, event, pp.probes[0]);
+ free(group);
+ free(event);
+ clear_probe_point(&pp);
+ }
+
+ strlist__delete(rawlist);
+}
+
static int write_trace_kprobe_event(int fd, const char *buf)
{
int ret;
@@ -216,16 +422,7 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
struct probe_point *pp;
char buf[MAX_CMDLEN];
- snprintf(buf, MAX_CMDLEN, "%s/../kprobe_events", debugfs_path);
- fd = open(buf, O_WRONLY, O_APPEND);
- if (fd < 0) {
- if (errno == ENOENT)
- die("kprobe_events file does not exist -"
- " please rebuild with CONFIG_KPROBE_TRACER.");
- else
- die("Could not open kprobe_events file: %s",
- strerror(errno));
- }
+ fd = open_kprobe_events(O_WRONLY, O_APPEND);
for (j = 0; j < nr_probes; j++) {
pp = probes + j;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 0089c45..88db7d1 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -2,9 +2,14 @@
#define _PROBE_EVENT_H
#include "probe-finder.h"
+#include "strlist.h"
extern int parse_perf_probe_event(const char *str, struct probe_point *pp);
+extern int synthesize_perf_probe_event(struct probe_point *pp);
+extern void parse_trace_kprobe_event(const char *str, char **group,
+ char **event, struct probe_point *pp);
extern int synthesize_trace_kprobe_event(struct probe_point *pp);
extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes);
+extern void show_perf_probe_events(void);
#endif /*_PROBE_EVENT_H */