Skip to content

Commit fc044c5

Browse files
namhyungacmel
authored andcommitted
perf annotate-data: Add dso->data_types tree
To aggregate accesses to the same data type, add 'data_types' tree in DSO to maintain data types and find it by name and size. It might have different data types that happen to have the same name, so it also compares the size of the type. Even if it doesn't 100% guarantee, it reduces the possibility of mis-handling of such conflicts. And I don't think it's common to have different types with the same name. Committer notes: Very few cases on the Linux kernel, but there are some different types with the same name, unsure if there is a debug mode in libbpf dedup that warns about such cases, but there are provisions in pahole for that, see: "emit: Notice type shadowing, i.e. multiple types with the same name (enum, struct, union, etc)" https://git.kernel.org/pub/scm/devel/pahole/pahole.git/commit/?id=4f332dbfd02072e4f410db7bdcda8d6e3422974b $ pahole --compile > vmlinux.h $ rm -f a ; make a cc a.c -o a $ grep __[0-9] vmlinux.h union irte__1 { struct map_info__1; struct map_info__1 { struct map_info__1 * next; /* 0 8 */ $ drivers/iommu/amd/amd_iommu_types.h 'union irte' include/linux/dmar.h 'struct irte' include/linux/device-mapper.h: union map_info { void *ptr; }; include/linux/mtd/map.h: struct map_info { const char *name; unsigned long size; resource_size_t phys; <SNIP> kernel/events/uprobes.c: struct map_info { struct map_info *next; struct mm_struct *mm; unsigned long vaddr; }; Signed-off-by: Namhyung Kim <namhyung@kernel.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Ian Rogers <irogers@google.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: linux-toolchains@vger.kernel.org Cc: linux-trace-devel@vger.kernel.org Link: https://lore.kernel.org/r/20231213001323.718046-5-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent b9c87f5 commit fc044c5

4 files changed

Lines changed: 100 additions & 10 deletions

File tree

tools/perf/util/annotate-data.c

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,76 @@
1818
#include "strbuf.h"
1919
#include "symbol.h"
2020

21+
/*
22+
* Compare type name and size to maintain them in a tree.
23+
* I'm not sure if DWARF would have information of a single type in many
24+
* different places (compilation units). If not, it could compare the
25+
* offset of the type entry in the .debug_info section.
26+
*/
27+
static int data_type_cmp(const void *_key, const struct rb_node *node)
28+
{
29+
const struct annotated_data_type *key = _key;
30+
struct annotated_data_type *type;
31+
32+
type = rb_entry(node, struct annotated_data_type, node);
33+
34+
if (key->type_size != type->type_size)
35+
return key->type_size - type->type_size;
36+
return strcmp(key->type_name, type->type_name);
37+
}
38+
39+
static bool data_type_less(struct rb_node *node_a, const struct rb_node *node_b)
40+
{
41+
struct annotated_data_type *a, *b;
42+
43+
a = rb_entry(node_a, struct annotated_data_type, node);
44+
b = rb_entry(node_b, struct annotated_data_type, node);
45+
46+
if (a->type_size != b->type_size)
47+
return a->type_size < b->type_size;
48+
return strcmp(a->type_name, b->type_name) < 0;
49+
}
50+
51+
static struct annotated_data_type *dso__findnew_data_type(struct dso *dso,
52+
Dwarf_Die *type_die)
53+
{
54+
struct annotated_data_type *result = NULL;
55+
struct annotated_data_type key;
56+
struct rb_node *node;
57+
struct strbuf sb;
58+
char *type_name;
59+
Dwarf_Word size;
60+
61+
strbuf_init(&sb, 32);
62+
if (die_get_typename_from_type(type_die, &sb) < 0)
63+
strbuf_add(&sb, "(unknown type)", 14);
64+
type_name = strbuf_detach(&sb, NULL);
65+
dwarf_aggregate_size(type_die, &size);
66+
67+
/* Check existing nodes in dso->data_types tree */
68+
key.type_name = type_name;
69+
key.type_size = size;
70+
node = rb_find(&key, &dso->data_types, data_type_cmp);
71+
if (node) {
72+
result = rb_entry(node, struct annotated_data_type, node);
73+
free(type_name);
74+
return result;
75+
}
76+
77+
/* If not, add a new one */
78+
result = zalloc(sizeof(*result));
79+
if (result == NULL) {
80+
free(type_name);
81+
return NULL;
82+
}
83+
84+
result->type_name = type_name;
85+
result->type_size = size;
86+
87+
rb_add(&result->node, &dso->data_types, data_type_less);
88+
return result;
89+
}
90+
2191
static bool find_cu_die(struct debuginfo *di, u64 pc, Dwarf_Die *cu_die)
2292
{
2393
Dwarf_Off off, next_off;
@@ -130,7 +200,6 @@ struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip,
130200
struct dso *dso = map__dso(ms->map);
131201
struct debuginfo *di;
132202
Dwarf_Die type_die;
133-
struct strbuf sb;
134203
u64 pc;
135204

136205
di = debuginfo__new(dso->long_name);
@@ -148,17 +217,23 @@ struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip,
148217
if (find_data_type_die(di, pc, reg, offset, &type_die) < 0)
149218
goto out;
150219

151-
result = zalloc(sizeof(*result));
152-
if (result == NULL)
153-
goto out;
154-
155-
strbuf_init(&sb, 32);
156-
if (die_get_typename_from_type(&type_die, &sb) < 0)
157-
strbuf_add(&sb, "(unknown type)", 14);
158-
159-
result->type_name = strbuf_detach(&sb, NULL);
220+
result = dso__findnew_data_type(dso, &type_die);
160221

161222
out:
162223
debuginfo__delete(di);
163224
return result;
164225
}
226+
227+
void annotated_data_type__tree_delete(struct rb_root *root)
228+
{
229+
struct annotated_data_type *pos;
230+
231+
while (!RB_EMPTY_ROOT(root)) {
232+
struct rb_node *node = rb_first(root);
233+
234+
rb_erase(node, root);
235+
pos = rb_entry(node, struct annotated_data_type, node);
236+
free(pos->type_name);
237+
free(pos);
238+
}
239+
}

