mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
perf probe: Support event name for --add option
Support event name syntax for --add option. This allows users to specify event name for each new event. The --add syntax is: perf probe --add '[EVENT=]SRC:LINE ARGS' or perf probe --add '[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC] ARGS' e.g. ./perf probe --add myprobe1=schedule Note: currently group name is not supported yet, because it can cause name-space confliction with other tracepoint/ hw-breakpoint events. Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> 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: 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: systemtap <systemtap@sources.redhat.com> Cc: DLE <dle-develop@lists.sourceforge.net> Cc: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <20091215153218.17436.84675.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
bbbb521bc6
commit
af663d75a6
5 changed files with 55 additions and 36 deletions
|
@ -49,8 +49,9 @@ PROBE SYNTAX
|
||||||
------------
|
------------
|
||||||
Probe points are defined by following syntax.
|
Probe points are defined by following syntax.
|
||||||
|
|
||||||
"FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]"
|
"[EVENT=]FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]"
|
||||||
|
|
||||||
|
'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'.
|
||||||
'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. 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. 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 by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number.
|
It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number.
|
||||||
'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc).
|
'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc).
|
||||||
|
|
|
@ -172,13 +172,13 @@ static const struct option options[] = {
|
||||||
opt_del_probe_event),
|
opt_del_probe_event),
|
||||||
OPT_CALLBACK('a', "add", NULL,
|
OPT_CALLBACK('a', "add", NULL,
|
||||||
#ifdef NO_LIBDWARF
|
#ifdef NO_LIBDWARF
|
||||||
"FUNC[+OFFS|%return] [ARG ...]",
|
"[EVENT=]FUNC[+OFFS|%return] [ARG ...]",
|
||||||
#else
|
#else
|
||||||
"FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]",
|
"[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]",
|
||||||
#endif
|
#endif
|
||||||
"probe point definition, where\n"
|
"probe point definition, where\n"
|
||||||
"\t\tGRP:\tGroup name (optional)\n"
|
"\t\tGROUP:\tGroup name (optional)\n"
|
||||||
"\t\tNAME:\tEvent name\n"
|
"\t\tEVENT:\tEvent name\n"
|
||||||
"\t\tFUNC:\tFunction name\n"
|
"\t\tFUNC:\tFunction name\n"
|
||||||
"\t\tOFFS:\tOffset from function entry (in byte)\n"
|
"\t\tOFFS:\tOffset from function entry (in byte)\n"
|
||||||
"\t\t%return:\tPut the probe at function return\n"
|
"\t\t%return:\tPut the probe at function return\n"
|
||||||
|
|
|
@ -69,10 +69,23 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
|
||||||
char c, nc = 0;
|
char c, nc = 0;
|
||||||
/*
|
/*
|
||||||
* <Syntax>
|
* <Syntax>
|
||||||
* perf probe SRC:LN
|
* perf probe [EVENT=]SRC:LN
|
||||||
* perf probe FUNC[+OFFS|%return][@SRC]
|
* perf probe [EVENT=]FUNC[+OFFS|%return][@SRC]
|
||||||
|
*
|
||||||
|
* TODO:Group name support
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
ptr = strchr(arg, '=');
|
||||||
|
if (ptr) { /* Event name */
|
||||||
|
*ptr = '\0';
|
||||||
|
tmp = ptr + 1;
|
||||||
|
ptr = strchr(arg, ':');
|
||||||
|
if (ptr) /* Group name is not supported yet. */
|
||||||
|
semantic_error("Group name is not supported yet.");
|
||||||
|
pp->event = strdup(arg);
|
||||||
|
arg = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
ptr = strpbrk(arg, ":+@%");
|
ptr = strpbrk(arg, ":+@%");
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
nc = *ptr;
|
nc = *ptr;
|
||||||
|
@ -188,8 +201,7 @@ void parse_perf_probe_event(const char *str, struct probe_point *pp,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse kprobe_events event into struct probe_point */
|
/* Parse kprobe_events event into struct probe_point */
|
||||||
void parse_trace_kprobe_event(const char *str, char **group, char **event,
|
void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
|
||||||
struct probe_point *pp)
|
|
||||||
{
|
{
|
||||||
char pr;
|
char pr;
|
||||||
char *p;
|
char *p;
|
||||||
|
@ -205,18 +217,17 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
|
||||||
|
|
||||||
/* Scan event and group name. */
|
/* Scan event and group name. */
|
||||||
ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
|
ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
|
||||||
&pr, (float *)(void *)group, (float *)(void *)event);
|
&pr, (float *)(void *)&pp->group,
|
||||||
|
(float *)(void *)&pp->event);
|
||||||
if (ret != 3)
|
if (ret != 3)
|
||||||
semantic_error("Failed to parse event name: %s", argv[0]);
|
semantic_error("Failed to parse event name: %s", argv[0]);
|
||||||
pr_debug("Group:%s Event:%s probe:%c\n", *group, *event, pr);
|
pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr);
|
||||||
|
|
||||||
if (!pp)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
pp->retprobe = (pr == 'r');
|
pp->retprobe = (pr == 'r');
|
||||||
|
|
||||||
/* Scan function name and offset */
|
/* Scan function name and offset */
|
||||||
ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, &pp->offset);
|
ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
|
||||||
|
&pp->offset);
|
||||||
if (ret == 1)
|
if (ret == 1)
|
||||||
pp->offset = 0;
|
pp->offset = 0;
|
||||||
|
|
||||||
|
@ -235,7 +246,6 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
|
||||||
die("Failed to copy argument.");
|
die("Failed to copy argument.");
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
|
||||||
argv_free(argv);
|
argv_free(argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,6 +378,10 @@ static void clear_probe_point(struct probe_point *pp)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (pp->event)
|
||||||
|
free(pp->event);
|
||||||
|
if (pp->group)
|
||||||
|
free(pp->group);
|
||||||
if (pp->function)
|
if (pp->function)
|
||||||
free(pp->function);
|
free(pp->function);
|
||||||
if (pp->file)
|
if (pp->file)
|
||||||
|
@ -382,13 +396,13 @@ static void clear_probe_point(struct probe_point *pp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Show an event */
|
/* Show an event */
|
||||||
static void show_perf_probe_event(const char *group, const char *event,
|
static void show_perf_probe_event(const char *event, const char *place,
|
||||||
const char *place, struct probe_point *pp)
|
struct probe_point *pp)
|
||||||
{
|
{
|
||||||
int i, ret;
|
int i, ret;
|
||||||
char buf[128];
|
char buf[128];
|
||||||
|
|
||||||
ret = e_snprintf(buf, 128, "%s:%s", group, event);
|
ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
die("Failed to copy event: %s", strerror(-ret));
|
die("Failed to copy event: %s", strerror(-ret));
|
||||||
printf(" %-40s (on %s", buf, place);
|
printf(" %-40s (on %s", buf, place);
|
||||||
|
@ -405,7 +419,6 @@ static void show_perf_probe_event(const char *group, const char *event,
|
||||||
void show_perf_probe_events(void)
|
void show_perf_probe_events(void)
|
||||||
{
|
{
|
||||||
int fd, nr;
|
int fd, nr;
|
||||||
char *group, *event;
|
|
||||||
struct probe_point pp;
|
struct probe_point pp;
|
||||||
struct strlist *rawlist;
|
struct strlist *rawlist;
|
||||||
struct str_node *ent;
|
struct str_node *ent;
|
||||||
|
@ -415,16 +428,14 @@ void show_perf_probe_events(void)
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
strlist__for_each(ent, rawlist) {
|
strlist__for_each(ent, rawlist) {
|
||||||
parse_trace_kprobe_event(ent->s, &group, &event, &pp);
|
parse_trace_kprobe_event(ent->s, &pp);
|
||||||
/* Synthesize only event probe point */
|
/* Synthesize only event probe point */
|
||||||
nr = pp.nr_args;
|
nr = pp.nr_args;
|
||||||
pp.nr_args = 0;
|
pp.nr_args = 0;
|
||||||
synthesize_perf_probe_event(&pp);
|
synthesize_perf_probe_event(&pp);
|
||||||
pp.nr_args = nr;
|
pp.nr_args = nr;
|
||||||
/* Show an event */
|
/* Show an event */
|
||||||
show_perf_probe_event(group, event, pp.probes[0], &pp);
|
show_perf_probe_event(pp.event, pp.probes[0], &pp);
|
||||||
free(group);
|
|
||||||
free(event);
|
|
||||||
clear_probe_point(&pp);
|
clear_probe_point(&pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,24 +445,25 @@ void show_perf_probe_events(void)
|
||||||
/* Get current perf-probe event names */
|
/* Get current perf-probe event names */
|
||||||
static struct strlist *get_perf_event_names(int fd, bool include_group)
|
static struct strlist *get_perf_event_names(int fd, bool include_group)
|
||||||
{
|
{
|
||||||
char *group, *event;
|
|
||||||
char buf[128];
|
char buf[128];
|
||||||
struct strlist *sl, *rawlist;
|
struct strlist *sl, *rawlist;
|
||||||
struct str_node *ent;
|
struct str_node *ent;
|
||||||
|
struct probe_point pp;
|
||||||
|
|
||||||
|
memset(&pp, 0, sizeof(pp));
|
||||||
rawlist = get_trace_kprobe_event_rawlist(fd);
|
rawlist = get_trace_kprobe_event_rawlist(fd);
|
||||||
|
|
||||||
sl = strlist__new(true, NULL);
|
sl = strlist__new(true, NULL);
|
||||||
strlist__for_each(ent, rawlist) {
|
strlist__for_each(ent, rawlist) {
|
||||||
parse_trace_kprobe_event(ent->s, &group, &event, NULL);
|
parse_trace_kprobe_event(ent->s, &pp);
|
||||||
if (include_group) {
|
if (include_group) {
|
||||||
if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
|
if (e_snprintf(buf, 128, "%s:%s", pp.group,
|
||||||
|
pp.event) < 0)
|
||||||
die("Failed to copy group:event name.");
|
die("Failed to copy group:event name.");
|
||||||
strlist__add(sl, buf);
|
strlist__add(sl, buf);
|
||||||
} else
|
} else
|
||||||
strlist__add(sl, event);
|
strlist__add(sl, pp.event);
|
||||||
free(group);
|
clear_probe_point(&pp);
|
||||||
free(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
strlist__delete(rawlist);
|
strlist__delete(rawlist);
|
||||||
|
@ -507,19 +519,23 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
|
||||||
|
|
||||||
for (j = 0; j < nr_probes; j++) {
|
for (j = 0; j < nr_probes; j++) {
|
||||||
pp = probes + j;
|
pp = probes + j;
|
||||||
|
if (!pp->event)
|
||||||
|
pp->event = strdup(pp->function);
|
||||||
|
if (!pp->group)
|
||||||
|
pp->group = strdup(PERFPROBE_GROUP);
|
||||||
|
DIE_IF(!pp->event || !pp->group);
|
||||||
for (i = 0; i < pp->found; i++) {
|
for (i = 0; i < pp->found; i++) {
|
||||||
/* Get an unused new event name */
|
/* Get an unused new event name */
|
||||||
get_new_event_name(event, 64, pp->function, namelist);
|
get_new_event_name(event, 64, pp->event, namelist);
|
||||||
snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
|
snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
|
||||||
pp->retprobe ? 'r' : 'p',
|
pp->retprobe ? 'r' : 'p',
|
||||||
PERFPROBE_GROUP, event,
|
pp->group, event,
|
||||||
pp->probes[i]);
|
pp->probes[i]);
|
||||||
write_trace_kprobe_event(fd, buf);
|
write_trace_kprobe_event(fd, buf);
|
||||||
printf("Added new event:\n");
|
printf("Added new event:\n");
|
||||||
/* Get the first parameter (probe-point) */
|
/* Get the first parameter (probe-point) */
|
||||||
sscanf(pp->probes[i], "%s", buf);
|
sscanf(pp->probes[i], "%s", buf);
|
||||||
show_perf_probe_event(PERFPROBE_GROUP, event,
|
show_perf_probe_event(event, buf, pp);
|
||||||
buf, pp);
|
|
||||||
/* Add added event name to namelist */
|
/* Add added event name to namelist */
|
||||||
strlist__add(namelist, event);
|
strlist__add(namelist, event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,7 @@
|
||||||
extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
|
extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
|
||||||
bool *need_dwarf);
|
bool *need_dwarf);
|
||||||
extern int synthesize_perf_probe_event(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,
|
extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
|
||||||
char **event, struct probe_point *pp);
|
|
||||||
extern int synthesize_trace_kprobe_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 add_trace_kprobe_events(struct probe_point *probes, int nr_probes);
|
||||||
extern void del_trace_kprobe_events(struct strlist *dellist);
|
extern void del_trace_kprobe_events(struct strlist *dellist);
|
||||||
|
|
|
@ -12,6 +12,9 @@ static inline int is_c_varname(const char *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct probe_point {
|
struct probe_point {
|
||||||
|
char *event; /* Event name */
|
||||||
|
char *group; /* Event group */
|
||||||
|
|
||||||
/* Inputs */
|
/* Inputs */
|
||||||
char *file; /* File name */
|
char *file; /* File name */
|
||||||
int line; /* Line number */
|
int line; /* Line number */
|
||||||
|
|
Loading…
Reference in a new issue