diff options
| author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2010-10-21 06:13:41 -0400 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-10-21 14:11:44 -0400 |
| commit | 469b9b88488e89114bb3e9ac5ee7906b7b96123f (patch) | |
| tree | 9f002195a8b1167eddbe560ac834e6ba2dedb19f | |
| parent | fb8c5a56c7ddbc2b0d2ee7a8da60fe1355f75141 (diff) | |
perf probe: Add basic module support
Add basic module probe support on perf probe. This introduces "--module
<MODNAME>" option to perf probe for putting probes and showing lines and
variables in the given module.
Currently, this supports only probing on running modules. Supporting off-line
module probing is the next step.
e.g.)
[show lines]
# ./perf probe --module drm -L drm_vblank_info
<drm_vblank_info:0>
0 int drm_vblank_info(struct seq_file *m, void *data)
1 {
struct drm_info_node *node = (struct drm_info_node *) m->private
3 struct drm_device *dev = node->minor->dev;
...
[show vars]
# ./perf probe --module drm -V drm_vblank_info:3
Available variables at drm_vblank_info:3
@<drm_vblank_info+20>
(unknown_type) data
struct drm_info_node* node
struct seq_file* m
[put a probe]
# ./perf probe --module drm drm_vblank_info:3 node m
Add new event:
probe:drm_vblank_info (on drm_vblank_info:3 with node m)
You can now use it on all perf tools, such as:
perf record -e probe:drm_vblank_info -aR sleep 1
[list probes]
# ./perf probe -l
probe:drm_vblank_info (on drm_vblank_info:3@drivers/gpu/drm/drm_info.c with ...
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20101021101341.3542.71638.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
| -rw-r--r-- | tools/perf/Documentation/perf-probe.txt | 9 | ||||
| -rw-r--r-- | tools/perf/builtin-probe.c | 11 | ||||
| -rw-r--r-- | tools/perf/util/map.h | 10 | ||||
| -rw-r--r-- | tools/perf/util/probe-event.c | 123 | ||||
| -rw-r--r-- | tools/perf/util/probe-event.h | 10 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.c | 142 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.h | 3 |
7 files changed, 239 insertions, 69 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 148c178a35a..62de1b7f4e7 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
| @@ -16,9 +16,9 @@ or | |||
| 16 | or | 16 | or |
| 17 | 'perf probe' --list | 17 | 'perf probe' --list |
| 18 | or | 18 | or |
| 19 | 'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' | 19 | 'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' |
| 20 | or | 20 | or |
| 21 | 'perf probe' [--externs] --vars='PROBEPOINT' | 21 | 'perf probe' [options] --vars='PROBEPOINT' |
| 22 | 22 | ||
| 23 | DESCRIPTION | 23 | DESCRIPTION |
| 24 | ----------- | 24 | ----------- |
| @@ -33,6 +33,11 @@ OPTIONS | |||
| 33 | --vmlinux=PATH:: | 33 | --vmlinux=PATH:: |
| 34 | Specify vmlinux path which has debuginfo (Dwarf binary). | 34 | Specify vmlinux path which has debuginfo (Dwarf binary). |
| 35 | 35 | ||
| 36 | -m:: | ||
| 37 | --module=MODNAME:: | ||
| 38 | Specify module name in which perf-probe searches probe points | ||
| 39 | or lines. | ||
| 40 | |||
| 36 | -s:: | 41 | -s:: |
| 37 | --source=PATH:: | 42 | --source=PATH:: |
| 38 | Specify path to kernel source. | 43 | Specify path to kernel source. |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index bdf60cfdf70..2e000c068cc 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
| @@ -57,6 +57,7 @@ static struct { | |||
| 57 | struct perf_probe_event events[MAX_PROBES]; | 57 | struct perf_probe_event events[MAX_PROBES]; |
| 58 | struct strlist *dellist; | 58 | struct strlist *dellist; |
| 59 | struct line_range line_range; | 59 | struct line_range line_range; |
| 60 | const char *target_module; | ||
| 60 | int max_probe_points; | 61 | int max_probe_points; |
| 61 | } params; | 62 | } params; |
| 62 | 63 | ||
| @@ -162,8 +163,8 @@ static const char * const probe_usage[] = { | |||
| 162 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", | 163 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", |
| 163 | "perf probe --list", | 164 | "perf probe --list", |
| 164 | #ifdef DWARF_SUPPORT | 165 | #ifdef DWARF_SUPPORT |
| 165 | "perf probe --line 'LINEDESC'", | 166 | "perf probe [<options>] --line 'LINEDESC'", |
| 166 | "perf probe [--externs] --vars 'PROBEPOINT'", | 167 | "perf probe [<options>] --vars 'PROBEPOINT'", |
| 167 | #endif | 168 | #endif |
| 168 | NULL | 169 | NULL |
| 169 | }; | 170 | }; |
| @@ -214,6 +215,8 @@ static const struct option options[] = { | |||
| 214 | "file", "vmlinux pathname"), | 215 | "file", "vmlinux pathname"), |
| 215 | OPT_STRING('s', "source", &symbol_conf.source_prefix, | 216 | OPT_STRING('s', "source", &symbol_conf.source_prefix, |
| 216 | "directory", "path to kernel source"), | 217 | "directory", "path to kernel source"), |
| 218 | OPT_STRING('m', "module", ¶ms.target_module, | ||
| 219 | "modname", "target module name"), | ||
| 217 | #endif | 220 | #endif |
| 218 | OPT__DRY_RUN(&probe_event_dry_run), | 221 | OPT__DRY_RUN(&probe_event_dry_run), |
| 219 | OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, | 222 | OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, |
| @@ -278,7 +281,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
| 278 | usage_with_options(probe_usage, options); | 281 | usage_with_options(probe_usage, options); |
| 279 | } | 282 | } |
| 280 | 283 | ||
| 281 | ret = show_line_range(¶ms.line_range); | 284 | ret = show_line_range(¶ms.line_range, params.target_module); |
| 282 | if (ret < 0) | 285 | if (ret < 0) |
| 283 | pr_err(" Error: Failed to show lines. (%d)\n", ret); | 286 | pr_err(" Error: Failed to show lines. (%d)\n", ret); |
| 284 | return ret; | 287 | return ret; |
| @@ -291,6 +294,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
| 291 | } | 294 | } |
| 292 | ret = show_available_vars(params.events, params.nevents, | 295 | ret = show_available_vars(params.events, params.nevents, |
| 293 | params.max_probe_points, | 296 | params.max_probe_points, |
| 297 | params.target_module, | ||
| 294 | params.show_ext_vars); | 298 | params.show_ext_vars); |
| 295 | if (ret < 0) | 299 | if (ret < 0) |
| 296 | pr_err(" Error: Failed to show vars. (%d)\n", ret); | 300 | pr_err(" Error: Failed to show vars. (%d)\n", ret); |
| @@ -310,6 +314,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
| 310 | if (params.nevents) { | 314 | if (params.nevents) { |
| 311 | ret = add_perf_probe_events(params.events, params.nevents, | 315 | ret = add_perf_probe_events(params.events, params.nevents, |
| 312 | params.max_probe_points, | 316 | params.max_probe_points, |
| 317 | params.target_module, | ||
| 313 | params.force_add); | 318 | params.force_add); |
| 314 | if (ret < 0) { | 319 | if (ret < 0) { |
| 315 | pr_err(" Error: Failed to add events. (%d)\n", ret); | 320 | pr_err(" Error: Failed to add events. (%d)\n", ret); |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 78575796d5f..b397c038372 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
| @@ -215,6 +215,16 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *self, | |||
| 215 | return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter); | 215 | return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter); |
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | static inline | ||
| 219 | struct symbol *machine__find_kernel_function_by_name(struct machine *self, | ||
| 220 | const char *name, | ||
| 221 | struct map **mapp, | ||
| 222 | symbol_filter_t filter) | ||
| 223 | { | ||
| 224 | return map_groups__find_function_by_name(&self->kmaps, name, mapp, | ||
| 225 | filter); | ||
| 226 | } | ||
| 227 | |||
| 218 | int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, | 228 | int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, |
| 219 | int verbose, FILE *fp); | 229 | int verbose, FILE *fp); |
| 220 | 230 | ||
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 82b0976e205..3b6a5297bf1 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -74,10 +74,9 @@ static int e_snprintf(char *str, size_t size, const char *format, ...) | |||
| 74 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); | 74 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); |
| 75 | static struct machine machine; | 75 | static struct machine machine; |
| 76 | 76 | ||
| 77 | /* Initialize symbol maps and path of vmlinux */ | 77 | /* Initialize symbol maps and path of vmlinux/modules */ |
| 78 | static int init_vmlinux(void) | 78 | static int init_vmlinux(void) |
| 79 | { | 79 | { |
| 80 | struct dso *kernel; | ||
| 81 | int ret; | 80 | int ret; |
| 82 | 81 | ||
| 83 | symbol_conf.sort_by_name = true; | 82 | symbol_conf.sort_by_name = true; |
| @@ -91,33 +90,61 @@ static int init_vmlinux(void) | |||
| 91 | goto out; | 90 | goto out; |
| 92 | } | 91 | } |
| 93 | 92 | ||
| 94 | ret = machine__init(&machine, "/", 0); | 93 | ret = machine__init(&machine, "", HOST_KERNEL_ID); |
| 95 | if (ret < 0) | 94 | if (ret < 0) |
| 96 | goto out; | 95 | goto out; |
| 97 | 96 | ||
| 98 | kernel = dso__new_kernel(symbol_conf.vmlinux_name); | 97 | if (machine__create_kernel_maps(&machine) < 0) { |
| 99 | if (kernel == NULL) | 98 | pr_debug("machine__create_kernel_maps "); |
| 100 | die("Failed to create kernel dso."); | 99 | goto out; |
| 101 | 100 | } | |
| 102 | ret = __machine__create_kernel_maps(&machine, kernel); | ||
| 103 | if (ret < 0) | ||
| 104 | pr_debug("Failed to create kernel maps.\n"); | ||
| 105 | |||
| 106 | out: | 101 | out: |
| 107 | if (ret < 0) | 102 | if (ret < 0) |
| 108 | pr_warning("Failed to init vmlinux path.\n"); | 103 | pr_warning("Failed to init vmlinux path.\n"); |
| 109 | return ret; | 104 | return ret; |
| 110 | } | 105 | } |
| 111 | 106 | ||
| 107 | static struct symbol *__find_kernel_function_by_name(const char *name, | ||
| 108 | struct map **mapp) | ||
| 109 | { | ||
| 110 | return machine__find_kernel_function_by_name(&machine, name, mapp, | ||
| 111 | NULL); | ||
| 112 | } | ||
| 113 | |||
| 114 | const char *kernel_get_module_path(const char *module) | ||
| 115 | { | ||
| 116 | struct dso *dso; | ||
| 117 | |||
| 118 | if (module) { | ||
| 119 | list_for_each_entry(dso, &machine.kernel_dsos, node) { | ||
| 120 | if (strncmp(dso->short_name + 1, module, | ||
| 121 | dso->short_name_len - 2) == 0) | ||
| 122 | goto found; | ||
| 123 | } | ||
| 124 | pr_debug("Failed to find module %s.\n", module); | ||
| 125 | return NULL; | ||
| 126 | } else { | ||
| < | |||
