Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Namhyung Kim and committed by
Arnaldo Carvalho de Melo
fc044c53 b9c87f53

+100 -10
+85 -10
tools/perf/util/annotate-data.c
··· 18 18 #include "strbuf.h" 19 19 #include "symbol.h" 20 20 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 + 21 91 static bool find_cu_die(struct debuginfo *di, u64 pc, Dwarf_Die *cu_die) 22 92 { 23 93 Dwarf_Off off, next_off; ··· 200 130 struct dso *dso = map__dso(ms->map); 201 131 struct debuginfo *di; 202 132 Dwarf_Die type_die; 203 - struct strbuf sb; 204 133 u64 pc; 205 134 206 135 di = debuginfo__new(dso->long_name); ··· 217 148 if (find_data_type_die(di, pc, reg, offset, &type_die) < 0) 218 149 goto out; 219 150 220 - result = zalloc(sizeof(*result)); 221 - if (result == NULL) 222 - goto out; 223 - 224 - strbuf_init(&sb, 32); 225 - if (die_get_typename_from_type(&type_die, &sb) < 0) 226 - strbuf_add(&sb, "(unknown type)", 14); 227 - 228 - result->type_name = strbuf_detach(&sb, NULL); 151 + result = dso__findnew_data_type(dso, &type_die); 229 152 230 153 out: 231 154 debuginfo__delete(di); 232 155 return result; 156 + } 157 + 158 + void annotated_data_type__tree_delete(struct rb_root *root) 159 + { 160 + struct annotated_data_type *pos; 161 + 162 + while (!RB_EMPTY_ROOT(root)) { 163 + struct rb_node *node = rb_first(root); 164 + 165 + rb_erase(node, root); 166 + pos = rb_entry(node, struct annotated_data_type, node); 167 + free(pos->type_name); 168 + free(pos); 169 + } 233 170 }
+9
tools/perf/util/annotate-data.h
··· 4 4 5 5 #include <errno.h> 6 6 #include <linux/compiler.h> 7 + #include <linux/rbtree.h> 7 8 #include <linux/types.h> 8 9 9 10 struct map_symbol; ··· 17 16 * This represents a data type accessed by samples in the profile data. 18 17 */ 19 18 struct annotated_data_type { 19 + struct rb_node node; 20 20 char *type_name; 21 21 int type_size; 22 22 }; ··· 28 26 struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip, 29 27 int reg, int offset); 30 28 29 + /* Release all data type information in the tree */ 30 + void annotated_data_type__tree_delete(struct rb_root *root); 31 + 31 32 #else /* HAVE_DWARF_SUPPORT */ 32 33 33 34 static inline struct annotated_data_type * ··· 38 33 int reg __maybe_unused, int offset __maybe_unused) 39 34 { 40 35 return NULL; 36 + } 37 + 38 + static inline void annotated_data_type__tree_delete(struct rb_root *root __maybe_unused) 39 + { 41 40 } 42 41 43 42 #endif /* HAVE_DWARF_SUPPORT */
+4
tools/perf/util/dso.c
··· 31 31 #include "debug.h" 32 32 #include "string2.h" 33 33 #include "vdso.h" 34 + #include "annotate-data.h" 34 35 35 36 static const char * const debuglink_paths[] = { 36 37 "%.0s%s", ··· 1328 1327 dso->data.cache = RB_ROOT; 1329 1328 dso->inlined_nodes = RB_ROOT_CACHED; 1330 1329 dso->srclines = RB_ROOT_CACHED; 1330 + dso->data_types = RB_ROOT; 1331 1331 dso->data.fd = -1; 1332 1332 dso->data.status = DSO_DATA_STATUS_UNKNOWN; 1333 1333 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; ··· 1372 1370 symbols__delete(&dso->symbols); 1373 1371 dso->symbol_names_len = 0; 1374 1372 zfree(&dso->symbol_names); 1373 + annotated_data_type__tree_delete(&dso->data_types); 1374 + 1375 1375 if (dso->short_name_allocated) { 1376 1376 zfree((char **)&dso->short_name); 1377 1377 dso->short_name_allocated = false;
+2
tools/perf/util/dso.h
··· 154 154 size_t symbol_names_len; 155 155 struct rb_root_cached inlined_nodes; 156 156 struct rb_root_cached srclines; 157 + struct rb_root data_types; 158 + 157 159 struct { 158 160 u64 addr; 159 161 struct symbol *symbol;