diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2010-04-12 13:16:53 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-04-14 16:26:04 -0400 |
commit | 48481938b02471d505296d7557ed296eb093d496 (patch) | |
tree | 7549d861d76621d1e3d2ddd75eae4575901f1fd0 | |
parent | fcd1498405c2c88ac632e7c3c3fce3213d9196db (diff) |
perf probe: Support argument name
Set given names to event arguments. The syntax is same as kprobe-tracer,
you can add 'NAME=' right before each argument.
e.g.
./perf probe vfs_read foo=file
then, 'foo' is set to the argument name as below.
./perf probe -l
probe:vfs_read (on vfs_read@linux-2.6-tip/fs/read_write.c with foo)
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20100412171653.3790.74624.stgit@localhost6.localdomain6>
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/Documentation/perf-probe.txt | 10 | ||||
-rw-r--r-- | tools/perf/builtin-probe.c | 4 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 34 | ||||
-rw-r--r-- | tools/perf/util/probe-event.h | 1 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 27 |
5 files changed, 52 insertions, 24 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index bb671b346774..e36ed4dd3868 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
@@ -79,7 +79,15 @@ Probe points are defined by following syntax. | |||
79 | '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'. | 79 | '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'. |
80 | '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. | 80 | '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. |
81 | 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. | 81 | 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. |
82 | '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). | 82 | 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT). |
83 | |||
84 | PROBE ARGUMENT | ||
85 | -------------- | ||
86 | Each probe argument follows below syntax. | ||
87 | |||
88 | [NAME=]LOCALVAR|$retval|%REG|@SYMBOL | ||
89 | |||
90 | 'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), or kprobe-tracer argument format (e.g. $retval, %ax, etc). | ||
83 | 91 | ||
84 | LINE SYNTAX | 92 | LINE SYNTAX |
85 | ----------- | 93 | ----------- |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index bfc47fff9c59..daf4668d2de0 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -142,9 +142,9 @@ static const struct option options[] = { | |||
142 | OPT_CALLBACK('a', "add", NULL, | 142 | OPT_CALLBACK('a', "add", NULL, |
143 | #ifdef DWARF_SUPPORT | 143 | #ifdef DWARF_SUPPORT |
144 | "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" | 144 | "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" |
145 | " [ARG ...]", | 145 | " [[NAME=]ARG ...]", |
146 | #else | 146 | #else |
147 | "[EVENT=]FUNC[+OFF|%return] [ARG ...]", | 147 | "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]", |
148 | #endif | 148 | #endif |
149 | "probe point definition, where\n" | 149 | "probe point definition, where\n" |
150 | "\t\tGROUP:\tGroup name (optional)\n" | 150 | "\t\tGROUP:\tGroup name (optional)\n" |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 3fc0be741b8e..ab6f53deabad 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -437,22 +437,28 @@ static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
437 | /* Parse perf-probe event argument */ | 437 | /* Parse perf-probe event argument */ |
438 | static void parse_perf_probe_arg(const char *str, struct perf_probe_arg *arg) | 438 | static void parse_perf_probe_arg(const char *str, struct perf_probe_arg *arg) |
439 | { | 439 | { |
440 | const char *tmp; | 440 | char *tmp; |
441 | struct perf_probe_arg_field **fieldp; | 441 | struct perf_probe_arg_field **fieldp; |
442 | 442 | ||
443 | pr_debug("parsing arg: %s into ", str); | 443 | pr_debug("parsing arg: %s into ", str); |
444 | 444 | ||
445 | tmp = strchr(str, '='); | ||
446 | if (tmp) { | ||
447 | arg->name = xstrndup(str, tmp - str); | ||
448 | str = tmp + 1; | ||
449 | } | ||
450 | |||
445 | tmp = strpbrk(str, "-."); | 451 | tmp = strpbrk(str, "-."); |
446 | if (!is_c_varname(str) || !tmp) { | 452 | if (!is_c_varname(str) || !tmp) { |
447 | /* A variable, register, symbol or special value */ | 453 | /* A variable, register, symbol or special value */ |
448 | arg->name = xstrdup(str); | 454 | arg->var = xstrdup(str); |
449 | pr_debug("%s\n", arg->name); | 455 | pr_debug("%s\n", arg->var); |
450 | return; | 456 | return; |
451 | } | 457 | } |
452 | 458 | ||
453 | /* Structure fields */ | 459 | /* Structure fields */ |
454 | arg->name = xstrndup(str, tmp - str); | 460 | arg->var = xstrndup(str, tmp - str); |
455 | pr_debug("%s, ", arg->name); | 461 | pr_debug("%s, ", arg->var); |
456 | fieldp = &arg->field; | 462 | fieldp = &arg->field; |
457 | 463 | ||
458 | do { | 464 | do { |
@@ -497,7 +503,7 @@ void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) | |||
497 | pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs); | 503 | pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs); |
498 | for (i = 0; i < pev->nargs; i++) { | 504 | for (i = 0; i < pev->nargs; i++) { |
499 | parse_perf_probe_arg(argv[i + 1], &pev->args[i]); | 505 | parse_perf_probe_arg(argv[i + 1], &pev->args[i]); |
500 | if (is_c_varname(pev->args[i].name) && pev->point.retprobe) | 506 | if (is_c_varname(pev->args[i].var) && pev->point.retprobe) |
501 | semantic_error("You can't specify local variable for" | 507 | semantic_error("You can't specify local variable for" |
502 | " kretprobe"); | 508 | " kretprobe"); |
503 | } | 509 | } |
@@ -514,7 +520,7 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) | |||
514 | return true; | 520 | return true; |
515 | 521 | ||
516 | for (i = 0; i < pev->nargs; i++) | 522 | for (i = 0; i < pev->nargs; i++) |
517 | if (is_c_varname(pev->args[i].name)) | 523 | if (is_c_varname(pev->args[i].var)) |
518 | return true; | 524 | return true; |
519 | 525 | ||
520 | return false; | 526 | return false; |
@@ -575,7 +581,10 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) | |||
575 | int ret; | 581 | int ret; |
576 | char *tmp = buf; | 582 | char *tmp = buf; |
577 | 583 | ||
578 | ret = e_snprintf(tmp, len, "%s", pa->name); | 584 | if (pa->name && pa->var) |
585 | ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); | ||
586 | else | ||
587 | ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); | ||
579 | if (ret <= 0) | 588 | if (ret <= 0) |
580 | goto error; | 589 | goto error; |
581 | tmp += ret; | 590 | tmp += ret; |
@@ -803,6 +812,8 @@ void clear_perf_probe_event(struct perf_probe_event *pev) | |||
803 | for (i = 0; i < pev->nargs; i++) { | 812 | for (i = 0; i < pev->nargs; i++) { |
804 | if (pev->args[i].name) | 813 | if (pev->args[i].name) |
805 | free(pev->args[i].name); | 814 | free(pev->args[i].name); |
815 | if (pev->args[i].var) | ||
816 | free(pev->args[i].var); | ||
806 | field = pev->args[i].field; | 817 | field = pev->args[i].field; |
807 | while (field) { | 818 | while (field) { |
808 | next = field->next; | 819 | next = field->next; |
@@ -1117,8 +1128,11 @@ static int convert_to_kprobe_trace_events(struct perf_probe_event *pev, | |||
1117 | if (tev->nargs) { | 1128 | if (tev->nargs) { |
1118 | tev->args = xzalloc(sizeof(struct kprobe_trace_arg) | 1129 | tev->args = xzalloc(sizeof(struct kprobe_trace_arg) |
1119 | * tev->nargs); | 1130 | * tev->nargs); |
1120 | for (i = 0; i < tev->nargs; i++) | 1131 | for (i = 0; i < tev->nargs; i++) { |
1121 | tev->args[i].value = xstrdup(pev->args[i].name); | 1132 | if (pev->args[i].name) |
1133 | tev->args[i].name = xstrdup(pev->args[i].name); | ||
1134 | tev->args[i].value = xstrdup(pev->args[i].var); | ||
1135 | } | ||
1122 | } | 1136 | } |
1123 | 1137 | ||
1124 | /* Currently just checking function name from symbol map */ | 1138 | /* Currently just checking function name from symbol map */ |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 9d99fc24c4fc..10411f596321 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -55,6 +55,7 @@ struct perf_probe_arg_field { | |||
55 | /* Perf probe probing argument */ | 55 | /* Perf probe probing argument */ |
56 | struct perf_probe_arg { | 56 | struct perf_probe_arg { |
57 | char *name; /* Argument name */ | 57 | char *name; /* Argument name */ |
58 | char *var; /* Variable name */ | ||
58 | struct perf_probe_arg_field *field; /* Structure fields */ | 59 | struct perf_probe_arg_field *field; /* Structure fields */ |
59 | }; | 60 | }; |
60 | 61 | ||
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index a8513772df08..105e95c95eeb 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -484,35 +484,40 @@ static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
484 | convert_location(expr, pf); | 484 | convert_location(expr, pf); |
485 | 485 | ||
486 | if (pf->pvar->field) | 486 | if (pf->pvar->field) |
487 | convert_variable_fields(vr_die, pf->pvar->name, | 487 | convert_variable_fields(vr_die, pf->pvar->var, |
488 | pf->pvar->field, &pf->tvar->ref); | 488 | pf->pvar->field, &pf->tvar->ref); |
489 | /* *expr will be cached in libdw. Don't free it. */ | 489 | /* *expr will be cached in libdw. Don't free it. */ |
490 | return ; | 490 | return ; |
491 | error: | 491 | error: |
492 | /* TODO: Support const_value */ | 492 | /* TODO: Support const_value */ |
493 | die("Failed to find the location of %s at this address.\n" | 493 | die("Failed to find the location of %s at this address.\n" |
494 | " Perhaps, it has been optimized out.", pf->pvar->name); | 494 | " Perhaps, it has been optimized out.", pf->pvar->var); |
495 | } | 495 | } |
496 | 496 | ||
497 | /* Find a variable in a subprogram die */ | 497 | /* Find a variable in a subprogram die */ |
498 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 498 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) |
499 | { | 499 | { |
500 | Dwarf_Die vr_die; | 500 | Dwarf_Die vr_die; |
501 | char buf[128]; | 501 | char buf[32]; |
502 | 502 | ||
503 | /* TODO: Support struct members and arrays */ | 503 | /* TODO: Support arrays */ |
504 | if (!is_c_varname(pf->pvar->name)) { | 504 | if (pf->pvar->name) |
505 | pf->tvar->name = xstrdup(pf->pvar->name); | ||
506 | else { | ||
507 | synthesize_perf_probe_arg(pf->pvar, buf, 32); | ||
508 | pf->tvar->name = xstrdup(buf); | ||
509 | } | ||
510 | |||
511 | if (!is_c_varname(pf->pvar->var)) { | ||
505 | /* Copy raw parameters */ | 512 | /* Copy raw parameters */ |
506 | pf->tvar->value = xstrdup(pf->pvar->name); | 513 | pf->tvar->value = xstrdup(pf->pvar->var); |
507 | } else { | 514 | } else { |
508 | synthesize_perf_probe_arg(pf->pvar, buf, 128); | ||
509 | pf->tvar->name = xstrdup(buf); | ||
510 | pr_debug("Searching '%s' variable in context.\n", | 515 | pr_debug("Searching '%s' variable in context.\n", |
511 | pf->pvar->name); | 516 | pf->pvar->var); |
512 | /* Search child die for local variables and parameters. */ | 517 | /* Search child die for local variables and parameters. */ |
513 | if (!die_find_variable(sp_die, pf->pvar->name, &vr_die)) | 518 | if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) |
514 | die("Failed to find '%s' in this function.", | 519 | die("Failed to find '%s' in this function.", |
515 | pf->pvar->name); | 520 | pf->pvar->var); |
516 | convert_variable(&vr_die, pf); | 521 | convert_variable(&vr_die, pf); |
517 | } | 522 | } |
518 | } | 523 | } |