1 | #include <errno.h> |
2 | #include <inttypes.h> |
3 | #include <asm/bug.h> |
4 | #include <linux/bitmap.h> |
5 | #include <linux/kernel.h> |
6 | #include <linux/zalloc.h> |
7 | #include "debug.h" |
8 | #include "env.h" |
9 | #include "mem2node.h" |
10 | |
11 | struct phys_entry { |
12 | struct rb_node rb_node; |
13 | u64 start; |
14 | u64 end; |
15 | u64 node; |
16 | }; |
17 | |
18 | static void phys_entry__insert(struct phys_entry *entry, struct rb_root *root) |
19 | { |
20 | struct rb_node **p = &root->rb_node; |
21 | struct rb_node *parent = NULL; |
22 | struct phys_entry *e; |
23 | |
24 | while (*p != NULL) { |
25 | parent = *p; |
26 | e = rb_entry(parent, struct phys_entry, rb_node); |
27 | |
28 | if (entry->start < e->start) |
29 | p = &(*p)->rb_left; |
30 | else |
31 | p = &(*p)->rb_right; |
32 | } |
33 | |
34 | rb_link_node(node: &entry->rb_node, parent, rb_link: p); |
35 | rb_insert_color(&entry->rb_node, root); |
36 | } |
37 | |
38 | static void |
39 | phys_entry__init(struct phys_entry *entry, u64 start, u64 bsize, u64 node) |
40 | { |
41 | entry->start = start; |
42 | entry->end = start + bsize; |
43 | entry->node = node; |
44 | RB_CLEAR_NODE(&entry->rb_node); |
45 | } |
46 | |
47 | int mem2node__init(struct mem2node *map, struct perf_env *env) |
48 | { |
49 | struct memory_node *n, *nodes = &env->memory_nodes[0]; |
50 | struct phys_entry *entries, *tmp_entries; |
51 | u64 bsize = env->memory_bsize; |
52 | int i, j = 0, max = 0; |
53 | |
54 | memset(map, 0x0, sizeof(*map)); |
55 | map->root = RB_ROOT; |
56 | |
57 | for (i = 0; i < env->nr_memory_nodes; i++) { |
58 | n = &nodes[i]; |
59 | max += bitmap_weight(src: n->set, nbits: n->size); |
60 | } |
61 | |
62 | entries = zalloc(sizeof(*entries) * max); |
63 | if (!entries) |
64 | return -ENOMEM; |
65 | |
66 | for (i = 0; i < env->nr_memory_nodes; i++) { |
67 | u64 bit; |
68 | |
69 | n = &nodes[i]; |
70 | |
71 | for (bit = 0; bit < n->size; bit++) { |
72 | u64 start; |
73 | |
74 | if (!test_bit(bit, n->set)) |
75 | continue; |
76 | |
77 | start = bit * bsize; |
78 | |
79 | /* |
80 | * Merge nearby areas, we walk in order |
81 | * through the bitmap, so no need to sort. |
82 | */ |
83 | if (j > 0) { |
84 | struct phys_entry *prev = &entries[j - 1]; |
85 | |
86 | if ((prev->end == start) && |
87 | (prev->node == n->node)) { |
88 | prev->end += bsize; |
89 | continue; |
90 | } |
91 | } |
92 | |
93 | phys_entry__init(entry: &entries[j++], start, bsize, node: n->node); |
94 | } |
95 | } |
96 | |
97 | /* Cut unused entries, due to merging. */ |
98 | tmp_entries = realloc(entries, sizeof(*entries) * j); |
99 | if (tmp_entries || |
100 | WARN_ONCE(j == 0, "No memory nodes, is CONFIG_MEMORY_HOTPLUG enabled?\n" )) |
101 | entries = tmp_entries; |
102 | |
103 | for (i = 0; i < j; i++) { |
104 | pr_debug("mem2node %03" PRIu64 " [0x%016" PRIx64 "-0x%016" PRIx64 "]\n" , |
105 | entries[i].node, entries[i].start, entries[i].end); |
106 | |
107 | phys_entry__insert(entry: &entries[i], root: &map->root); |
108 | } |
109 | |
110 | map->entries = entries; |
111 | return 0; |
112 | } |
113 | |
114 | void mem2node__exit(struct mem2node *map) |
115 | { |
116 | zfree(&map->entries); |
117 | } |
118 | |
119 | int mem2node__node(struct mem2node *map, u64 addr) |
120 | { |
121 | struct rb_node **p, *parent = NULL; |
122 | struct phys_entry *entry; |
123 | |
124 | p = &map->root.rb_node; |
125 | while (*p != NULL) { |
126 | parent = *p; |
127 | entry = rb_entry(parent, struct phys_entry, rb_node); |
128 | if (addr < entry->start) |
129 | p = &(*p)->rb_left; |
130 | else if (addr >= entry->end) |
131 | p = &(*p)->rb_right; |
132 | else |
133 | goto out; |
134 | } |
135 | |
136 | entry = NULL; |
137 | out: |
138 | return entry ? (int) entry->node : -1; |
139 | } |
140 | |