| #include <errno.h> |
| #include <inttypes.h> |
| #include <asm/bug.h> |
| #include <linux/bitmap.h> |
| #include <linux/kernel.h> |
| #include <linux/zalloc.h> |
| #include "debug.h" |
| #include "env.h" |
| #include "mem2node.h" |
| |
| struct phys_entry { |
| <------>struct rb_node rb_node; |
| <------>u64 start; |
| <------>u64 end; |
| <------>u64 node; |
| }; |
| |
| static void phys_entry__insert(struct phys_entry *entry, struct rb_root *root) |
| { |
| <------>struct rb_node **p = &root->rb_node; |
| <------>struct rb_node *parent = NULL; |
| <------>struct phys_entry *e; |
| |
| <------>while (*p != NULL) { |
| <------><------>parent = *p; |
| <------><------>e = rb_entry(parent, struct phys_entry, rb_node); |
| |
| <------><------>if (entry->start < e->start) |
| <------><------><------>p = &(*p)->rb_left; |
| <------><------>else |
| <------><------><------>p = &(*p)->rb_right; |
| <------>} |
| |
| <------>rb_link_node(&entry->rb_node, parent, p); |
| <------>rb_insert_color(&entry->rb_node, root); |
| } |
| |
| static void |
| phys_entry__init(struct phys_entry *entry, u64 start, u64 bsize, u64 node) |
| { |
| <------>entry->start = start; |
| <------>entry->end = start + bsize; |
| <------>entry->node = node; |
| <------>RB_CLEAR_NODE(&entry->rb_node); |
| } |
| |
| int mem2node__init(struct mem2node *map, struct perf_env *env) |
| { |
| <------>struct memory_node *n, *nodes = &env->memory_nodes[0]; |
| <------>struct phys_entry *entries, *tmp_entries; |
| <------>u64 bsize = env->memory_bsize; |
| <------>int i, j = 0, max = 0; |
| |
| <------>memset(map, 0x0, sizeof(*map)); |
| <------>map->root = RB_ROOT; |
| |
| <------>for (i = 0; i < env->nr_memory_nodes; i++) { |
| <------><------>n = &nodes[i]; |
| <------><------>max += bitmap_weight(n->set, n->size); |
| <------>} |
| |
| <------>entries = zalloc(sizeof(*entries) * max); |
| <------>if (!entries) |
| <------><------>return -ENOMEM; |
| |
| <------>for (i = 0; i < env->nr_memory_nodes; i++) { |
| <------><------>u64 bit; |
| |
| <------><------>n = &nodes[i]; |
| |
| <------><------>for (bit = 0; bit < n->size; bit++) { |
| <------><------><------>u64 start; |
| |
| <------><------><------>if (!test_bit(bit, n->set)) |
| <------><------><------><------>continue; |
| |
| <------><------><------>start = bit * bsize; |
| |
| <------><------><------> |
| <------><------><------> * Merge nearby areas, we walk in order |
| <------><------><------> * through the bitmap, so no need to sort. |
| <------><------><------> */ |
| <------><------><------>if (j > 0) { |
| <------><------><------><------>struct phys_entry *prev = &entries[j - 1]; |
| |
| <------><------><------><------>if ((prev->end == start) && |
| <------><------><------><------> (prev->node == n->node)) { |
| <------><------><------><------><------>prev->end += bsize; |
| <------><------><------><------><------>continue; |
| <------><------><------><------>} |
| <------><------><------>} |
| |
| <------><------><------>phys_entry__init(&entries[j++], start, bsize, n->node); |
| <------><------>} |
| <------>} |
| |
| <------> |
| <------>tmp_entries = realloc(entries, sizeof(*entries) * j); |
| <------>if (tmp_entries || WARN_ON_ONCE(j == 0)) |
| <------><------>entries = tmp_entries; |
| |
| <------>for (i = 0; i < j; i++) { |
| <------><------>pr_debug("mem2node %03" PRIu64 " [0x%016" PRIx64 "-0x%016" PRIx64 "]\n", |
| <------><------><------> entries[i].node, entries[i].start, entries[i].end); |
| |
| <------><------>phys_entry__insert(&entries[i], &map->root); |
| <------>} |
| |
| <------>map->entries = entries; |
| <------>return 0; |
| } |
| |
| void mem2node__exit(struct mem2node *map) |
| { |
| <------>zfree(&map->entries); |
| } |
| |
| int mem2node__node(struct mem2node *map, u64 addr) |
| { |
| <------>struct rb_node **p, *parent = NULL; |
| <------>struct phys_entry *entry; |
| |
| <------>p = &map->root.rb_node; |
| <------>while (*p != NULL) { |
| <------><------>parent = *p; |
| <------><------>entry = rb_entry(parent, struct phys_entry, rb_node); |
| <------><------>if (addr < entry->start) |
| <------><------><------>p = &(*p)->rb_left; |
| <------><------>else if (addr >= entry->end) |
| <------><------><------>p = &(*p)->rb_right; |
| <------><------>else |
| <------><------><------>goto out; |
| <------>} |
| |
| <------>entry = NULL; |
| out: |
| <------>return entry ? (int) entry->node : -1; |
| } |
| |