forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
2.8 KiB
139 lines
2.8 KiB
#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); |
|
} |
|
} |
|
|
|
/* Cut unused entries, due to merging. */ |
|
tmp_entries = realloc(entries, sizeof(*entries) * j); |
|
if (tmp_entries || |
|
WARN_ONCE(j == 0, "No memory nodes, is CONFIG_MEMORY_HOTPLUG enabled?\n")) |
|
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; |
|
}
|
|
|