tools/perf/util/annotate-data.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <errno.h>
66
#include <linux/compiler.h>
7+
#include <linux/rbtree.h>
78
#include <linux/types.h>
89

910
struct map_symbol;
@@ -16,6 +17,7 @@ struct map_symbol;
1617
* This represents a data type accessed by samples in the profile data.
1718
*/
1819
struct annotated_data_type {
20+
struct rb_node node;
1921
char *type_name;
2022
int type_size;
2123
};
@@ -26,6 +28,9 @@ struct annotated_data_type {
2628
struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip,
2729
int reg, int offset);
2830

31+
/* Release all data type information in the tree */
32+
void annotated_data_type__tree_delete(struct rb_root *root);
33+
2934
#else /* HAVE_DWARF_SUPPORT */
3035

3136
static inline struct annotated_data_type *
@@ -35,6 +40,10 @@ find_data_type(struct map_symbol *ms __maybe_unused, u64 ip __maybe_unused,
3540
return NULL;
3641
}
3742

43+
static inline void annotated_data_type__tree_delete(struct rb_root *root __maybe_unused)
44+
{
45+
}
46+
3847
#endif /* HAVE_DWARF_SUPPORT */
3948

4049
#endif /* _PERF_ANNOTATE_DATA_H */

tools/perf/util/dso.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "debug.h"
3232
#include "string2.h"
3333
#include "vdso.h"
34+
#include "annotate-data.h"
3435

3536
static const char * const debuglink_paths[] = {
3637
"%.0s%s",
@@ -1327,6 +1328,7 @@ struct dso *dso__new_id(const char *name, struct dso_id *id)
13271328
dso->data.cache = RB_ROOT;
13281329
dso->inlined_nodes = RB_ROOT_CACHED;
13291330
dso->srclines = RB_ROOT_CACHED;
1331+
dso->data_types = RB_ROOT;
13301332
dso->data.fd = -1;
13311333
dso->data.status = DSO_DATA_STATUS_UNKNOWN;
13321334
dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
@@ -1370,6 +1372,8 @@ void dso__delete(struct dso *dso)
13701372
symbols__delete(&dso->symbols);
13711373
dso->symbol_names_len = 0;
13721374
zfree(&dso->symbol_names);
1375+
annotated_data_type__tree_delete(&dso->data_types);
1376+
13731377
if (dso->short_name_allocated) {
13741378
zfree((char **)&dso->short_name);
13751379
dso->short_name_allocated = false;

tools/perf/util/dso.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ struct dso {
154154
size_t symbol_names_len;
155155
struct rb_root_cached inlined_nodes;
156156
struct rb_root_cached srclines;
157+
struct rb_root data_types;
158+
157159
struct {
158160
u64 addr;
159161
struct symbol *symbol;

0 commit comments

Comments
 (0)