From: Arnaldo Carvalho de Melo <[email protected]>
This should be properly fixed when we remove the XXX comment in 'perf
report', function resolve_symbol.
Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/symbol.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 4ed379b..8aab89b 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1516,6 +1516,7 @@ static int kernel_maps__create_kernel_map(const struct symbol_conf *conf)
vdso = dso__new("[vdso]");
if (vdso == NULL)
goto out_delete_kernel_map;
+ vdso->loaded = 1;
if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
sizeof(kernel->build_id)) == 0)
--
1.6.2.5
From: Arnaldo Carvalho de Melo <[email protected]>
As we'll have kernel_map[s]__variables too.
Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-annotate.c | 2 +-
tools/perf/util/symbol.c | 46 ++++++++++++++++++++--------------------
tools/perf/util/symbol.h | 2 +-
3 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 18ac5ea..377cb7c 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -184,7 +184,7 @@ got_map:
* trick of looking in the whole kernel symbol list.
*/
if ((long long)ip < 0) {
- map = kernel_map;
+ map = kernel_map__functions;
goto got_map;
}
}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 8aab89b..687fb7f 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -43,7 +43,7 @@ static struct symbol_conf symbol_conf__defaults = {
.try_vmlinux_path = true,
};
-static struct rb_root kernel_maps;
+static struct rb_root kernel_maps__functions;
static void symbols__fixup_end(struct rb_root *self)
{
@@ -71,7 +71,7 @@ static void symbols__fixup_end(struct rb_root *self)
static void kernel_maps__fixup_end(void)
{
struct map *prev, *curr;
- struct rb_node *nd, *prevnd = rb_first(&kernel_maps);
+ struct rb_node *nd, *prevnd = rb_first(&kernel_maps__functions);
if (prevnd == NULL)
return;
@@ -325,7 +325,7 @@ static int kernel_maps__load_all_kallsyms(void)
* kernel_maps__split_kallsyms, when we have split the
* maps per module
*/
- symbols__insert(&kernel_map->dso->functions, sym);
+ symbols__insert(&kernel_map__functions->dso->functions, sym);
}
free(line);
@@ -346,10 +346,10 @@ out_failure:
*/
static int kernel_maps__split_kallsyms(symbol_filter_t filter)
{
- struct map *map = kernel_map;
+ struct map *map = kernel_map__functions;
struct symbol *pos;
int count = 0;
- struct rb_node *next = rb_first(&kernel_map->dso->functions);
+ struct rb_node *next = rb_first(&kernel_map__functions->dso->functions);
int kernel_range = 0;
while (next) {
@@ -376,7 +376,7 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter)
*/
pos->start = map->map_ip(map, pos->start);
pos->end = map->map_ip(map, pos->end);
- } else if (map != kernel_map) {
+ } else if (map != kernel_map__functions) {
char dso_name[PATH_MAX];
struct dso *dso;
@@ -399,12 +399,12 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter)
}
if (filter && filter(map, pos)) {
- rb_erase(&pos->rb_node, &kernel_map->dso->functions);
+ rb_erase(&pos->rb_node, &kernel_map__functions->dso->functions);
symbol__delete(pos);
} else {
- if (map != kernel_map) {
+ if (map != kernel_map__functions) {
rb_erase(&pos->rb_node,
- &kernel_map->dso->functions);
+ &kernel_map__functions->dso->functions);
symbols__insert(&map->dso->functions, pos);
}
count++;
@@ -420,8 +420,8 @@ static int kernel_maps__load_kallsyms(symbol_filter_t filter)
if (kernel_maps__load_all_kallsyms())
return -1;
- symbols__fixup_end(&kernel_map->dso->functions);
- kernel_map->dso->origin = DSO__ORIG_KERNEL;
+ symbols__fixup_end(&kernel_map__functions->dso->functions);
+ kernel_map__functions->dso->origin = DSO__ORIG_KERNEL;
return kernel_maps__split_kallsyms(filter);
}
@@ -431,7 +431,7 @@ size_t kernel_maps__fprintf(FILE *fp)
size_t printed = fprintf(fp, "Kernel maps:\n");
struct rb_node *nd;
- for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
+ for (nd = rb_first(&kernel_maps__functions); nd; nd = rb_next(nd)) {
struct map *pos = rb_entry(nd, struct map, rb_node);
printed += fprintf(fp, "Map:");
@@ -1159,17 +1159,17 @@ out:
return ret;
}
-struct map *kernel_map;
+struct map *kernel_map__functions;
static void kernel_maps__insert(struct map *map)
{
- maps__insert(&kernel_maps, map);
+ maps__insert(&kernel_maps__functions, map);
}
struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp,
symbol_filter_t filter)
{
- struct map *map = maps__find(&kernel_maps, ip);
+ struct map *map = maps__find(&kernel_maps__functions, ip);
if (mapp)
*mapp = map;
@@ -1178,7 +1178,7 @@ struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp,
ip = map->map_ip(map, ip);
return map__find_function(map, ip, filter);
} else
- WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps),
+ WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps__functions),
"Empty kernel_maps, was symbol__init() called?\n");
return NULL;
@@ -1188,7 +1188,7 @@ struct map *kernel_maps__find_by_dso_name(const char *name)
{
struct rb_node *nd;
- for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
+ for (nd = rb_first(&kernel_maps__functions); nd; nd = rb_next(nd)) {
struct map *map = rb_entry(nd, struct map, rb_node);
if (map->dso && strcmp(map->dso->name, name) == 0)
@@ -1505,11 +1505,11 @@ static int kernel_maps__create_kernel_map(const struct symbol_conf *conf)
if (kernel == NULL)
return -1;
- kernel_map = map__new2(0, kernel);
- if (kernel_map == NULL)
+ kernel_map__functions = map__new2(0, kernel);
+ if (kernel_map__functions == NULL)
goto out_delete_kernel_dso;
- kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip;
+ kernel_map__functions->map_ip = kernel_map__functions->unmap_ip = identity__map_ip;
kernel->short_name = "[kernel]";
kernel->kernel = 1;
@@ -1522,15 +1522,15 @@ static int kernel_maps__create_kernel_map(const struct symbol_conf *conf)
sizeof(kernel->build_id)) == 0)
kernel->has_build_id = true;
- kernel_maps__insert(kernel_map);
+ kernel_maps__insert(kernel_map__functions);
dsos__add(kernel);
dsos__add(vdso);
return 0;
out_delete_kernel_map:
- map__delete(kernel_map);
- kernel_map = NULL;
+ map__delete(kernel_map__functions);
+ kernel_map__functions = NULL;
out_delete_kernel_dso:
dso__delete(kernel);
return -1;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 65846d0..b42d196 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -105,6 +105,6 @@ size_t kernel_maps__fprintf(FILE *fp);
int symbol__init(struct symbol_conf *conf);
extern struct list_head dsos;
-extern struct map *kernel_map;
+extern struct map *kernel_map__functions;
extern struct dso *vdso;
#endif /* __PERF_SYMBOL */
--
1.6.2.5
From: Arnaldo Carvalho de Melo <[email protected]>
We don't need to look at modules in dsos__findnew because the kernel
events come only with user DSOs. Also we need a way to list just the
module DSOs so that we can create multiple sets of maps, now that we
will support maps for the variables in a symtab.
Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/header.c | 12 ++++++++-
tools/perf/util/symbol.c | 56 ++++++++++++++++++++++++++++++---------------
tools/perf/util/symbol.h | 2 +-
3 files changed, 48 insertions(+), 22 deletions(-)
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 4b58656..4805e6d 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -185,11 +185,11 @@ static int do_write(int fd, const void *buf, size_t size)
return 0;
}
-static int dsos__write_buildid_table(int fd)
+static int __dsos__write_buildid_table(struct list_head *head, int fd)
{
struct dso *pos;
- list_for_each_entry(pos, &dsos, node) {
+ list_for_each_entry(pos, head, node) {
int err;
struct build_id_event b;
size_t len;
@@ -212,6 +212,14 @@ static int dsos__write_buildid_table(int fd)
return 0;
}
+static int dsos__write_buildid_table(int fd)
+{
+ int err = __dsos__write_buildid_table(&dsos__kernel, fd);
+ if (err == 0)
+ err = __dsos__write_buildid_table(&dsos__user, fd);
+ return err;
+}
+
static int perf_header__adds_write(struct perf_header *self, int fd)
{
int nr_sections;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 687fb7f..dc25231 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -28,8 +28,7 @@ enum dso_origin {
DSO__ORIG_NOT_FOUND,
};
-static void dsos__add(struct dso *dso);
-static struct dso *dsos__find(const char *name);
+static void dsos__add(struct list_head *head, struct dso *dso);
static struct map *map__new2(u64 start, struct dso *dso);
static void kernel_maps__insert(struct map *map);
static int dso__load_kernel_sym(struct dso *self, struct map *map,
@@ -855,7 +854,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
curr_map->unmap_ip = identity__map_ip;
curr_dso->origin = DSO__ORIG_KERNEL;
kernel_maps__insert(curr_map);
- dsos__add(curr_dso);
+ dsos__add(&dsos__kernel, curr_dso);
} else
curr_dso = curr_map->dso;
@@ -907,12 +906,12 @@ static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
}
-bool dsos__read_build_ids(void)
+static bool __dsos__read_build_ids(struct list_head *head)
{
bool have_build_id = false;
struct dso *pos;
- list_for_each_entry(pos, &dsos, node)
+ list_for_each_entry(pos, head, node)
if (filename__read_build_id(pos->long_name, pos->build_id,
sizeof(pos->build_id)) > 0) {
have_build_id = true;
@@ -922,6 +921,12 @@ bool dsos__read_build_ids(void)
return have_build_id;
}
+bool dsos__read_build_ids(void)
+{
+ return __dsos__read_build_ids(&dsos__kernel) ||
+ __dsos__read_build_ids(&dsos__user);
+}
+
/*
* Align offset to 4 bytes as needed for note name and descriptor data.
*/
@@ -1343,7 +1348,7 @@ static int kernel_maps__create_module_maps(void)
dso->origin = DSO__ORIG_KMODULE;
kernel_maps__insert(map);
- dsos__add(dso);
+ dsos__add(&dsos__kernel, dso);
}
free(line);
@@ -1445,19 +1450,20 @@ out_fixup:
return err;
}
-LIST_HEAD(dsos);
+LIST_HEAD(dsos__user);
+LIST_HEAD(dsos__kernel);
struct dso *vdso;
-static void dsos__add(struct dso *dso)
+static void dsos__add(struct list_head *head, struct dso *dso)
{
- list_add_tail(&dso->node, &dsos);
+ list_add_tail(&dso->node, head);
}
-static struct dso *dsos__find(const char *name)
+static struct dso *dsos__find(struct list_head *head, const char *name)
{
struct dso *pos;
- list_for_each_entry(pos, &dsos, node)
+ list_for_each_entry(pos, head, node)
if (strcmp(pos->name, name) == 0)
return pos;
return NULL;
@@ -1465,12 +1471,12 @@ static struct dso *dsos__find(const char *name)
struct dso *dsos__findnew(const char *name)
{
- struct dso *dso = dsos__find(name);
+ struct dso *dso = dsos__find(&dsos__user, name);
if (!dso) {
dso = dso__new(name);
if (dso != NULL) {
- dsos__add(dso);
+ dsos__add(&dsos__user, dso);
dso__set_basename(dso);
}
}
@@ -1478,26 +1484,38 @@ struct dso *dsos__findnew(const char *name)
return dso;
}
-void dsos__fprintf(FILE *fp)
+static void __dsos__fprintf(struct list_head *head, FILE *fp)
{
struct dso *pos;
- list_for_each_entry(pos, &dsos, node)
+ list_for_each_entry(pos, head, node)
dso__fprintf(pos, fp);
}
-size_t dsos__fprintf_buildid(FILE *fp)
+void dsos__fprintf(FILE *fp)
+{
+ __dsos__fprintf(&dsos__kernel, fp);
+ __dsos__fprintf(&dsos__user, fp);
+}
+
+static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp)
{
struct dso *pos;
size_t ret = 0;
- list_for_each_entry(pos, &dsos, node) {
+ list_for_each_entry(pos, head, node) {
ret += dso__fprintf_buildid(pos, fp);
ret += fprintf(fp, " %s\n", pos->long_name);
}
return ret;
}
+size_t dsos__fprintf_buildid(FILE *fp)
+{
+ return (__dsos__fprintf_buildid(&dsos__kernel, fp) +
+ __dsos__fprintf_buildid(&dsos__user, fp));
+}
+
static int kernel_maps__create_kernel_map(const struct symbol_conf *conf)
{
struct dso *kernel = dso__new(conf->vmlinux_name ?: "[kernel.kallsyms]");
@@ -1523,8 +1541,8 @@ static int kernel_maps__create_kernel_map(const struct symbol_conf *conf)
kernel->has_build_id = true;
kernel_maps__insert(kernel_map__functions);
- dsos__add(kernel);
- dsos__add(vdso);
+ dsos__add(&dsos__kernel, kernel);
+ dsos__add(&dsos__user, vdso);
return 0;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index b42d196..5d0371f 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -104,7 +104,7 @@ size_t kernel_maps__fprintf(FILE *fp);
int symbol__init(struct symbol_conf *conf);
-extern struct list_head dsos;
+extern struct list_head dsos__user, dsos__kernel;
extern struct map *kernel_map__functions;
extern struct dso *vdso;
#endif /* __PERF_SYMBOL */
--
1.6.2.5
From: Arnaldo Carvalho de Melo <[email protected]>
perf annotate was the only user, and it doesn't really needs it.
Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-annotate.c | 8 +++-----
tools/perf/util/symbol.c | 3 +--
tools/perf/util/symbol.h | 1 -
3 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 377cb7c..0846c8a 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -169,7 +169,6 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
level = '.';
map = thread__find_map(thread, ip);
if (map != NULL) {
-got_map:
ip = map->map_ip(map, ip);
sym = map__find_function(map, ip, symbol_filter);
} else {
@@ -183,10 +182,9 @@ got_map:
* the "[vdso]" dso, but for now lets use the old
* trick of looking in the whole kernel symbol list.
*/
- if ((long long)ip < 0) {
- map = kernel_map__functions;
- goto got_map;
- }
+ if ((long long)ip < 0)
+ sym = kernel_maps__find_function(ip, &map,
+ symbol_filter);
}
dump_printf(" ...... dso: %s\n",
map ? map->dso->long_name : "<not found>");
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index dc25231..0b8a298 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -36,6 +36,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
unsigned int symbol__priv_size;
static int vmlinux_path__nr_entries;
static char **vmlinux_path;
+static struct map *kernel_map__functions;
static struct symbol_conf symbol_conf__defaults = {
.use_modules = true,
@@ -1164,8 +1165,6 @@ out:
return ret;
}
-struct map *kernel_map__functions;
-
static void kernel_maps__insert(struct map *map)
{
maps__insert(&kernel_maps__functions, map);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 5d0371f..fb0be9e 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -105,6 +105,5 @@ size_t kernel_maps__fprintf(FILE *fp);
int symbol__init(struct symbol_conf *conf);
extern struct list_head dsos__user, dsos__kernel;
-extern struct map *kernel_map__functions;
extern struct dso *vdso;
#endif /* __PERF_SYMBOL */
--
1.6.2.5
From: Arnaldo Carvalho de Melo <[email protected]>
That way we will be able to check if the right symtab is loaded in the
underlying DSO.
Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-top.c | 2 +-
tools/perf/util/event.h | 12 +++++++++---
tools/perf/util/map.c | 12 +++++++-----
tools/perf/util/process_events.c | 2 +-
tools/perf/util/symbol.c | 31 +++++++++++++++++++++----------
tools/perf/util/symbol.h | 4 +++-
6 files changed, 42 insertions(+), 21 deletions(-)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ded6cf6..a0168f2 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -996,7 +996,7 @@ static void event__process_mmap(event_t *self)
struct thread *thread = threads__findnew(self->mmap.pid);
if (thread != NULL) {
- struct map *map = map__new(&self->mmap, NULL, 0);
+ struct map *map = map__new(&self->mmap, MAP__FUNCTION, NULL, 0);
if (map != NULL)
thread__insert_map(thread, map);
}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 882a953..29543bd 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -80,6 +80,10 @@ typedef union event_union {
struct sample_event sample;
} event_t;
+enum map_type {
+ MAP__FUNCTION,
+};
+
struct map {
union {
struct rb_node rb_node;
@@ -87,6 +91,7 @@ struct map {
};
u64 start;
u64 end;
+ enum map_type type;
u64 pgoff;
u64 (*map_ip)(struct map *, u64);
u64 (*unmap_ip)(struct map *, u64);
@@ -112,9 +117,10 @@ struct symbol;
typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
-void map__init(struct map *self, u64 start, u64 end, u64 pgoff,
- struct dso *dso);
-struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen);
+void map__init(struct map *self, enum map_type type,
+ u64 start, u64 end, u64 pgoff, struct dso *dso);
+struct map *map__new(struct mmap_event *event, enum map_type,
+ char *cwd, int cwdlen);
void map__delete(struct map *self);
struct map *map__clone(struct map *self);
int map__overlap(struct map *l, struct map *r);
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 41c5c4a..52bb4c6 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -20,9 +20,10 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
return n;
}
-void map__init(struct map *self, u64 start, u64 end, u64 pgoff,
- struct dso *dso)
+void map__init(struct map *self, enum map_type type,
+ u64 start, u64 end, u64 pgoff, struct dso *dso)
{
+ self->type = type;
self->start = start;
self->end = end;
self->pgoff = pgoff;
@@ -32,7 +33,8 @@ void map__init(struct map *self, u64 start, u64 end, u64 pgoff,
RB_CLEAR_NODE(&self->rb_node);
}
-struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen)
+struct map *map__new(struct mmap_event *event, enum map_type type,
+ char *cwd, int cwdlen)
{
struct map *self = malloc(sizeof(*self));
@@ -63,7 +65,7 @@ struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen)
if (dso == NULL)
goto out_delete;
- map__init(self, event->start, event->start + event->len,
+ map__init(self, type, event->start, event->start + event->len,
event->pgoff, dso);
if (self->dso == vdso || anon)
@@ -103,7 +105,7 @@ void map__fixup_end(struct map *self, struct rb_root *symbols)
struct symbol *map__find_function(struct map *self, u64 ip,
symbol_filter_t filter)
{
- if (!self->dso->loaded) {
+ if (!dso__loaded(self->dso, self->type)) {
int nr = dso__load(self->dso, self, filter);
if (nr < 0) {
diff --git a/tools/perf/util/process_events.c b/tools/perf/util/process_events.c
index a920436..5377868 100644
--- a/tools/perf/util/process_events.c
+++ b/tools/perf/util/process_events.c
@@ -6,7 +6,7 @@ int cwdlen;
int
process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
{
- struct map *map = map__new(&event->mmap, cwd, cwdlen);
+ struct map *map = map__new(&event->mmap, MAP__FUNCTION, cwd, cwdlen);
struct thread *thread = threads__findnew(event->mmap.pid);
dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 0b8a298..45a4a9a 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -29,7 +29,7 @@ enum dso_origin {
};
static void dsos__add(struct list_head *head, struct dso *dso);
-static struct map *map__new2(u64 start, struct dso *dso);
+static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
static void kernel_maps__insert(struct map *map);
static int dso__load_kernel_sym(struct dso *self, struct map *map,
symbol_filter_t filter);
@@ -45,6 +45,16 @@ static struct symbol_conf symbol_conf__defaults = {
static struct rb_root kernel_maps__functions;
+bool dso__loaded(const struct dso *self, enum map_type type)
+{
+ return self->loaded & (1 << type);
+}
+
+static void dso__set_loaded(struct dso *self, enum map_type type)
+{
+ self->loaded |= (1 << type);
+}
+
static void symbols__fixup_end(struct rb_root *self)
{
struct rb_node *nd, *prevnd = rb_first(self);
@@ -387,7 +397,7 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter)
if (dso == NULL)
return -1;
- map = map__new2(pos->start, dso);
+ map = map__new2(pos->start, dso, MAP__FUNCTION);
if (map == NULL) {
dso__delete(dso);
return -1;
@@ -846,7 +856,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
curr_dso = dso__new(dso_name);
if (curr_dso == NULL)
goto out_elf_end;
- curr_map = map__new2(start, curr_dso);
+ curr_map = map__new2(start, curr_dso,
+ MAP__FUNCTION);
if (curr_map == NULL) {
dso__delete(curr_dso);
goto out_elf_end;
@@ -1076,7 +1087,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
int ret = -1;
int fd;
- self->loaded = 1;
+ dso__set_loaded(self, map->type);
if (self->kernel)
return dso__load_kernel_sym(self, map, filter);
@@ -1275,7 +1286,7 @@ static int dsos__set_modules_path(void)
* they are loaded) and for vmlinux, where only after we load all the
* symbols we'll know where it starts and ends.
*/
-static struct map *map__new2(u64 start, struct dso *dso)
+static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
{
struct map *self = malloc(sizeof(*self));
@@ -1283,7 +1294,7 @@ static struct map *map__new2(u64 start, struct dso *dso)
/*
* ->end will be filled after we load all the symbols
*/
- map__init(self, start, 0, 0, dso);
+ map__init(self, type, start, 0, 0, dso);
}
return self;
@@ -1333,7 +1344,7 @@ static int kernel_maps__create_module_maps(void)
if (dso == NULL)
goto out_delete_line;
- map = map__new2(start, dso);
+ map = map__new2(start, dso, MAP__FUNCTION);
if (map == NULL) {
dso__delete(dso);
goto out_delete_line;
@@ -1394,7 +1405,7 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
if (fd < 0)
return -1;
- self->loaded = 1;
+ dso__set_loaded(self, map->type);
err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0);
close(fd);
@@ -1522,7 +1533,7 @@ static int kernel_maps__create_kernel_map(const struct symbol_conf *conf)
if (kernel == NULL)
return -1;
- kernel_map__functions = map__new2(0, kernel);
+ kernel_map__functions = map__new2(0, kernel, MAP__FUNCTION);
if (kernel_map__functions == NULL)
goto out_delete_kernel_dso;
@@ -1533,7 +1544,7 @@ static int kernel_maps__create_kernel_map(const struct symbol_conf *conf)
vdso = dso__new("[vdso]");
if (vdso == NULL)
goto out_delete_kernel_map;
- vdso->loaded = 1;
+ dso__set_loaded(vdso, MAP__FUNCTION);
if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
sizeof(kernel->build_id)) == 0)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index fb0be9e..11d4195 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -69,10 +69,10 @@ struct dso {
struct symbol *(*find_function)(struct dso *, u64 ip);
u8 adjust_symbols:1;
u8 slen_calculated:1;
- u8 loaded:1;
u8 has_build_id:1;
u8 kernel:1;
unsigned char origin;
+ u8 loaded;
u8 build_id[BUILD_ID_SIZE];
u16 long_name_len;
const char *short_name;
@@ -85,6 +85,8 @@ void dso__delete(struct dso *self);
struct symbol *dso__find_function(struct dso *self, u64 ip);
+bool dso__loaded(const struct dso *self, enum map_type type);
+
struct dso *dsos__findnew(const char *name);
int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
void dsos__fprintf(FILE *fp);
--
1.6.2.5
From: Arnaldo Carvalho de Melo <[email protected]>
By using an array of rb_roots in struct dso we can, from a struct map
instance to get the right symbol rb_tree more easily. This way we can
have just one symbol lookup method for struct map instances,
map__find_symbol, instead of one per symtab type (functions, variables).
Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-annotate.c | 2 +-
tools/perf/builtin-report.c | 2 +-
tools/perf/builtin-top.c | 2 +-
tools/perf/util/event.h | 12 +++++---
tools/perf/util/map.c | 12 +++++---
tools/perf/util/symbol.c | 59 +++++++++++++++++++++++++----------------
tools/perf/util/symbol.h | 7 ++---
7 files changed, 56 insertions(+), 40 deletions(-)
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 0846c8a..c32e760 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -170,7 +170,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
map = thread__find_map(thread, ip);
if (map != NULL) {
ip = map->map_ip(map, ip);
- sym = map__find_function(map, ip, symbol_filter);
+ sym = map__find_symbol(map, ip, symbol_filter);
} else {
/*
* If this is outside of all known maps,
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index e4b1004..400bef9 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -455,7 +455,7 @@ got_map:
dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
*ipp = ip;
- return map ? map__find_function(map, ip, NULL) : NULL;
+ return map ? map__find_symbol(map, ip, NULL) : NULL;
}
static int call__match(struct symbol *sym)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index a0168f2..abe78bb 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -948,7 +948,7 @@ static void event__process_sample(const event_t *self, int counter)
map = thread__find_map(thread, ip);
if (map != NULL) {
ip = map->map_ip(map, ip);
- sym = map__find_function(map, ip, symbol_filter);
+ sym = map__find_symbol(map, ip, symbol_filter);
if (sym == NULL)
return;
userspace_samples++;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 29543bd..3ae3c96 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -81,7 +81,9 @@ typedef union event_union {
} event_t;
enum map_type {
- MAP__FUNCTION,
+ MAP__FUNCTION = 0,
+
+ MAP__NR_TYPES,
};
struct map {
@@ -125,10 +127,10 @@ void map__delete(struct map *self);
struct map *map__clone(struct map *self);
int map__overlap(struct map *l, struct map *r);
size_t map__fprintf(struct map *self, FILE *fp);
-struct symbol *map__find_function(struct map *self, u64 ip,
- symbol_filter_t filter);
-void map__fixup_start(struct map *self, struct rb_root *symbols);
-void map__fixup_end(struct map *self, struct rb_root *symbols);
+struct symbol *map__find_symbol(struct map *self, u64 addr,
+ symbol_filter_t filter);
+void map__fixup_start(struct map *self);
+void map__fixup_end(struct map *self);
int event__synthesize_thread(pid_t pid, int (*process)(event_t *event));
void event__synthesize_threads(int (*process)(event_t *event));
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 52bb4c6..69f94fe 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -82,8 +82,9 @@ void map__delete(struct map *self)
free(self);
}
-void map__fixup_start(struct map *self, struct rb_root *symbols)
+void map__fixup_start(struct map *self)
{
+ struct rb_root *symbols = &self->dso->symbols[self->type];
struct rb_node *nd = rb_first(symbols);
if (nd != NULL) {
struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
@@ -91,8 +92,9 @@ void map__fixup_start(struct map *self, struct rb_root *symbols)
}
}
-void map__fixup_end(struct map *self, struct rb_root *symbols)
+void map__fixup_end(struct map *self)
{
+ struct rb_root *symbols = &self->dso->symbols[self->type];
struct rb_node *nd = rb_last(symbols);
if (nd != NULL) {
struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
@@ -102,8 +104,8 @@ void map__fixup_end(struct map *self, struct rb_root *symbols)
#define DSO__DELETED "(deleted)"
-struct symbol *map__find_function(struct map *self, u64 ip,
- symbol_filter_t filter)
+struct symbol *map__find_symbol(struct map *self, u64 addr,
+ symbol_filter_t filter)
{
if (!dso__loaded(self->dso, self->type)) {
int nr = dso__load(self->dso, self, filter);
@@ -138,7 +140,7 @@ struct symbol *map__find_function(struct map *self, u64 ip,
}
}
- return self->dso->find_function(self->dso, ip);
+ return self->dso->find_symbol(self->dso, self->type, addr);
}
struct map *map__clone(struct map *self)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 45a4a9a..9a2dd81 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -31,6 +31,7 @@ enum dso_origin {
static void dsos__add(struct list_head *head, struct dso *dso);
static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
static void kernel_maps__insert(struct map *map);
+struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
static int dso__load_kernel_sym(struct dso *self, struct map *map,
symbol_filter_t filter);
unsigned int symbol__priv_size;
@@ -151,11 +152,13 @@ struct dso *dso__new(const char *name)
struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
if (self != NULL) {
+ int i;
strcpy(self->name, name);
dso__set_long_name(self, self->name);
self->short_name = self->name;
- self->functions = RB_ROOT;
- self->find_function = dso__find_function;
+ for (i = 0; i < MAP__NR_TYPES; ++i)
+ self->symbols[i] = RB_ROOT;
+ self->find_symbol = dso__find_symbol;
self->slen_calculated = 0;
self->origin = DSO__ORIG_NOT_FOUND;
self->loaded = 0;
@@ -180,7 +183,9 @@ static void symbols__delete(struct rb_root *self)
void dso__delete(struct dso *self)
{
- symbols__delete(&self->functions);
+ int i;
+ for (i = 0; i < MAP__NR_TYPES; ++i)
+ symbols__delete(&self->symbols[i]);
if (self->long_name != self->name)
free(self->long_name);
free(self);
@@ -234,9 +239,9 @@ static struct symbol *symbols__find(struct rb_root *self, u64 ip)
return NULL;
}
-struct symbol *dso__find_function(struct dso *self, u64 ip)
+struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr)
{
- return symbols__find(&self->functions, ip);
+ return symbols__find(&self->symbols[type], addr);
}
int build_id__sprintf(u8 *self, int len, char *bf)
@@ -262,17 +267,25 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
return fprintf(fp, "%s", sbuild_id);
}
+static const char * map_type__name[MAP__NR_TYPES] = {
+ [MAP__FUNCTION] = "Functions",
+};
+
size_t dso__fprintf(struct dso *self, FILE *fp)
{
+ int i;
struct rb_node *nd;
size_t ret = fprintf(fp, "dso: %s (", self->short_name);
ret += dso__fprintf_buildid(self, fp);
- ret += fprintf(fp, ")\nFunctions:\n");
+ ret += fprintf(fp, ")\n");
+ for (i = 0; i < MAP__NR_TYPES; ++i) {
+ ret += fprintf(fp, "%s:\n", map_type__name[i]);
- for (nd = rb_first(&self->functions); nd; nd = rb_next(nd)) {
- struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
- ret += symbol__fprintf(pos, fp);
+ for (nd = rb_first(&self->symbols[i]); nd; nd = rb_next(nd)) {
+ struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+ ret += symbol__fprintf(pos, fp);
+ }
}
return ret;
@@ -335,7 +348,7 @@ static int kernel_maps__load_all_kallsyms(void)
* kernel_maps__split_kallsyms, when we have split the
* maps per module
*/
- symbols__insert(&kernel_map__functions->dso->functions, sym);
+ symbols__insert(&kernel_map__functions->dso->symbols[MAP__FUNCTION], sym);
}
free(line);
@@ -359,7 +372,7 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter)
struct map *map = kernel_map__functions;
struct symbol *pos;
int count = 0;
- struct rb_node *next = rb_first(&kernel_map__functions->dso->functions);
+ struct rb_node *next = rb_first(&kernel_map__functions->dso->symbols[map->type]);
int kernel_range = 0;
while (next) {
@@ -409,13 +422,13 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter)
}
if (filter && filter(map, pos)) {
- rb_erase(&pos->rb_node, &kernel_map__functions->dso->functions);
+ rb_erase(&pos->rb_node, &kernel_map__functions->dso->symbols[map->type]);
symbol__delete(pos);
} else {
if (map != kernel_map__functions) {
rb_erase(&pos->rb_node,
- &kernel_map__functions->dso->functions);
- symbols__insert(&map->dso->functions, pos);
+ &kernel_map__functions->dso->symbols[map->type]);
+ symbols__insert(&map->dso->symbols[map->type], pos);
}
count++;
}
@@ -430,7 +443,7 @@ static int kernel_maps__load_kallsyms(symbol_filter_t filter)
if (kernel_maps__load_all_kallsyms())
return -1;
- symbols__fixup_end(&kernel_map__functions->dso->functions);
+ symbols__fixup_end(&kernel_map__functions->dso->symbols[MAP__FUNCTION]);
kernel_map__functions->dso->origin = DSO__ORIG_KERNEL;
return kernel_maps__split_kallsyms(filter);
@@ -501,7 +514,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map,
if (filter && filter(map, sym))
symbol__delete(sym);
else {
- symbols__insert(&self->functions, sym);
+ symbols__insert(&self->symbols[map->type], sym);
nr_syms++;
}
}
@@ -699,7 +712,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
if (filter && filter(map, f))
symbol__delete(f);
else {
- symbols__insert(&self->functions, f);
+ symbols__insert(&self->symbols[map->type], f);
++nr;
}
}
@@ -721,7 +734,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
if (filter && filter(map, f))
symbol__delete(f);
else {
- symbols__insert(&self->functions, f);
+ symbols__insert(&self->symbols[map->type], f);
++nr;
}
}
@@ -896,7 +909,7 @@ new_symbol:
if (filter && filter(curr_map, f))
symbol__delete(f);
else {
- symbols__insert(&curr_dso->functions, f);
+ symbols__insert(&curr_dso->symbols[curr_map->type], f);
nr++;
}
}
@@ -905,7 +918,7 @@ new_symbol:
* For misannotated, zeroed, ASM function sizes.
*/
if (nr > 0)
- symbols__fixup_end(&self->functions);
+ symbols__fixup_end(&self->symbols[map->type]);
err = nr;
out_elf_end:
elf_end(elf);
@@ -1191,7 +1204,7 @@ struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp,
if (map) {
ip = map->map_ip(map, ip);
- return map__find_function(map, ip, filter);
+ return map__find_symbol(map, ip, filter);
} else
WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps__functions),
"Empty kernel_maps, was symbol__init() called?\n");
@@ -1453,8 +1466,8 @@ do_kallsyms:
if (err > 0) {
out_fixup:
- map__fixup_start(map, &map->dso->functions);
- map__fixup_end(map, &map->dso->functions);
+ map__fixup_start(map);
+ map__fixup_end(map);
}
return err;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 11d4195..8934814 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -65,8 +65,9 @@ static inline void *symbol__priv(struct symbol *self)
struct dso {
struct list_head node;
- struct rb_root functions;
- struct symbol *(*find_function)(struct dso *, u64 ip);
+ struct rb_root symbols[MAP__NR_TYPES];
+ struct symbol *(*find_symbol)(struct dso *self,
+ enum map_type type, u64 addr);
u8 adjust_symbols:1;
u8 slen_calculated:1;
u8 has_build_id:1;
@@ -83,8 +84,6 @@ struct dso {
struct dso *dso__new(const char *name);
void dso__delete(struct dso *self);
-struct symbol *dso__find_function(struct dso *self, u64 ip);
-
bool dso__loaded(const struct dso *self, enum map_type type);
struct dso *dsos__findnew(const char *name);
--
1.6.2.5
From: Arnaldo Carvalho de Melo <[email protected]>
So that the kallsyms loading routines are the direct counterpart of the
vmlinux loading ones, i.e. dso__load_kallsyms is the counterpart of
dso__load_vmlinux.
In the process make them also use the symbols rb tree indexed by
map->type, paving the way for supporting other types of symtabs, such as
the next one to be supported: variables.
This also allowed removal of yet another global variable:
kernel_map__functions.
Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/symbol.c | 77 ++++++++++++++++++++++-----------------------
1 files changed, 38 insertions(+), 39 deletions(-)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 9a2dd81..956656f 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -37,7 +37,6 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
unsigned int symbol__priv_size;
static int vmlinux_path__nr_entries;
static char **vmlinux_path;
-static struct map *kernel_map__functions;
static struct symbol_conf symbol_conf__defaults = {
.use_modules = true,
@@ -296,10 +295,11 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
* so that we can in the next step set the symbol ->end address and then
* call kernel_maps__split_kallsyms.
*/
-static int kernel_maps__load_all_kallsyms(void)
+static int dso__load_all_kallsyms(struct dso *self, struct map *map)
{
char *line = NULL;
size_t n;
+ struct rb_root *root = &self->symbols[map->type];
FILE *file = fopen("/proc/kallsyms", "r");
if (file == NULL)
@@ -342,13 +342,11 @@ static int kernel_maps__load_all_kallsyms(void)
if (sym == NULL)
goto out_delete_line;
-
/*
* We will pass the symbols to the filter later, in
- * kernel_maps__split_kallsyms, when we have split the
- * maps per module
+ * map__split_kallsyms, when we have split the maps per module
*/
- symbols__insert(&kernel_map__functions->dso->symbols[MAP__FUNCTION], sym);
+ symbols__insert(root, sym);
}
free(line);
@@ -367,12 +365,14 @@ out_failure:
* kernel range is broken in several maps, named [kernel].N, as we don't have
* the original ELF section names vmlinux have.
*/
-static int kernel_maps__split_kallsyms(symbol_filter_t filter)
+static int dso__split_kallsyms(struct dso *self, struct map *map,
+ symbol_filter_t filter)
{
- struct map *map = kernel_map__functions;
+ struct map *curr_map = map;
struct symbol *pos;
int count = 0;
- struct rb_node *next = rb_first(&kernel_map__functions->dso->symbols[map->type]);
+ struct rb_root *root = &self->symbols[map->type];
+ struct rb_node *next = rb_first(root);
int kernel_range = 0;
while (next) {
@@ -385,9 +385,9 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter)
if (module) {
*module++ = '\0';
- if (strcmp(map->dso->name, module)) {
- map = kernel_maps__find_by_dso_name(module);
- if (!map) {
+ if (strcmp(self->name, module)) {
+ curr_map = kernel_maps__find_by_dso_name(module);
+ if (curr_map == NULL) {
pr_err("/proc/{kallsyms,modules} "
"inconsistency!\n");
return -1;
@@ -397,9 +397,9 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter)
* So that we look just like we get from .ko files,
* i.e. not prelinked, relative to map->start.
*/
- pos->start = map->map_ip(map, pos->start);
- pos->end = map->map_ip(map, pos->end);
- } else if (map != kernel_map__functions) {
+ pos->start = curr_map->map_ip(curr_map, pos->start);
+ pos->end = curr_map->map_ip(curr_map, pos->end);
+ } else if (curr_map != map) {
char dso_name[PATH_MAX];
struct dso *dso;
@@ -410,25 +410,24 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter)
if (dso == NULL)
return -1;
- map = map__new2(pos->start, dso, MAP__FUNCTION);
+ curr_map = map__new2(pos->start, dso, map->type);
if (map == NULL) {
dso__delete(dso);
return -1;
}
- map->map_ip = map->unmap_ip = identity__map_ip;
- kernel_maps__insert(map);
+ curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
+ kernel_maps__insert(curr_map);
++kernel_range;
}
- if (filter && filter(map, pos)) {
- rb_erase(&pos->rb_node, &kernel_map__functions->dso->symbols[map->type]);
+ if (filter && filter(curr_map, pos)) {
+ rb_erase(&pos->rb_node, root);
symbol__delete(pos);
} else {
- if (map != kernel_map__functions) {
- rb_erase(&pos->rb_node,
- &kernel_map__functions->dso->symbols[map->type]);
- symbols__insert(&map->dso->symbols[map->type], pos);
+ if (curr_map != map) {
+ rb_erase(&pos->rb_node, root);
+ symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
}
count++;
}
@@ -438,15 +437,16 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter)
}
-static int kernel_maps__load_kallsyms(symbol_filter_t filter)
+static int dso__load_kallsyms(struct dso *self, struct map *map,
+ symbol_filter_t filter)
{
- if (kernel_maps__load_all_kallsyms())
+ if (dso__load_all_kallsyms(self, map) < 0)
return -1;
- symbols__fixup_end(&kernel_map__functions->dso->symbols[MAP__FUNCTION]);
- kernel_map__functions->dso->origin = DSO__ORIG_KERNEL;
+ symbols__fixup_end(&self->symbols[map->type]);
+ self->origin = DSO__ORIG_KERNEL;
- return kernel_maps__split_kallsyms(filter);
+ return dso__split_kallsyms(self, map, filter);
}
size_t kernel_maps__fprintf(FILE *fp)
@@ -1457,9 +1457,8 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
if (err <= 0) {
pr_info("The file %s cannot be used, "
"trying to use /proc/kallsyms...", self->long_name);
- sleep(2);
do_kallsyms:
- err = kernel_maps__load_kallsyms(filter);
+ err = dso__load_kallsyms(self, map, filter);
if (err > 0 && !is_kallsyms)
dso__set_long_name(self, strdup("[kernel.kallsyms]"));
}
@@ -1541,18 +1540,19 @@ size_t dsos__fprintf_buildid(FILE *fp)
static int kernel_maps__create_kernel_map(const struct symbol_conf *conf)
{
+ struct map *kmap;
struct dso *kernel = dso__new(conf->vmlinux_name ?: "[kernel.kallsyms]");
if (kernel == NULL)
return -1;
- kernel_map__functions = map__new2(0, kernel, MAP__FUNCTION);
- if (kernel_map__functions == NULL)
+ kmap = map__new2(0, kernel, MAP__FUNCTION);
+ if (kmap == NULL)
goto out_delete_kernel_dso;
- kernel_map__functions->map_ip = kernel_map__functions->unmap_ip = identity__map_ip;
- kernel->short_name = "[kernel]";
- kernel->kernel = 1;
+ kmap->map_ip = kmap->unmap_ip = identity__map_ip;
+ kernel->short_name = "[kernel]";
+ kernel->kernel = 1;
vdso = dso__new("[vdso]");
if (vdso == NULL)
@@ -1563,15 +1563,14 @@ static int kernel_maps__create_kernel_map(const struct symbol_conf *conf)
sizeof(kernel->build_id)) == 0)
kernel->has_build_id = true;
- kernel_maps__insert(kernel_map__functions);
+ kernel_maps__insert(kmap);
dsos__add(&dsos__kernel, kernel);
dsos__add(&dsos__user, vdso);
return 0;
out_delete_kernel_map:
- map__delete(kernel_map__functions);
- kernel_map__functions = NULL;
+ map__delete(kmap);
out_delete_kernel_dso:
dso__delete(kernel);
return -1;
--
1.6.2.5
From: Arnaldo Carvalho de Melo <[email protected]>
So that we can support multiple symbol table types.
Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/symbol.c | 51 ++++++++++++++++++++++++++++++++++-----------
tools/perf/util/thread.h | 1 -
2 files changed, 38 insertions(+), 14 deletions(-)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 956656f..581db4c 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -29,6 +29,7 @@ enum dso_origin {
};
static void dsos__add(struct list_head *head, struct dso *dso);
+static struct map *kernel_maps__find_by_dso_name(const char *name);
static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
static void kernel_maps__insert(struct map *map);
struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
@@ -43,7 +44,7 @@ static struct symbol_conf symbol_conf__defaults = {
.try_vmlinux_path = true,
};
-static struct rb_root kernel_maps__functions;
+static struct rb_root kernel_maps[MAP__NR_TYPES];
bool dso__loaded(const struct dso *self, enum map_type type)
{
@@ -78,10 +79,10 @@ static void symbols__fixup_end(struct rb_root *self)
curr->end = roundup(curr->start, 4096);
}
-static void kernel_maps__fixup_end(void)
+static void __kernel_maps__fixup_end(struct rb_root *root)
{
struct map *prev, *curr;
- struct rb_node *nd, *prevnd = rb_first(&kernel_maps__functions);
+ struct rb_node *nd, *prevnd = rb_first(root);
if (prevnd == NULL)
return;
@@ -101,6 +102,13 @@ static void kernel_maps__fixup_end(void)
curr->end = ~0UL;
}
+static void kernel_maps__fixup_end(void)
+{
+ int i;
+ for (i = 0; i < MAP__NR_TYPES; ++i)
+ __kernel_maps__fixup_end(&kernel_maps[i]);
+}
+
static struct symbol *symbol__new(u64 start, u64 len, const char *name)
{
size_t namelen = strlen(name) + 1;
@@ -449,12 +457,12 @@ static int dso__load_kallsyms(struct dso *self, struct map *map,
return dso__split_kallsyms(self, map, filter);
}
-size_t kernel_maps__fprintf(FILE *fp)
+static size_t __kernel_maps__fprintf(enum map_type type, FILE *fp)
{
- size_t printed = fprintf(fp, "Kernel maps:\n");
+ size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
struct rb_node *nd;
- for (nd = rb_first(&kernel_maps__functions); nd; nd = rb_next(nd)) {
+ for (nd = rb_first(&kernel_maps[type]); nd; nd = rb_next(nd)) {
struct map *pos = rb_entry(nd, struct map, rb_node);
printed += fprintf(fp, "Map:");
@@ -465,6 +473,16 @@ size_t kernel_maps__fprintf(FILE *fp)
}
}
+ return printed;
+}
+
+size_t kernel_maps__fprintf(FILE *fp)
+{
+ size_t printed = fprintf(fp, "Kernel maps:\n");
+ int i;
+ for (i = 0; i < MAP__NR_TYPES; ++i)
+ printed += __kernel_maps__fprintf(i, fp);
+
return printed + fprintf(fp, "END kernel maps\n");
}
@@ -1191,13 +1209,14 @@ out:
static void kernel_maps__insert(struct map *map)
{
- maps__insert(&kernel_maps__functions, map);
+ maps__insert(&kernel_maps[map->type], map);
}
-struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp,
- symbol_filter_t filter)
+static struct symbol *kernel_maps__find_symbol(u64 ip, enum map_type type,
+ struct map **mapp,
+ symbol_filter_t filter)
{
- struct map *map = maps__find(&kernel_maps__functions, ip);
+ struct map *map = maps__find(&kernel_maps[type], ip);
if (mapp)
*mapp = map;
@@ -1206,17 +1225,23 @@ struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp,
ip = map->map_ip(map, ip);
return map__find_symbol(map, ip, filter);
} else
- WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps__functions),
+ WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps[type]),
"Empty kernel_maps, was symbol__init() called?\n");
return NULL;
}
-struct map *kernel_maps__find_by_dso_name(const char *name)
+struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp,
+ symbol_filter_t filter)
+{
+ return kernel_maps__find_symbol(ip, MAP__FUNCTION, mapp, filter);
+}
+
+static struct map *kernel_maps__find_by_dso_name(const char *name)
{
struct rb_node *nd;
- for (nd = rb_first(&kernel_maps__functions); nd; nd = rb_next(nd)) {
+ for (nd = rb_first(&kernel_maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
struct map *map = rb_entry(nd, struct map, rb_node);
if (map->dso && strcmp(map->dso->name, name) == 0)
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 74cba64..54580bb 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -28,7 +28,6 @@ struct map *maps__find(struct rb_root *maps, u64 ip);
struct symbol *kernel_maps__find_function(const u64 ip, struct map **mapp,
symbol_filter_t filter);
-struct map *kernel_maps__find_by_dso_name(const char *name);
static inline struct map *thread__find_map(struct thread *self, u64 ip)
{
--
1.6.2.5
From: Arnaldo Carvalho de Melo <[email protected]>
Making the routines that were so far specific to the kernel maps useful
for all threads.
This is done by making the kernel maps be contained in a kernel
"thread".
This gets the kernel specific routines closer to the userspace
counterparts, which will help in reducing the boilerplate for resolving
a symbol, as will be demonstrated in the next patches.
Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-annotate.c | 2 +-
tools/perf/builtin-report.c | 2 +-
tools/perf/builtin-top.c | 2 +-
tools/perf/util/symbol.c | 157 +++++++++++++++--------------------------
tools/perf/util/symbol.h | 2 +-
tools/perf/util/thread.c | 115 +++++++++++++++++++++++-------
tools/perf/util/thread.h | 15 +++-
7 files changed, 162 insertions(+), 133 deletions(-)
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index c32e760..3ebd70b 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -167,7 +167,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
map ? map->dso->long_name : "<not found>");
} else if (event->header.misc & PERF_RECORD_MISC_USER) {
level = '.';
- map = thread__find_map(thread, ip);
+ map = thread__find_map(thread, MAP__FUNCTION, ip);
if (map != NULL) {
ip = map->map_ip(map, ip);
sym = map__find_symbol(map, ip, symbol_filter);
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 400bef9..9bd20c2 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -422,7 +422,7 @@ resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
if (!thread)
return NULL;
- map = thread__find_map(thread, ip);
+ map = thread__find_map(thread, MAP__FUNCTION, ip);
if (map != NULL) {
/*
* We have to do this here as we may have a dso
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index abe78bb..bf6730c 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -945,7 +945,7 @@ static void event__process_sample(const event_t *self, int counter)
if (thread == NULL)
return;
- map = thread__find_map(thread, ip);
+ map = thread__find_map(thread, MAP__FUNCTION, ip);
if (map != NULL) {
ip = map->map_ip(map, ip);
sym = map__find_symbol(map, ip, symbol_filter);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 581db4c..b6a2941 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -29,12 +29,11 @@ enum dso_origin {
};
static void dsos__add(struct list_head *head, struct dso *dso);
-static struct map *kernel_maps__find_by_dso_name(const char *name);
+static struct map *thread__find_map_by_name(struct thread *self, char *name);
static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
-static void kernel_maps__insert(struct map *map);
struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
static int dso__load_kernel_sym(struct dso *self, struct map *map,
- symbol_filter_t filter);
+ struct thread *thread, symbol_filter_t filter);
unsigned int symbol__priv_size;
static int vmlinux_path__nr_entries;
static char **vmlinux_path;
@@ -44,7 +43,7 @@ static struct symbol_conf symbol_conf__defaults = {
.try_vmlinux_path = true,
};
-static struct rb_root kernel_maps[MAP__NR_TYPES];
+static struct thread kthread_mem, *kthread = &kthread_mem;
bool dso__loaded(const struct dso *self, enum map_type type)
{
@@ -79,10 +78,10 @@ static void symbols__fixup_end(struct rb_root *self)
curr->end = roundup(curr->start, 4096);
}
-static void __kernel_maps__fixup_end(struct rb_root *root)
+static void __thread__fixup_maps_end(struct thread *self, enum map_type type)
{
struct map *prev, *curr;
- struct rb_node *nd, *prevnd = rb_first(root);
+ struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
if (prevnd == NULL)
return;
@@ -102,11 +101,11 @@ static void __kernel_maps__fixup_end(struct rb_root *root)
curr->end = ~0UL;
}
-static void kernel_maps__fixup_end(void)
+static void thread__fixup_maps_end(struct thread *self)
{
int i;
for (i = 0; i < MAP__NR_TYPES; ++i)
- __kernel_maps__fixup_end(&kernel_maps[i]);
+ __thread__fixup_maps_end(self, i);
}
static struct symbol *symbol__new(u64 start, u64 len, const char *name)
@@ -274,25 +273,16 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
return fprintf(fp, "%s", sbuild_id);
}
-static const char * map_type__name[MAP__NR_TYPES] = {
- [MAP__FUNCTION] = "Functions",
-};
-
-size_t dso__fprintf(struct dso *self, FILE *fp)
+size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
{
- int i;
struct rb_node *nd;
size_t ret = fprintf(fp, "dso: %s (", self->short_name);
ret += dso__fprintf_buildid(self, fp);
ret += fprintf(fp, ")\n");
- for (i = 0; i < MAP__NR_TYPES; ++i) {
- ret += fprintf(fp, "%s:\n", map_type__name[i]);
-
- for (nd = rb_first(&self->symbols[i]); nd; nd = rb_next(nd)) {
- struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
- ret += symbol__fprintf(pos, fp);
- }
+ for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
+ struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+ ret += symbol__fprintf(pos, fp);
}
return ret;
@@ -373,7 +363,7 @@ out_failure:
* kernel range is broken in several maps, named [kernel].N, as we don't have
* the original ELF section names vmlinux have.
*/
-static int dso__split_kallsyms(struct dso *self, struct map *map,
+static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread,
symbol_filter_t filter)
{
struct map *curr_map = map;
@@ -394,10 +384,10 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
*module++ = '\0';
if (strcmp(self->name, module)) {
- curr_map = kernel_maps__find_by_dso_name(module);
+ curr_map = thread__find_map_by_name(thread, module);
if (curr_map == NULL) {
- pr_err("/proc/{kallsyms,modules} "
- "inconsistency!\n");
+ pr_debug("/proc/{kallsyms,modules} "
+ "inconsistency!\n");
return -1;
}
}
@@ -425,7 +415,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
}
curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
- kernel_maps__insert(curr_map);
+ __thread__insert_map(thread, curr_map);
++kernel_range;
}
@@ -446,7 +436,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
static int dso__load_kallsyms(struct dso *self, struct map *map,
- symbol_filter_t filter)
+ struct thread *thread, symbol_filter_t filter)
{
if (dso__load_all_kallsyms(self, map) < 0)
return -1;
@@ -454,35 +444,13 @@ static int dso__load_kallsyms(struct dso *self, struct map *map,
symbols__fixup_end(&self->symbols[map->type]);
self->origin = DSO__ORIG_KERNEL;
- return dso__split_kallsyms(self, map, filter);
-}
-
-static size_t __kernel_maps__fprintf(enum map_type type, FILE *fp)
-{
- size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
- struct rb_node *nd;
-
- for (nd = rb_first(&kernel_maps[type]); nd; nd = rb_next(nd)) {
- struct map *pos = rb_entry(nd, struct map, rb_node);
-
- printed += fprintf(fp, "Map:");
- printed += map__fprintf(pos, fp);
- if (verbose > 1) {
- printed += dso__fprintf(pos->dso, fp);
- printed += fprintf(fp, "--\n");
- }
- }
-
- return printed;
+ return dso__split_kallsyms(self, map, thread, filter);
}
size_t kernel_maps__fprintf(FILE *fp)
{
size_t printed = fprintf(fp, "Kernel maps:\n");
- int i;
- for (i = 0; i < MAP__NR_TYPES; ++i)
- printed += __kernel_maps__fprintf(i, fp);
-
+ printed += thread__fprintf_maps(kthread, fp);
return printed + fprintf(fp, "END kernel maps\n");
}
@@ -772,9 +740,9 @@ out:
return 0;
}
-static int dso__load_sym(struct dso *self, struct map *map, const char *name,
- int fd, symbol_filter_t filter, int kernel,
- int kmodule)
+static int dso__load_sym(struct dso *self, struct map *map,
+ struct thread *thread, const char *name, int fd,
+ symbol_filter_t filter, int kernel, int kmodule)
{
struct map *curr_map = map;
struct dso *curr_dso = self;
@@ -877,7 +845,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
snprintf(dso_name, sizeof(dso_name),
"%s%s", self->short_name, section_name);
- curr_map = kernel_maps__find_by_dso_name(dso_name);
+ curr_map = thread__find_map_by_name(thread, dso_name);
if (curr_map == NULL) {
u64 start = sym.st_value;
@@ -896,7 +864,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
curr_map->map_ip = identity__map_ip;
curr_map->unmap_ip = identity__map_ip;
curr_dso->origin = DSO__ORIG_KERNEL;
- kernel_maps__insert(curr_map);
+ __thread__insert_map(kthread, curr_map);
dsos__add(&dsos__kernel, curr_dso);
} else
curr_dso = curr_map->dso;
@@ -1121,7 +1089,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
dso__set_loaded(self, map->type);
if (self->kernel)
- return dso__load_kernel_sym(self, map, filter);
+ return dso__load_kernel_sym(self, map, kthread, filter);
name = malloc(size);
if (!name)
@@ -1186,7 +1154,7 @@ compare_build_id:
fd = open(name, O_RDONLY);
} while (fd < 0);
- ret = dso__load_sym(self, map, name, fd, filter, 0, 0);
+ ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0);
close(fd);
/*
@@ -1207,16 +1175,11 @@ out:
return ret;
}
-static void kernel_maps__insert(struct map *map)
-{
- maps__insert(&kernel_maps[map->type], map);
-}
-
-static struct symbol *kernel_maps__find_symbol(u64 ip, enum map_type type,
- struct map **mapp,
- symbol_filter_t filter)
+static struct symbol *thread__find_symbol(struct thread *self, u64 ip,
+ enum map_type type, struct map **mapp,
+ symbol_filter_t filter)
{
- struct map *map = maps__find(&kernel_maps[type], ip);
+ struct map *map = thread__find_map(self, type, ip);
if (mapp)
*mapp = map;
@@ -1224,9 +1187,7 @@ static struct symbol *kernel_maps__find_symbol(u64 ip, enum map_type type,
if (map) {
ip = map->map_ip(map, ip);
return map__find_symbol(map, ip, filter);
- } else
- WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps[type]),
- "Empty kernel_maps, was symbol__init() called?\n");
+ }
return NULL;
}
@@ -1234,14 +1195,14 @@ static struct symbol *kernel_maps__find_symbol(u64 ip, enum map_type type,
struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp,
symbol_filter_t filter)
{
- return kernel_maps__find_symbol(ip, MAP__FUNCTION, mapp, filter);
+ return thread__find_symbol(kthread, ip, MAP__FUNCTION, mapp, filter);
}
-static struct map *kernel_maps__find_by_dso_name(const char *name)
+static struct map *thread__find_map_by_name(struct thread *self, char *name)
{
struct rb_node *nd;
- for (nd = rb_first(&kernel_maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
+ for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
struct map *map = rb_entry(nd, struct map, rb_node);
if (map->dso && strcmp(map->dso->name, name) == 0)
@@ -1285,7 +1246,7 @@ static int dsos__set_modules_path_dir(char *dirname)
(int)(dot - dent->d_name), dent->d_name);
strxfrchar(dso_name, '-', '_');
- map = kernel_maps__find_by_dso_name(dso_name);
+ map = thread__find_map_by_name(kthread, dso_name);
if (map == NULL)
continue;
@@ -1338,7 +1299,7 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
return self;
}
-static int kernel_maps__create_module_maps(void)
+static int thread__create_module_maps(struct thread *self)
{
char *line = NULL;
size_t n;
@@ -1395,7 +1356,7 @@ static int kernel_maps__create_module_maps(void)
dso->has_build_id = true;
dso->origin = DSO__ORIG_KMODULE;
- kernel_maps__insert(map);
+ __thread__insert_map(self, map);
dsos__add(&dsos__kernel, dso);
}
@@ -1410,7 +1371,7 @@ out_failure:
return -1;
}
-static int dso__load_vmlinux(struct dso *self, struct map *map,
+static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread,
const char *vmlinux, symbol_filter_t filter)
{
int err = -1, fd;
@@ -1444,15 +1405,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
return -1;
dso__set_loaded(self, map->type);
- err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0);
-
+ err = dso__load_sym(self, map, thread, self->long_name, fd, filter, 1, 0);
close(fd);
return err;
}
static int dso__load_kernel_sym(struct dso *self, struct map *map,
- symbol_filter_t filter)
+ struct thread *thread, symbol_filter_t filter)
{
int err;
bool is_kallsyms;
@@ -1462,8 +1422,8 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
pr_debug("Looking at the vmlinux_path (%d entries long)\n",
vmlinux_path__nr_entries);
for (i = 0; i < vmlinux_path__nr_entries; ++i) {
- err = dso__load_vmlinux(self, map, vmlinux_path[i],
- filter);
+ err = dso__load_vmlinux(self, map, thread,
+ vmlinux_path[i], filter);
if (err > 0) {
pr_debug("Using %s for symbols\n",
vmlinux_path[i]);
@@ -1478,12 +1438,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
if (is_kallsyms)
goto do_kallsyms;
- err = dso__load_vmlinux(self, map, self->long_name, filter);
+ err = dso__load_vmlinux(self, map, thread, self->long_name, filter);
if (err <= 0) {
pr_info("The file %s cannot be used, "
"trying to use /proc/kallsyms...", self->long_name);
do_kallsyms:
- err = dso__load_kallsyms(self, map, filter);
+ err = dso__load_kallsyms(self, map, thread, filter);
if (err > 0 && !is_kallsyms)
dso__set_long_name(self, strdup("[kernel.kallsyms]"));
}
@@ -1535,8 +1495,11 @@ static void __dsos__fprintf(struct list_head *head, FILE *fp)
{
struct dso *pos;
- list_for_each_entry(pos, head, node)
- dso__fprintf(pos, fp);
+ list_for_each_entry(pos, head, node) {
+ int i;
+ for (i = 0; i < MAP__NR_TYPES; ++i)
+ dso__fprintf(pos, i, fp);
+ }
}
void dsos__fprintf(FILE *fp)
@@ -1563,10 +1526,10 @@ size_t dsos__fprintf_buildid(FILE *fp)
__dsos__fprintf_buildid(&dsos__user, fp));
}
-static int kernel_maps__create_kernel_map(const struct symbol_conf *conf)
+static int thread__create_kernel_map(struct thread *self, const char *vmlinux)
{
struct map *kmap;
- struct dso *kernel = dso__new(conf->vmlinux_name ?: "[kernel.kallsyms]");
+ struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
if (kernel == NULL)
return -1;
@@ -1588,7 +1551,7 @@ static int kernel_maps__create_kernel_map(const struct symbol_conf *conf)
sizeof(kernel->build_id)) == 0)
kernel->has_build_id = true;
- kernel_maps__insert(kmap);
+ __thread__insert_map(self, kmap);
dsos__add(&dsos__kernel, kernel);
dsos__add(&dsos__user, vdso);
@@ -1656,32 +1619,28 @@ out_fail:
return -1;
}
-static int kernel_maps__init(const struct symbol_conf *conf)
+int symbol__init(struct symbol_conf *conf)
{
const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults;
+ elf_version(EV_CURRENT);
symbol__priv_size = pconf->priv_size;
+ thread__init(kthread, 0);
if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
return -1;
- if (kernel_maps__create_kernel_map(pconf) < 0) {
+ if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) {
vmlinux_path__exit();
return -1;
}
- if (pconf->use_modules && kernel_maps__create_module_maps() < 0)
+ if (pconf->use_modules && thread__create_module_maps(kthread) < 0)
pr_debug("Failed to load list of modules in use, "
"continuing...\n");
/*
* Now that we have all the maps created, just set the ->end of them:
*/
- kernel_maps__fixup_end();
+ thread__fixup_maps_end(kthread);
return 0;
}
-
-int symbol__init(struct symbol_conf *conf)
-{
- elf_version(EV_CURRENT);
- return kernel_maps__init(conf);
-}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 8934814..3f9e4a4 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -92,7 +92,7 @@ void dsos__fprintf(FILE *fp);
size_t dsos__fprintf_buildid(FILE *fp);
size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
-size_t dso__fprintf(struct dso *self, FILE *fp);
+size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
char dso__symtab_origin(const struct dso *self);
void dso__set_build_id(struct dso *self, void *build_id);
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 1796625..2229f82 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -9,17 +9,26 @@
static struct rb_root threads;
static struct thread *last_match;
+void thread__init(struct thread *self, pid_t pid)
+{
+ int i;
+ self->pid = pid;
+ self->comm = NULL;
+ for (i = 0; i < MAP__NR_TYPES; ++i) {
+ self->maps[i] = RB_ROOT;
+ INIT_LIST_HEAD(&self->removed_maps[i]);
+ }
+}
+
static struct thread *thread__new(pid_t pid)
{
struct thread *self = zalloc(sizeof(*self));
if (self != NULL) {
- self->pid = pid;
+ thread__init(self, pid);
self->comm = malloc(32);
if (self->comm)
snprintf(self->comm, 32, ":%d", self->pid);
- self->maps = RB_ROOT;
- INIT_LIST_HEAD(&self->removed_maps);
}
return self;
@@ -44,24 +53,68 @@ int thread__comm_len(struct thread *self)
return self->comm_len;
}
-static size_t thread__fprintf(struct thread *self, FILE *fp)
+static const char *map_type__name[MAP__NR_TYPES] = {
+ [MAP__FUNCTION] = "Functions",
+};
+
+static size_t __thread__fprintf_maps(struct thread *self,
+ enum map_type type, FILE *fp)
{
+ size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
struct rb_node *nd;
- struct map *pos;
- size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n",
- self->pid, self->comm);
- for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) {
- pos = rb_entry(nd, struct map, rb_node);
- ret += map__fprintf(pos, fp);
+ for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
+ struct map *pos = rb_entry(nd, struct map, rb_node);
+ printed += fprintf(fp, "Map:");
+ printed += map__fprintf(pos, fp);
+ if (verbose > 1) {
+ printed += dso__fprintf(pos->dso, type, fp);
+ printed += fprintf(fp, "--\n");
+ }
}
- ret = fprintf(fp, "Removed maps:\n");
+ return printed;
+}
+
+size_t thread__fprintf_maps(struct thread *self, FILE *fp)
+{
+ size_t printed = 0, i;
+ for (i = 0; i < MAP__NR_TYPES; ++i)
+ printed += __thread__fprintf_maps(self, i, fp);
+ return printed;
+}
- list_for_each_entry(pos, &self->removed_maps, node)
- ret += map__fprintf(pos, fp);
+static size_t __thread__fprintf_removed_maps(struct thread *self,
+ enum map_type type, FILE *fp)
+{
+ struct map *pos;
+ size_t printed = 0;
+
+ list_for_each_entry(pos, &self->removed_maps[type], node) {
+ printed += fprintf(fp, "Map:");
+ printed += map__fprintf(pos, fp);
+ if (verbose > 1) {
+ printed += dso__fprintf(pos->dso, type, fp);
+ printed += fprintf(fp, "--\n");
+ }
+ }
+ return printed;
+}
- return ret;
+static size_t thread__fprintf_removed_maps(struct thread *self, FILE *fp)
+{
+ size_t printed = 0, i;
+ for (i = 0; i < MAP__NR_TYPES; ++i)
+ printed += __thread__fprintf_removed_maps(self, i, fp);
+ return printed;
+}
+
+static size_t thread__fprintf(struct thread *self, FILE *fp)
+{
+ size_t printed = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
+ printed += thread__fprintf_removed_maps(self, fp);
+ printed += fprintf(fp, "Removed maps:\n");
+ return printed + thread__fprintf_removed_maps(self, fp);
}
struct thread *threads__findnew(pid_t pid)
@@ -117,7 +170,8 @@ struct thread *register_idle_thread(void)
static void thread__remove_overlappings(struct thread *self, struct map *map)
{
- struct rb_node *next = rb_first(&self->maps);
+ struct rb_root *root = &self->maps[map->type];
+ struct rb_node *next = rb_first(root);
while (next) {
struct map *pos = rb_entry(next, struct map, rb_node);
@@ -132,13 +186,13 @@ static void thread__remove_overlappings(struct thread *self, struct map *map)
map__fprintf(pos, stderr);
}
- rb_erase(&pos->rb_node, &self->maps);
+ rb_erase(&pos->rb_node, root);
/*
* We may have references to this map, for instance in some
* hist_entry instances, so just move them to a separate
* list.
*/
- list_add_tail(&pos->node, &self->removed_maps);
+ list_add_tail(&pos->node, &self->removed_maps[map->type]);
}
}
@@ -185,12 +239,26 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
void thread__insert_map(struct thread *self, struct map *map)
{
thread__remove_overlappings(self, map);
- maps__insert(&self->maps, map);
+ maps__insert(&self->maps[map->type], map);
}
-int thread__fork(struct thread *self, struct thread *parent)
+static int thread__clone_maps(struct thread *self, struct thread *parent,
+ enum map_type type)
{
struct rb_node *nd;
+ for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
+ struct map *map = rb_entry(nd, struct map, rb_node);
+ struct map *new = map__clone(map);
+ if (new == NULL)
+ return -ENOMEM;
+ thread__insert_map(self, new);
+ }
+ return 0;
+}
+
+int thread__fork(struct thread *self, struct thread *parent)
+{
+ int i;
if (self->comm)
free(self->comm);
@@ -198,14 +266,9 @@ int thread__fork(struct thread *self, struct thread *parent)
if (!self->comm)
return -ENOMEM;
- for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) {
- struct map *map = rb_entry(nd, struct map, rb_node);
- struct map *new = map__clone(map);
- if (!new)
+ for (i = 0; i < MAP__NR_TYPES; ++i)
+ if (thread__clone_maps(self, parent, i) < 0)
return -ENOMEM;
- thread__insert_map(self, new);
- }
-
return 0;
}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 54580bb..3bdd9b2 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -7,20 +7,22 @@
struct thread {
struct rb_node rb_node;
- struct rb_root maps;
- struct list_head removed_maps;
+ struct rb_root maps[MAP__NR_TYPES];
+ struct list_head removed_maps[MAP__NR_TYPES];
pid_t pid;
char shortname[3];
char *comm;
int comm_len;
};
+void thread__init(struct thread *self, pid_t pid);
int thread__set_comm(struct thread *self, const char *comm);
int thread__comm_len(struct thread *self);
struct thread *threads__findnew(pid_t pid);
struct thread *register_idle_thread(void);
void thread__insert_map(struct thread *self, struct map *map);
int thread__fork(struct thread *self, struct thread *parent);
+size_t thread__fprintf_maps(struct thread *self, FILE *fp);
size_t threads__fprintf(FILE *fp);
void maps__insert(struct rb_root *maps, struct map *map);
@@ -29,9 +31,14 @@ struct map *maps__find(struct rb_root *maps, u64 ip);
struct symbol *kernel_maps__find_function(const u64 ip, struct map **mapp,
symbol_filter_t filter);
-static inline struct map *thread__find_map(struct thread *self, u64 ip)
+static inline struct map *thread__find_map(struct thread *self,
+ enum map_type type, u64 ip)
{
- return self ? maps__find(&self->maps, ip) : NULL;
+ return self ? maps__find(&self->maps[type], ip) : NULL;
}
+static inline void __thread__insert_map(struct thread *self, struct map *map)
+{
+ maps__insert(&self->maps[map->type], map);
+}
#endif /* __PERF_THREAD_H */
--
1.6.2.5
From: Arnaldo Carvalho de Melo <[email protected]>
Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/symbol.c | 6 +++++-
tools/perf/util/thread.h | 1 +
2 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index b6a2941..b788c2f 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -381,6 +381,9 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread
module = strchr(pos->name, '\t');
if (module) {
+ if (!thread->use_modules)
+ goto discard_symbol;
+
*module++ = '\0';
if (strcmp(self->name, module)) {
@@ -420,7 +423,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread
}
if (filter && filter(curr_map, pos)) {
- rb_erase(&pos->rb_node, root);
+discard_symbol: rb_erase(&pos->rb_node, root);
symbol__delete(pos);
} else {
if (curr_map != map) {
@@ -1635,6 +1638,7 @@ int symbol__init(struct symbol_conf *conf)
return -1;
}
+ kthread->use_modules = pconf->use_modules;
if (pconf->use_modules && thread__create_module_maps(kthread) < 0)
pr_debug("Failed to load list of modules in use, "
"continuing...\n");
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 3bdd9b2..59b0d9b 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -10,6 +10,7 @@ struct thread {
struct rb_root maps[MAP__NR_TYPES];
struct list_head removed_maps[MAP__NR_TYPES];
pid_t pid;
+ bool use_modules;
char shortname[3];
char *comm;
int comm_len;
--
1.6.2.5
From: Arnaldo Carvalho de Melo <[email protected]>
While implementing event__preprocess_sample, that will do all of the
symbol lookup in one convenient function, I noticed that
util/process_event.[ch] were not being used at all, then started looking
if there were other functions that could be shared and...
All those functions really don't need to receive offset + head, the only
thing they did was common to all of them, so do it at one place instead.
Stats about number of each type of event processed now is done in a
central place.
Cc: Frédéric Weisbecker <[email protected]>
Cc: John Kacur <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Makefile | 2 -
tools/perf/builtin-annotate.c | 63 ++++++++------------------------
tools/perf/builtin-kmem.c | 33 ++---------------
tools/perf/builtin-report.c | 72 ++++++++++---------------------------
tools/perf/builtin-sched.c | 42 +++-------------------
tools/perf/builtin-top.c | 19 ----------
tools/perf/builtin-trace.c | 40 +++------------------
tools/perf/util/data_map.c | 56 ++++++++++++++++++++++-------
tools/perf/util/data_map.h | 2 +-
tools/perf/util/event.c | 74 ++++++++++++++++++++++++++++++++++++++
tools/perf/util/event.h | 17 +++++++++
tools/perf/util/hist.c | 7 ----
tools/perf/util/process_event.c | 53 ---------------------------
tools/perf/util/process_event.h | 29 ---------------
tools/perf/util/process_events.c | 64 --------------------------------
tools/perf/util/process_events.h | 35 ------------------
16 files changed, 183 insertions(+), 425 deletions(-)
delete mode 100644 tools/perf/util/process_event.c
delete mode 100644 tools/perf/util/process_event.h
delete mode 100644 tools/perf/util/process_events.c
delete mode 100644 tools/perf/util/process_events.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index de37d49..f1537a9 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -369,7 +369,6 @@ LIB_H += util/sort.h
LIB_H += util/hist.h
LIB_H += util/thread.h
LIB_H += util/data_map.h
-LIB_H += util/process_events.h
LIB_OBJS += util/abspath.o
LIB_OBJS += util/alias.o
@@ -412,7 +411,6 @@ LIB_OBJS += util/svghelper.o
LIB_OBJS += util/sort.o
LIB_OBJS += util/hist.o
LIB_OBJS += util/data_map.o
-LIB_OBJS += util/process_events.o
BUILTIN_OBJS += builtin-annotate.o
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 3ebd70b..7d39bd2 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -19,12 +19,12 @@
#include "perf.h"
#include "util/debug.h"
+#include "util/event.h"
#include "util/parse-options.h"
#include "util/parse-events.h"
#include "util/thread.h"
#include "util/sort.h"
#include "util/hist.h"
-#include "util/process_events.h"
static char const *input_name = "perf.data";
@@ -136,8 +136,7 @@ static int hist_entry__add(struct thread *thread, struct map *map,
return 0;
}
-static int
-process_sample_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_sample_event(event_t *event)
{
char level;
u64 ip = event->ip.ip;
@@ -145,12 +144,8 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
struct symbol *sym = NULL;
struct thread *thread = threads__findnew(event->ip.pid);
- dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->header.misc,
- event->ip.pid,
- (void *)(long)ip);
+ dump_printf("(IP, %d): %d: %p\n", event->header.misc,
+ event->ip.pid, (void *)(long)ip);
if (thread == NULL) {
fprintf(stderr, "problem processing %d event, skipping it.\n",
@@ -198,46 +193,24 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
"skipping event\n");
return -1;
}
- total++;
return 0;
}
-static int
-process_comm_event(event_t *event, unsigned long offset, unsigned long head)
+static int event__process(event_t *self)
{
- struct thread *thread = threads__findnew(event->comm.pid);
-
- dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->comm.comm, event->comm.pid);
-
- if (thread == NULL ||
- thread__set_comm(thread, event->comm.comm)) {
- dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
- return -1;
- }
- total_comm++;
-
- return 0;
-}
-
-static int
-process_event(event_t *event, unsigned long offset, unsigned long head)
-{
- switch (event->header.type) {
+ switch (self->header.type) {
case PERF_RECORD_SAMPLE:
- return process_sample_event(event, offset, head);
+ return process_sample_event(self);
case PERF_RECORD_MMAP:
- return process_mmap_event(event, offset, head);
+ return event__process_mmap(self);
case PERF_RECORD_COMM:
- return process_comm_event(event, offset, head);
+ return event__process_comm(self);
case PERF_RECORD_FORK:
- return process_task_event(event, offset, head);
+ return event__process_task(self);
/*
* We dont process them right now but they are fine:
*/
@@ -621,15 +594,12 @@ more:
(void *)(long)event->header.size,
event->header.type);
- if (!size || process_event(event, offset, head) < 0) {
+ if (!size || event__process(event) < 0) {
dump_printf("%p [%p]: skipping unknown header type: %d\n",
(void *)(offset + head),
(void *)(long)(event->header.size),
event->header.type);
-
- total_unknown++;
-
/*
* assume we lost track of the stream, check alignment, and
* increment a single u64 in the hope to catch on again 'soon'.
@@ -649,14 +619,11 @@ more:
rc = EXIT_SUCCESS;
close(input);
- dump_printf(" IP events: %10ld\n", total);
- dump_printf(" mmap events: %10ld\n", total_mmap);
- dump_printf(" comm events: %10ld\n", total_comm);
- dump_printf(" fork events: %10ld\n", total_fork);
- dump_printf(" unknown events: %10ld\n", total_unknown);
- if (dump_trace)
+ if (dump_trace) {
+ event__print_totals();
return 0;
+ }
if (verbose > 3)
threads__fprintf(stdout);
@@ -665,7 +632,7 @@ more:
dsos__fprintf(stdout);
collapse__resort();
- output__resort(total);
+ output__resort(event__total[0]);
find_annotations();
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 35722fa..e7294c8 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -33,9 +33,6 @@ static bool raw_ip;
static char default_sort_order[] = "frag,hit,bytes";
-static char *cwd;
-static int cwdlen;
-
static int *cpunode_map;
static int max_cpu_num;
@@ -126,25 +123,6 @@ static void setup_cpunode_map(void)
}
}
-static int
-process_comm_event(event_t *event, unsigned long offset, unsigned long head)
-{
- struct thread *thread = threads__findnew(event->comm.pid);
-
- dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->comm.comm, event->comm.pid);
-
- if (thread == NULL ||
- thread__set_comm(thread, event->comm.comm)) {
- dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
- return -1;
- }
-
- return 0;
-}
-
static void insert_alloc_stat(unsigned long call_site, unsigned long ptr,
int bytes_req, int bytes_alloc, int cpu)
{
@@ -340,8 +318,7 @@ process_raw_event(event_t *raw_event __used, void *more_data,
}
}
-static int
-process_sample_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_sample_event(event_t *event)
{
u64 ip = event->ip.ip;
u64 timestamp = -1;
@@ -366,9 +343,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
more_data += sizeof(u64);
}
- dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
+ dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
event->header.misc,
event->ip.pid, event->ip.tid,
(void *)(long)ip,
@@ -403,7 +378,7 @@ static int sample_type_check(u64 type)
static struct perf_file_handler file_handler = {
.process_sample_event = process_sample_event,
- .process_comm_event = process_comm_event,
+ .process_comm_event = event__process_comm,
.sample_type_check = sample_type_check,
};
@@ -413,7 +388,7 @@ static int read_events(void)
register_perf_file_handler(&file_handler);
return mmap_dispatch_perf_file(&header, input_name, 0, 0,
- &cwdlen, &cwd);
+ &event__cwdlen, &event__cwd);
}
static double fragmentation(unsigned long n_req, unsigned long n_alloc)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 9bd20c2..01ef35c 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -30,7 +30,6 @@
#include "util/thread.h"
#include "util/sort.h"
#include "util/hist.h"
-#include "util/process_events.h"
static char const *input_name = "perf.data";
@@ -655,8 +654,7 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
return 0;
}
-static int
-process_sample_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_sample_event(event_t *event)
{
char level;
struct symbol *sym = NULL;
@@ -673,9 +671,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
more_data += sizeof(u64);
}
- dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
+ dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
event->header.misc,
event->ip.pid, event->ip.tid,
(void *)(long)ip,
@@ -743,47 +739,27 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
return -1;
}
- total += period;
+ event__stats.total += period;
return 0;
}
-static int
-process_comm_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_comm_event(event_t *event)
{
struct thread *thread = threads__findnew(event->comm.pid);
- dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->comm.comm, event->comm.pid);
+ dump_printf(": %s:%d\n", event->comm.comm, event->comm.pid);
if (thread == NULL ||
thread__set_comm_adjust(thread, event->comm.comm)) {
dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
return -1;
}
- total_comm++;
-
- return 0;
-}
-
-static int
-process_lost_event(event_t *event, unsigned long offset, unsigned long head)
-{
- dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->lost.id,
- event->lost.lost);
-
- total_lost += event->lost.lost;
return 0;
}
-static int
-process_read_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_read_event(event_t *event)
{
struct perf_event_attr *attr;
@@ -799,14 +775,9 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
event->read.value);
}
- dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->read.pid,
- event->read.tid,
- attr ? __event_name(attr->type, attr->config)
- : "FAIL",
- event->read.value);
+ dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid,
+ attr ? __event_name(attr->type, attr->config) : "FAIL",
+ event->read.value);
return 0;
}
@@ -842,11 +813,11 @@ static int sample_type_check(u64 type)
static struct perf_file_handler file_handler = {
.process_sample_event = process_sample_event,
- .process_mmap_event = process_mmap_event,
+ .process_mmap_event = event__process_mmap,
.process_comm_event = process_comm_event,
- .process_exit_event = process_task_event,
- .process_fork_event = process_task_event,
- .process_lost_event = process_lost_event,
+ .process_exit_event = event__process_task,
+ .process_fork_event = event__process_task,
+ .process_lost_event = event__process_lost,
.process_read_event = process_read_event,
.sample_type_check = sample_type_check,
};
@@ -866,19 +837,14 @@ static int __cmd_report(void)
register_perf_file_handler(&file_handler);
ret = mmap_dispatch_perf_file(&header, input_name, force,
- full_paths, &cwdlen, &cwd);
+ full_paths, &event__cwdlen, &event__cwd);
if (ret)
return ret;
- dump_printf(" IP events: %10ld\n", total);
- dump_printf(" mmap events: %10ld\n", total_mmap);
- dump_printf(" comm events: %10ld\n", total_comm);
- dump_printf(" fork events: %10ld\n", total_fork);
- dump_printf(" lost events: %10ld\n", total_lost);
- dump_printf(" unknown events: %10ld\n", file_handler.total_unknown);
-
- if (dump_trace)
+ if (dump_trace) {
+ event__print_totals();
return 0;
+ }
if (verbose > 3)
threads__fprintf(stdout);
@@ -887,8 +853,8 @@ static int __cmd_report(void)
dsos__fprintf(stdout);
collapse__resort();
- output__resort(total);
- output__fprintf(stdout, total);
+ output__resort(event__stats.total);
+ output__fprintf(stdout, event__stats.total);
if (show_threads)
perf_read_values_destroy(&show_threads_values);
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 19eb708..26b782f 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -22,8 +22,6 @@
static char const *input_name = "perf.data";
-static unsigned long total_comm = 0;
-
static struct perf_header *header;
static u64 sample_type;
@@ -32,9 +30,6 @@ static char *sort_order = default_sort_order;
static int profile_cpu = -1;
-static char *cwd;
-static int cwdlen;
-
#define PR_SET_NAME 15 /* Set process name */
#define MAX_CPUS 4096
@@ -633,27 +628,6 @@ static void test_calibrations(void)
printf("the sleep test took %Ld nsecs\n", T1-T0);
}
-static int
-process_comm_event(event_t *event, unsigned long offset, unsigned long head)
-{
- struct thread *thread = threads__findnew(event->comm.tid);
-
- dump_printf("%p [%p]: perf_event_comm: %s:%d\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->comm.comm, event->comm.pid);
-
- if (thread == NULL ||
- thread__set_comm(thread, event->comm.comm)) {
- dump_printf("problem processing perf_event_comm, skipping event.\n");
- return -1;
- }
- total_comm++;
-
- return 0;
-}
-
-
struct raw_event_sample {
u32 size;
char data[0];
@@ -1622,8 +1596,7 @@ process_raw_event(event_t *raw_event __used, void *more_data,
process_sched_migrate_task_event(raw, event, cpu, timestamp, thread);
}
-static int
-process_sample_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_sample_event(event_t *event)
{
struct thread *thread;
u64 ip = event->ip.ip;
@@ -1653,9 +1626,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
more_data += sizeof(u64);
}
- dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
+ dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
event->header.misc,
event->ip.pid, event->ip.tid,
(void *)(long)ip,
@@ -1677,10 +1648,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
return 0;
}
-static int
-process_lost_event(event_t *event __used,
- unsigned long offset __used,
- unsigned long head __used)
+static int process_lost_event(event_t *event __used)
{
nr_lost_chunks++;
nr_lost_events += event->lost.lost;
@@ -1704,7 +1672,7 @@ static int sample_type_check(u64 type)
static struct perf_file_handler file_handler = {
.process_sample_event = process_sample_event,
- .process_comm_event = process_comm_event,
+ .process_comm_event = event__process_comm,
.process_lost_event = process_lost_event,
.sample_type_check = sample_type_check,
};
@@ -1715,7 +1683,7 @@ static int read_events(void)
register_perf_file_handler(&file_handler);
return mmap_dispatch_perf_file(&header, input_name, 0, 0,
- &cwdlen, &cwd);
+ &event__cwdlen, &event__cwd);
}
static void print_bad_events(void)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index bf6730c..7a3c0c7 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -991,25 +991,6 @@ static void event__process_sample(const event_t *self, int counter)
}
}
-static void event__process_mmap(event_t *self)
-{
- struct thread *thread = threads__findnew(self->mmap.pid);
-
- if (thread != NULL) {
- struct map *map = map__new(&self->mmap, MAP__FUNCTION, NULL, 0);
- if (map != NULL)
- thread__insert_map(thread, map);
- }
-}
-
-static void event__process_comm(event_t *self)
-{
- struct thread *thread = threads__findnew(self->comm.pid);
-
- if (thread != NULL)
- thread__set_comm(thread, self->comm.comm);
-}
-
static int event__process(event_t *event)
{
switch (event->header.type) {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 75972fd..a775025 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -16,38 +16,10 @@
static char const *input_name = "perf.data";
-static unsigned long total = 0;
-static unsigned long total_comm = 0;
-
static struct perf_header *header;
static u64 sample_type;
-static char *cwd;
-static int cwdlen;
-
-
-static int
-process_comm_event(event_t *event, unsigned long offset, unsigned long head)
-{
- struct thread *thread = threads__findnew(event->comm.pid);
-
- dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->comm.comm, event->comm.pid);
-
- if (thread == NULL ||
- thread__set_comm(thread, event->comm.comm)) {
- dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
- return -1;
- }
- total_comm++;
-
- return 0;
-}
-
-static int
-process_sample_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_sample_event(event_t *event)
{
u64 ip = event->ip.ip;
u64 timestamp = -1;
@@ -72,9 +44,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
more_data += sizeof(u64);
}
- dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
+ dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
event->header.misc,
event->ip.pid, event->ip.tid,
(void *)(long)ip,
@@ -101,7 +71,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
*/
print_event(cpu, raw->data, raw->size, timestamp, thread->comm);
}
- total += period;
+ event__stats.total += period;
return 0;
}
@@ -122,7 +92,7 @@ static int sample_type_check(u64 type)
static struct perf_file_handler file_handler = {
.process_sample_event = process_sample_event,
- .process_comm_event = process_comm_event,
+ .process_comm_event = event__process_comm,
.sample_type_check = sample_type_check,
};
@@ -132,7 +102,7 @@ static int __cmd_trace(void)
register_perf_file_handler(&file_handler);
return mmap_dispatch_perf_file(&header, input_name,
- 0, 0, &cwdlen, &cwd);
+ 0, 0, &event__cwdlen, &event__cwd);
}
static const char * const annotate_usage[] = {
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
index b238462..ca0bedf 100644
--- a/tools/perf/util/data_map.c
+++ b/tools/perf/util/data_map.c
@@ -8,11 +8,9 @@ static struct perf_file_handler *curr_handler;
static unsigned long mmap_window = 32;
static char __cwd[PATH_MAX];
-static int
-process_event_stub(event_t *event __used,
- unsigned long offset __used,
- unsigned long head __used)
+static int process_event_stub(event_t *event __used)
{
+ dump_printf(": unhandled!\n");
return 0;
}
@@ -40,30 +38,62 @@ void register_perf_file_handler(struct perf_file_handler *handler)
curr_handler = handler;
}
+static const char *event__name[] = {
+ [0] = "TOTAL",
+ [PERF_RECORD_MMAP] = "MMAP",
+ [PERF_RECORD_LOST] = "LOST",
+ [PERF_RECORD_COMM] = "COMM",
+ [PERF_RECORD_EXIT] = "EXIT",
+ [PERF_RECORD_THROTTLE] = "THROTTLE",
+ [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
+ [PERF_RECORD_FORK] = "FORK",
+ [PERF_RECORD_READ] = "READ",
+ [PERF_RECORD_SAMPLE] = "SAMPLE",
+};
+
+unsigned long event__total[PERF_RECORD_MAX];
+
+void event__print_totals(void)
+{
+ int i;
+ for (i = 0; i < PERF_RECORD_MAX; ++i)
+ pr_info("%10s events: %10ld\n",
+ event__name[i], event__total[i]);
+}
+
static int
process_event(event_t *event, unsigned long offset, unsigned long head)
{
trace_event(event);
+ if (event->header.type < PERF_RECORD_MAX) {
+ dump_printf("%p [%p]: PERF_RECORD_%s",
+ (void *)(offset + head),
+ (void *)(long)(event->header.size),
+ event__name[event->header.type]);
+ ++event__total[0];
+ ++event__total[event->header.type];
+ }
+
switch (event->header.type) {
case PERF_RECORD_SAMPLE:
- return curr_handler->process_sample_event(event, offset, head);
+ return curr_handler->process_sample_event(event);
case PERF_RECORD_MMAP:
- return curr_handler->process_mmap_event(event, offset, head);
+ return curr_handler->process_mmap_event(event);
case PERF_RECORD_COMM:
- return curr_handler->process_comm_event(event, offset, head);
+ return curr_handler->process_comm_event(event);
case PERF_RECORD_FORK:
- return curr_handler->process_fork_event(event, offset, head);
+ return curr_handler->process_fork_event(event);
case PERF_RECORD_EXIT:
- return curr_handler->process_exit_event(event, offset, head);
+ return curr_handler->process_exit_event(event);
case PERF_RECORD_LOST:
- return curr_handler->process_lost_event(event, offset, head);
+ return curr_handler->process_lost_event(event);
case PERF_RECORD_READ:
- return curr_handler->process_read_event(event, offset, head);
+ return curr_handler->process_read_event(event);
case PERF_RECORD_THROTTLE:
- return curr_handler->process_throttle_event(event, offset, head);
+ return curr_handler->process_throttle_event(event);
case PERF_RECORD_UNTHROTTLE:
- return curr_handler->process_unthrottle_event(event, offset, head);
+ return curr_handler->process_unthrottle_event(event);
default:
curr_handler->total_unknown++;
return -1;
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
index ae036ec..3180ff7 100644
--- a/tools/perf/util/data_map.h
+++ b/tools/perf/util/data_map.h
@@ -4,7 +4,7 @@
#include "event.h"
#include "header.h"
-typedef int (*event_type_handler_t)(event_t *, unsigned long, unsigned long);
+typedef int (*event_type_handler_t)(event_t *);
struct perf_file_handler {
event_type_handler_t process_sample_event;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 1dae7e3..70b4aa0 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -2,6 +2,7 @@
#include "event.h"
#include "debug.h"
#include "string.h"
+#include "thread.h"
static pid_t event__synthesize_comm(pid_t pid, int full,
int (*process)(event_t *event))
@@ -175,3 +176,76 @@ void event__synthesize_threads(int (*process)(event_t *event))
closedir(proc);
}
+
+char *event__cwd;
+int event__cwdlen;
+
+struct events_stats event__stats;
+
+int event__process_comm(event_t *self)
+{
+ struct thread *thread = threads__findnew(self->comm.pid);
+
+ dump_printf("PERF_RECORD_COMM: %s:%d\n",
+ self->comm.comm, self->comm.pid);
+
+ if (thread == NULL || thread__set_comm(thread, self->comm.comm)) {
+ dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int event__process_lost(event_t *self)
+{
+ dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
+ event__stats.lost += self->lost.lost;
+ return 0;
+}
+
+int event__process_mmap(event_t *self)
+{
+ struct thread *thread = threads__findnew(self->mmap.pid);
+ struct map *map = map__new(&self->mmap, MAP__FUNCTION,
+ event__cwd, event__cwdlen);
+
+ dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
+ self->mmap.pid, self->mmap.tid,
+ (void *)(long)self->mmap.start,
+ (void *)(long)self->mmap.len,
+ (void *)(long)self->mmap.pgoff,
+ self->mmap.filename);
+
+ if (thread == NULL || map == NULL)
+ dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
+ else
+ thread__insert_map(thread, map);
+
+ return 0;
+}
+
+int event__process_task(event_t *self)
+{
+ struct thread *thread = threads__findnew(self->fork.pid);
+ struct thread *parent = threads__findnew(self->fork.ppid);
+
+ dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
+ self->fork.ppid, self->fork.ptid);
+ /*
+ * A thread clone will have the same PID for both parent and child.
+ */
+ if (thread == parent)
+ return 0;
+
+ if (self->header.type == PERF_RECORD_EXIT)
+ return 0;
+
+ if (thread == NULL || parent == NULL ||
+ thread__fork(thread, parent) < 0) {
+ dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 3ae3c96..13c12c7 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -80,6 +80,13 @@ typedef union event_union {
struct sample_event sample;
} event_t;
+struct events_stats {
+ unsigned long total;
+ unsigned long lost;
+};
+
+void event__print_totals(void);
+
enum map_type {
MAP__FUNCTION = 0,
@@ -135,4 +142,14 @@ void map__fixup_end(struct map *self);
int event__synthesize_thread(pid_t pid, int (*process)(event_t *event));
void event__synthesize_threads(int (*process)(event_t *event));
+extern char *event__cwd;
+extern int event__cwdlen;
+extern struct events_stats event__stats;
+extern unsigned long event__total[PERF_RECORD_MAX];
+
+int event__process_comm(event_t *self);
+int event__process_lost(event_t *self);
+int event__process_mmap(event_t *self);
+int event__process_task(event_t *self);
+
#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 7393a02..f26cd9b 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -10,13 +10,6 @@ struct callchain_param callchain_param = {
.min_percent = 0.5
};
-unsigned long total;
-unsigned long total_mmap;
-unsigned long total_comm;
-unsigned long total_fork;
-unsigned long total_unknown;
-unsigned long total_lost;
-
/*
* histogram, sorted on item, collects counts
*/
diff --git a/tools/perf/util/process_event.c b/tools/perf/util/process_event.c
deleted file mode 100644
index a970789..0000000
--- a/tools/perf/util/process_event.c
+++ /dev/null
@@ -1,53 +0,0 @@
-#include "process_event.h"
-
-char *cwd;
-int cwdlen;
-
-int
-process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
-{
- struct map *map = map__new(&event->mmap, cwd, cwdlen);
- struct thread *thread = threads__findnew(event->mmap.pid);
-
- dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->mmap.pid,
- event->mmap.tid,
- (void *)(long)event->mmap.start,
- (void *)(long)event->mmap.len,
- (void *)(long)event->mmap.pgoff,
- event->mmap.filename);
-
- if (thread == NULL || map == NULL) {
- dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
- return 0;
- }
-
- thread__insert_map(thread, map);
- total_mmap++;
-
- return 0;
-
-}
-
-int
-process_comm_event(event_t *event, unsigned long offset, unsigned long head)
-{
- struct thread *thread = threads__findnew(event->comm.pid);
-
- dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->comm.comm, event->comm.pid);
-
- if (thread == NULL ||
- thread__set_comm_adjust(thread, event->comm.comm)) {
- dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
- return -1;
- }
- total_comm++;
-
- return 0;
-}
-
diff --git a/tools/perf/util/process_event.h b/tools/perf/util/process_event.h
deleted file mode 100644
index 6f68c69..0000000
--- a/tools/perf/util/process_event.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __PROCESS_EVENT_H
-#define __PROCESS_EVENT_H
-
-#include "../builtin.h"
-#include "util.h"
-
-#include "color.h"
-#include <linux/list.h>
-#include "cache.h"
-#include <linux/rbtree.h>
-#include "symbol.h"
-#include "string.h"
-
-#include "../perf.h"
-#include "debug.h"
-
-#include "parse-options.h"
-#include "parse-events.h"
-
-#include "thread.h"
-#include "sort.h"
-#include "hist.h"
-
-extern char *cwd;
-extern int cwdlen;
-extern int process_mmap_event(event_t *, unsigned long, unsigned long);
-extern int process_comm_event(event_t *, unsigned long , unsigned long);
-
-#endif /* __PROCESS_H */
diff --git a/tools/perf/util/process_events.c b/tools/perf/util/process_events.c
deleted file mode 100644
index 5377868..0000000
--- a/tools/perf/util/process_events.c
+++ /dev/null
@@ -1,64 +0,0 @@
-#include "process_events.h"
-
-char *cwd;
-int cwdlen;
-
-int
-process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
-{
- struct map *map = map__new(&event->mmap, MAP__FUNCTION, cwd, cwdlen);
- struct thread *thread = threads__findnew(event->mmap.pid);
-
- dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->mmap.pid,
- event->mmap.tid,
- (void *)(long)event->mmap.start,
- (void *)(long)event->mmap.len,
- (void *)(long)event->mmap.pgoff,
- event->mmap.filename);
-
- if (thread == NULL || map == NULL) {
- dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
- return 0;
- }
-
- thread__insert_map(thread, map);
- total_mmap++;
-
- return 0;
-}
-
-int
-process_task_event(event_t *event, unsigned long offset, unsigned long head)
-{
- struct thread *thread = threads__findnew(event->fork.pid);
- struct thread *parent = threads__findnew(event->fork.ppid);
-
- dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
- event->fork.pid, event->fork.tid,
- event->fork.ppid, event->fork.ptid);
-
- /*
- * A thread clone will have the same PID for both
- * parent and child.
- */
- if (thread == parent)
- return 0;
-
- if (event->header.type == PERF_RECORD_EXIT)
- return 0;
-
- if (!thread || !parent || thread__fork(thread, parent)) {
- dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
- return -1;
- }
- total_fork++;
-
- return 0;
-}
-
diff --git a/tools/perf/util/process_events.h b/tools/perf/util/process_events.h
deleted file mode 100644
index 73d092f..0000000
--- a/tools/perf/util/process_events.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __PROCESS_EVENTS_H
-#define __PROCESS_EVENTS_H
-
-#include "../builtin.h"
-
-#include "util.h"
-#include "color.h"
-#include <linux/list.h>
-#include "cache.h"
-#include <linux/rbtree.h>
-#include "symbol.h"
-#include "string.h"
-#include "callchain.h"
-#include "strlist.h"
-#include "values.h"
-
-#include "../perf.h"
-#include "debug.h"
-#include "header.h"
-
-#include "parse-options.h"
-#include "parse-events.h"
-
-#include "data_map.h"
-#include "thread.h"
-#include "sort.h"
-#include "hist.h"
-
-extern char *cwd;
-extern int cwdlen;
-
-extern int process_mmap_event(event_t *, unsigned long , unsigned long);
-extern int process_task_event(event_t *, unsigned long, unsigned long);
-
-#endif /* __PROCESS_EVENTS_H */
--
1.6.2.5
From: Arnaldo Carvalho de Melo <[email protected]>
Now we have a very high level routine for simple tools to process
IP sample events:
int event__preprocess_sample(const event_t *self,
struct addr_location *al,
symbol_filter_t filter)
It receives the event itself and will insert new threads in the global
threads list and resolve the map and symbol, filling all this info into
the new addr_location struct, so that tools like annotate and report can
further process the event by creating hist_entries in their specific
way (with or without callgraphs, etc).
It in turn uses the new next layer function:
void thread__find_addr_location(struct thread *self, u8 cpumode,
enum map_type type, u64 addr,
struct addr_location *al,
symbol_filter_t filter)
This one will, given a thread (userspace or the kernel kthread one),
will find the given type (MAP__FUNCTION now, MAP__VARIABLE too in
the near future) at the given cpumode, taking vdsos into account
(userspace hit, but kernel symbol) and will fill all these details in
the addr_location given.
Tools that need a more compact API for plain function resolution, like
'kmem', can use this other one:
struct symbol *thread__find_function(struct thread *self, u64 addr,
symbol_filter_t filter)
So, to resolve a kernel symbol, that is all the 'kmem' tool needs, its
just a matter of calling:
sym = thread__find_function(kthread, addr, NULL);
The 'filter' parameter is needed because we do lazy parsing/loading of
ELF symtabs or /proc/kallsyms.
With this we remove more code duplication all around, which is always
good, huh? :-)
Cc: Frédéric Weisbecker <[email protected]>
Cc: John Kacur <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-annotate.c | 55 ++---------------
tools/perf/builtin-kmem.c | 2 +-
tools/perf/builtin-report.c | 135 ++++++++++++-----------------------------
tools/perf/builtin-top.c | 44 +++-----------
tools/perf/util/event.c | 62 +++++++++++++++++++
tools/perf/util/event.h | 4 +
tools/perf/util/hist.c | 15 ++---
tools/perf/util/hist.h | 6 +-
tools/perf/util/symbol.c | 26 +-------
tools/perf/util/symbol.h | 10 +++
tools/perf/util/thread.c | 12 ++++
tools/perf/util/thread.h | 23 +++++--
12 files changed, 172 insertions(+), 222 deletions(-)
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 7d39bd2..7f85c6e 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -124,71 +124,30 @@ static void hist_hit(struct hist_entry *he, u64 ip)
h->ip[offset]);
}
-static int hist_entry__add(struct thread *thread, struct map *map,
- struct symbol *sym, u64 ip, u64 count, char level)
+static int hist_entry__add(struct addr_location *al, u64 count)
{
bool hit;
- struct hist_entry *he = __hist_entry__add(thread, map, sym, NULL, ip,
- count, level, &hit);
+ struct hist_entry *he = __hist_entry__add(al, NULL, count, &hit);
if (he == NULL)
return -ENOMEM;
- hist_hit(he, ip);
+ hist_hit(he, al->addr);
return 0;
}
static int process_sample_event(event_t *event)
{
- char level;
- u64 ip = event->ip.ip;
- struct map *map = NULL;
- struct symbol *sym = NULL;
- struct thread *thread = threads__findnew(event->ip.pid);
+ struct addr_location al;
dump_printf("(IP, %d): %d: %p\n", event->header.misc,
- event->ip.pid, (void *)(long)ip);
+ event->ip.pid, (void *)(long)event->ip.ip);
- if (thread == NULL) {
+ if (event__preprocess_sample(event, &al, symbol_filter) < 0) {
fprintf(stderr, "problem processing %d event, skipping it.\n",
event->header.type);
return -1;
}
- dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
-
- if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
- level = 'k';
- sym = kernel_maps__find_function(ip, &map, symbol_filter);
- dump_printf(" ...... dso: %s\n",
- map ? map->dso->long_name : "<not found>");
- } else if (event->header.misc & PERF_RECORD_MISC_USER) {
- level = '.';
- map = thread__find_map(thread, MAP__FUNCTION, ip);
- if (map != NULL) {
- ip = map->map_ip(map, ip);
- sym = map__find_symbol(map, ip, symbol_filter);
- } else {
- /*
- * If this is outside of all known maps,
- * and is a negative address, try to look it
- * up in the kernel dso, as it might be a
- * vsyscall or vdso (which executes in user-mode).
- *
- * XXX This is nasty, we should have a symbol list in
- * the "[vdso]" dso, but for now lets use the old
- * trick of looking in the whole kernel symbol list.
- */
- if ((long long)ip < 0)
- sym = kernel_maps__find_function(ip, &map,
- symbol_filter);
- }
- dump_printf(" ...... dso: %s\n",
- map ? map->dso->long_name : "<not found>");
- } else {
- level = 'H';
- dump_printf(" ...... dso: [hypervisor]\n");
- }
-
- if (hist_entry__add(thread, map, sym, ip, 1, level)) {
+ if (hist_entry__add(&al, 1)) {
fprintf(stderr, "problem incrementing symbol count, "
"skipping event\n");
return -1;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index e7294c8..047fef7 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -420,7 +420,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
if (is_caller) {
addr = data->call_site;
if (!raw_ip)
- sym = kernel_maps__find_function(addr, NULL, NULL);
+ sym = thread__find_function(kthread, addr, NULL);
} else
addr = data->ptr;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 01ef35c..383c4ab 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -408,55 +408,6 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
return 0;
}
-
-static struct symbol *
-resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
-{
- struct map *map = mapp ? *mapp : NULL;
- u64 ip = *ipp;
-
- if (map)
- goto got_map;
-
- if (!thread)
- return NULL;
-
- map = thread__find_map(thread, MAP__FUNCTION, ip);
- if (map != NULL) {
- /*
- * We have to do this here as we may have a dso
- * with no symbol hit that has a name longer than
- * the ones with symbols sampled.
- */
- if (!sort_dso.elide && !map->dso->slen_calculated)
- dso__calc_col_width(map->dso);
-
- if (mapp)
- *mapp = map;
-got_map:
- ip = map->map_ip(map, ip);
- } else {
- /*
- * If this is outside of all known maps,
- * and is a negative address, try to look it
- * up in the kernel dso, as it might be a
- * vsyscall or vdso (which executes in user-mode).
- *
- * XXX This is nasty, we should have a symbol list in
- * the "[vdso]" dso, but for now lets use the old
- * trick of looking in the whole kernel symbol list.
- */
- if ((long long)ip < 0)
- return kernel_maps__find_function(ip, mapp, NULL);
- }
- dump_printf(" ...... dso: %s\n",
- map ? map->dso->long_name : "<not found>");
- dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
- *ipp = ip;
-
- return map ? map__find_symbol(map, ip, NULL) : NULL;
-}
-
static int call__match(struct symbol *sym)
{
if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
@@ -469,7 +420,7 @@ static struct symbol **resolve_callchain(struct thread *thread,
struct ip_callchain *chain,
struct symbol **parent)
{
- u64 context = PERF_CONTEXT_MAX;
+ u8 cpumode = PERF_RECORD_MISC_USER;
struct symbol **syms = NULL;
unsigned int i;
@@ -483,30 +434,31 @@ static struct symbol **resolve_callchain(struct thread *thread,
for (i = 0; i < chain->nr; i++) {
u64 ip = chain->ips[i];
- struct symbol *sym = NULL;
+ struct addr_location al;
if (ip >= PERF_CONTEXT_MAX) {
- context = ip;
+ switch (ip) {
+ case PERF_CONTEXT_HV:
+ cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
+ case PERF_CONTEXT_KERNEL:
+ cpumode = PERF_RECORD_MISC_KERNEL; break;
+ case PERF_CONTEXT_USER:
+ cpumode = PERF_RECORD_MISC_USER; break;
+ default:
+ break;
+ }
continue;
}
- switch (context) {
- case PERF_CONTEXT_HV:
- break;
- case PERF_CONTEXT_KERNEL:
- sym = kernel_maps__find_function(ip, NULL, NULL);
- break;
- default:
- sym = resolve_symbol(thread, NULL, &ip);
- break;
- }
-
- if (sym) {
- if (sort__has_parent && !*parent && call__match(sym))
- *parent = sym;
+ thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
+ ip, &al, NULL);
+ if (al.sym != NULL) {
+ if (sort__has_parent && !*parent &&
+ call__match(al.sym))
+ *parent = al.sym;
if (!callchain)
break;
- syms[i] = sym;
+ syms[i] = al.sym;
}
}
@@ -517,20 +469,17 @@ static struct symbol **resolve_callchain(struct thread *thread,
* collect histogram counts
*/
-static int
-hist_entry__add(struct thread *thread, struct map *map,
- struct symbol *sym, u64 ip, struct ip_callchain *chain,
- char level, u64 count)
+static int hist_entry__add(struct addr_location *al,
+ struct ip_callchain *chain, u64 count)
{
struct symbol **syms = NULL, *parent = NULL;
bool hit;
struct hist_entry *he;
if ((sort__has_parent || callchain) && chain)
- syms = resolve_callchain(thread, chain, &parent);
+ syms = resolve_callchain(al->thread, chain, &parent);
- he = __hist_entry__add(thread, map, sym, parent,
- ip, count, level, &hit);
+ he = __hist_entry__add(al, parent, count, &hit);
if (he == NULL)
return -ENOMEM;
@@ -656,14 +605,12 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
static int process_sample_event(event_t *event)
{
- char level;
- struct symbol *sym = NULL;
u64 ip = event->ip.ip;
u64 period = 1;
- struct map *map = NULL;
void *more_data = event->ip.__more_data;
struct ip_callchain *chain = NULL;
int cpumode;
+ struct addr_location al;
struct thread *thread = threads__findnew(event->ip.pid);
if (sample_type & PERF_SAMPLE_PERIOD) {
@@ -709,32 +656,26 @@ static int process_sample_event(event_t *event)
cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
- if (cpumode == PERF_RECORD_MISC_KERNEL) {
- level = 'k';
- sym = kernel_maps__find_function(ip, &map, NULL);
- dump_printf(" ...... dso: %s\n",
- map ? map->dso->long_name : "<not found>");
- } else if (cpumode == PERF_RECORD_MISC_USER) {
- level = '.';
- sym = resolve_symbol(thread, &map, &ip);
-
- } else {
- level = 'H';
- dump_printf(" ...... dso: [hypervisor]\n");
- }
+ thread__find_addr_location(thread, cpumode,
+ MAP__FUNCTION, ip, &al, NULL);
+ /*
+ * We have to do this here as we may have a dso with no symbol hit that
+ * has a name longer than the ones with symbols sampled.
+ */
+ if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated)
+ dso__calc_col_width(al.map->dso);
if (dso_list &&
- (!map || !map->dso ||
- !(strlist__has_entry(dso_list, map->dso->short_name) ||
- (map->dso->short_name != map->dso->long_name &&
- strlist__has_entry(dso_list, map->dso->long_name)))))
+ (!al.map || !al.map->dso ||
+ !(strlist__has_entry(dso_list, al.map->dso->short_name) ||
+ (al.map->dso->short_name != al.map->dso->long_name &&
+ strlist__has_entry(dso_list, al.map->dso->long_name)))))
return 0;
- if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
+ if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name))
return 0;
- if (hist_entry__add(thread, map, sym, ip,
- chain, level, period)) {
+ if (hist_entry__add(&al, chain, period)) {
pr_debug("problem incrementing symbol count, skipping event\n");
return -1;
}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 7a3c0c7..e0a374d 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -929,55 +929,28 @@ static int symbol_filter(struct map *map, struct symbol *sym)
static void event__process_sample(const event_t *self, int counter)
{
u64 ip = self->ip.ip;
- struct map *map;
struct sym_entry *syme;
- struct symbol *sym;
+ struct addr_location al;
u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
switch (origin) {
- case PERF_RECORD_MISC_USER: {
- struct thread *thread;
-
+ case PERF_RECORD_MISC_USER:
if (hide_user_symbols)
return;
-
- thread = threads__findnew(self->ip.pid);
- if (thread == NULL)
- return;
-
- map = thread__find_map(thread, MAP__FUNCTION, ip);
- if (map != NULL) {
- ip = map->map_ip(map, ip);
- sym = map__find_symbol(map, ip, symbol_filter);
- if (sym == NULL)
- return;
- userspace_samples++;
- break;
- }
- }
- /*
- * If this is outside of all known maps,
- * and is a negative address, try to look it
- * up in the kernel dso, as it might be a
- * vsyscall or vdso (which executes in user-mode).
- */
- if ((long long)ip >= 0)
- return;
- /* Fall thru */
+ break;
case PERF_RECORD_MISC_KERNEL:
if (hide_kernel_symbols)
return;
-
- sym = kernel_maps__find_function(ip, &map, symbol_filter);
- if (sym == NULL)
- return;
break;
default:
return;
}
- syme = symbol__priv(sym);
+ if (event__preprocess_sample(self, &al, symbol_filter) < 0 ||
+ al.sym == NULL)
+ return;
+ syme = symbol__priv(al.sym);
if (!syme->skip) {
syme->count[counter]++;
syme->origin = origin;
@@ -986,8 +959,9 @@ static void event__process_sample(const event_t *self, int counter)
if (list_empty(&syme->node) || !syme->node.next)
__list_insert_active_sym(syme);
pthread_mutex_unlock(&active_symbols_lock);
+ if (origin == PERF_RECORD_MISC_USER)
+ ++userspace_samples;
++samples;
- return;
}
}
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 70b4aa0..233d7ad 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -249,3 +249,65 @@ int event__process_task(event_t *self)
return 0;
}
+
+void thread__find_addr_location(struct thread *self, u8 cpumode,
+ enum map_type type, u64 addr,
+ struct addr_location *al,
+ symbol_filter_t filter)
+{
+ struct thread *thread = al->thread = self;
+
+ al->addr = addr;
+
+ if (cpumode & PERF_RECORD_MISC_KERNEL) {
+ al->level = 'k';
+ thread = kthread;
+ } else if (cpumode & PERF_RECORD_MISC_USER)
+ al->level = '.';
+ else {
+ al->level = 'H';
+ al->map = NULL;
+ al->sym = NULL;
+ return;
+ }
+try_again:
+ al->map = thread__find_map(thread, type, al->addr);
+ if (al->map == NULL) {
+ /*
+ * If this is outside of all known maps, and is a negative
+ * address, try to look it up in the kernel dso, as it might be
+ * a vsyscall or vdso (which executes in user-mode).
+ *
+ * XXX This is nasty, we should have a symbol list in the
+ * "[vdso]" dso, but for now lets use the old trick of looking
+ * in the whole kernel symbol list.
+ */
+ if ((long long)al->addr < 0 && thread != kthread) {
+ thread = kthread;
+ goto try_again;
+ }
+ al->sym = NULL;
+ } else {
+ al->addr = al->map->map_ip(al->map, al->addr);
+ al->sym = map__find_symbol(al->map, al->addr, filter);
+ }
+}
+
+int event__preprocess_sample(const event_t *self, struct addr_location *al,
+ symbol_filter_t filter)
+{
+ u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+ struct thread *thread = threads__findnew(self->ip.pid);
+
+ if (thread == NULL)
+ return -1;
+
+ dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
+
+ thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
+ self->ip.ip, al, filter);
+ dump_printf(" ...... dso: %s\n",
+ al->map ? al->map->dso->long_name :
+ al->level == 'H' ? "[hypervisor]" : "<not found>");
+ return 0;
+}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 13c12c7..a4cc810 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -152,4 +152,8 @@ int event__process_lost(event_t *self);
int event__process_mmap(event_t *self);
int event__process_task(event_t *self);
+struct addr_location;
+int event__preprocess_sample(const event_t *self, struct addr_location *al,
+ symbol_filter_t filter);
+
#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index f26cd9b..0ebf6ee 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -14,20 +14,19 @@ struct callchain_param callchain_param = {
* histogram, sorted on item, collects counts
*/
-struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
- struct symbol *sym,
+struct hist_entry *__hist_entry__add(struct addr_location *al,
struct symbol *sym_parent,
- u64 ip, u64 count, char level, bool *hit)
+ u64 count, bool *hit)
{
struct rb_node **p = &hist.rb_node;
struct rb_node *parent = NULL;
struct hist_entry *he;
struct hist_entry entry = {
- .thread = thread,
- .map = map,
- .sym = sym,
- .ip = ip,
- .level = level,
+ .thread = al->thread,
+ .map = al->map,
+ .sym = al->sym,
+ .ip = al->addr,
+ .level = al->level,
.count = count,
.parent = sym_parent,
};
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index ac2149c..3020db0 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -36,9 +36,9 @@ extern unsigned long total_fork;
extern unsigned long total_unknown;
extern unsigned long total_lost;
-struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
- struct symbol *sym, struct symbol *parent,
- u64 ip, u64 count, char level, bool *hit);
+struct hist_entry *__hist_entry__add(struct addr_location *al,
+ struct symbol *parent,
+ u64 count, bool *hit);
extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
extern void hist_entry__free(struct hist_entry *);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index b788c2f..fffcb93 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -43,7 +43,8 @@ static struct symbol_conf symbol_conf__defaults = {
.try_vmlinux_path = true,
};
-static struct thread kthread_mem, *kthread = &kthread_mem;
+static struct thread kthread_mem;
+struct thread *kthread = &kthread_mem;
bool dso__loaded(const struct dso *self, enum map_type type)
{
@@ -1178,29 +1179,6 @@ out:
return ret;
}
-static struct symbol *thread__find_symbol(struct thread *self, u64 ip,
- enum map_type type, struct map **mapp,
- symbol_filter_t filter)
-{
- struct map *map = thread__find_map(self, type, ip);
-
- if (mapp)
- *mapp = map;
-
- if (map) {
- ip = map->map_ip(map, ip);
- return map__find_symbol(map, ip, filter);
- }
-
- return NULL;
-}
-
-struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp,
- symbol_filter_t filter)
-{
- return thread__find_symbol(kthread, ip, MAP__FUNCTION, mapp, filter);
-}
-
static struct map *thread__find_map_by_name(struct thread *self, char *name)
{
struct rb_node *nd;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 3f9e4a4..17003ef 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -63,6 +63,14 @@ static inline void *symbol__priv(struct symbol *self)
return ((void *)self) - symbol__priv_size;
}
+struct addr_location {
+ struct thread *thread;
+ struct map *map;
+ struct symbol *sym;
+ u64 addr;
+ char level;
+};
+
struct dso {
struct list_head node;
struct rb_root symbols[MAP__NR_TYPES];
@@ -105,6 +113,8 @@ size_t kernel_maps__fprintf(FILE *fp);
int symbol__init(struct symbol_conf *conf);
+struct thread;
+struct thread *kthread;
extern struct list_head dsos__user, dsos__kernel;
extern struct dso *vdso;
#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 2229f82..603f561 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -285,3 +285,15 @@ size_t threads__fprintf(FILE *fp)
return ret;
}
+
+struct symbol *thread__find_symbol(struct thread *self,
+ enum map_type type, u64 addr,
+ symbol_filter_t filter)
+{
+ struct map *map = thread__find_map(self, type, addr);
+
+ if (map != NULL)
+ return map__find_symbol(map, map->map_ip(map, addr), filter);
+
+ return NULL;
+}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 59b0d9b..686d6e9 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -27,19 +27,30 @@ size_t thread__fprintf_maps(struct thread *self, FILE *fp);
size_t threads__fprintf(FILE *fp);
void maps__insert(struct rb_root *maps, struct map *map);
-struct map *maps__find(struct rb_root *maps, u64 ip);
-
-struct symbol *kernel_maps__find_function(const u64 ip, struct map **mapp,
- symbol_filter_t filter);
+struct map *maps__find(struct rb_root *maps, u64 addr);
static inline struct map *thread__find_map(struct thread *self,
- enum map_type type, u64 ip)
+ enum map_type type, u64 addr)
{
- return self ? maps__find(&self->maps[type], ip) : NULL;
+ return self ? maps__find(&self->maps[type], addr) : NULL;
}
static inline void __thread__insert_map(struct thread *self, struct map *map)
{
maps__insert(&self->maps[map->type], map);
}
+
+void thread__find_addr_location(struct thread *self, u8 cpumode,
+ enum map_type type, u64 addr,
+ struct addr_location *al,
+ symbol_filter_t filter);
+struct symbol *thread__find_symbol(struct thread *self,
+ enum map_type type, u64 addr,
+ symbol_filter_t filter);
+
+static inline struct symbol *
+thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter)
+{
+ return thread__find_symbol(self, MAP__FUNCTION, addr, filter);
+}
#endif /* __PERF_THREAD_H */
--
1.6.2.5