xref: /openbmc/linux/tools/perf/util/mem2node.c (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
14acf6142SJiri Olsa #include <errno.h>
24acf6142SJiri Olsa #include <inttypes.h>
3266150c9SIan Rogers #include <asm/bug.h>
44acf6142SJiri Olsa #include <linux/bitmap.h>
5b6b5574bSArnaldo Carvalho de Melo #include <linux/kernel.h>
67f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
75e51b0bbSArnaldo Carvalho de Melo #include "debug.h"
8b6b5574bSArnaldo Carvalho de Melo #include "env.h"
94acf6142SJiri Olsa #include "mem2node.h"
104acf6142SJiri Olsa 
114acf6142SJiri Olsa struct phys_entry {
124acf6142SJiri Olsa 	struct rb_node	rb_node;
134acf6142SJiri Olsa 	u64	start;
144acf6142SJiri Olsa 	u64	end;
154acf6142SJiri Olsa 	u64	node;
164acf6142SJiri Olsa };
174acf6142SJiri Olsa 
phys_entry__insert(struct phys_entry * entry,struct rb_root * root)184acf6142SJiri Olsa static void phys_entry__insert(struct phys_entry *entry, struct rb_root *root)
194acf6142SJiri Olsa {
204acf6142SJiri Olsa 	struct rb_node **p = &root->rb_node;
214acf6142SJiri Olsa 	struct rb_node *parent = NULL;
224acf6142SJiri Olsa 	struct phys_entry *e;
234acf6142SJiri Olsa 
244acf6142SJiri Olsa 	while (*p != NULL) {
254acf6142SJiri Olsa 		parent = *p;
264acf6142SJiri Olsa 		e = rb_entry(parent, struct phys_entry, rb_node);
274acf6142SJiri Olsa 
284acf6142SJiri Olsa 		if (entry->start < e->start)
294acf6142SJiri Olsa 			p = &(*p)->rb_left;
304acf6142SJiri Olsa 		else
314acf6142SJiri Olsa 			p = &(*p)->rb_right;
324acf6142SJiri Olsa 	}
334acf6142SJiri Olsa 
344acf6142SJiri Olsa 	rb_link_node(&entry->rb_node, parent, p);
354acf6142SJiri Olsa 	rb_insert_color(&entry->rb_node, root);
364acf6142SJiri Olsa }
374acf6142SJiri Olsa 
384acf6142SJiri Olsa static void
phys_entry__init(struct phys_entry * entry,u64 start,u64 bsize,u64 node)394acf6142SJiri Olsa phys_entry__init(struct phys_entry *entry, u64 start, u64 bsize, u64 node)
404acf6142SJiri Olsa {
414acf6142SJiri Olsa 	entry->start = start;
424acf6142SJiri Olsa 	entry->end   = start + bsize;
434acf6142SJiri Olsa 	entry->node  = node;
444acf6142SJiri Olsa 	RB_CLEAR_NODE(&entry->rb_node);
454acf6142SJiri Olsa }
464acf6142SJiri Olsa 
mem2node__init(struct mem2node * map,struct perf_env * env)474acf6142SJiri Olsa int mem2node__init(struct mem2node *map, struct perf_env *env)
484acf6142SJiri Olsa {
494acf6142SJiri Olsa 	struct memory_node *n, *nodes = &env->memory_nodes[0];
504acf6142SJiri Olsa 	struct phys_entry *entries, *tmp_entries;
514acf6142SJiri Olsa 	u64 bsize = env->memory_bsize;
524acf6142SJiri Olsa 	int i, j = 0, max = 0;
534acf6142SJiri Olsa 
544acf6142SJiri Olsa 	memset(map, 0x0, sizeof(*map));
554acf6142SJiri Olsa 	map->root = RB_ROOT;
564acf6142SJiri Olsa 
574acf6142SJiri Olsa 	for (i = 0; i < env->nr_memory_nodes; i++) {
584acf6142SJiri Olsa 		n = &nodes[i];
594acf6142SJiri Olsa 		max += bitmap_weight(n->set, n->size);
604acf6142SJiri Olsa 	}
614acf6142SJiri Olsa 
624acf6142SJiri Olsa 	entries = zalloc(sizeof(*entries) * max);
634acf6142SJiri Olsa 	if (!entries)
644acf6142SJiri Olsa 		return -ENOMEM;
654acf6142SJiri Olsa 
664acf6142SJiri Olsa 	for (i = 0; i < env->nr_memory_nodes; i++) {
674acf6142SJiri Olsa 		u64 bit;
684acf6142SJiri Olsa 
694acf6142SJiri Olsa 		n = &nodes[i];
704acf6142SJiri Olsa 
714acf6142SJiri Olsa 		for (bit = 0; bit < n->size; bit++) {
724acf6142SJiri Olsa 			u64 start;
734acf6142SJiri Olsa 
744acf6142SJiri Olsa 			if (!test_bit(bit, n->set))
754acf6142SJiri Olsa 				continue;
764acf6142SJiri Olsa 
774acf6142SJiri Olsa 			start = bit * bsize;
784acf6142SJiri Olsa 
794acf6142SJiri Olsa 			/*
804acf6142SJiri Olsa 			 * Merge nearby areas, we walk in order
814acf6142SJiri Olsa 			 * through the bitmap, so no need to sort.
824acf6142SJiri Olsa 			 */
834acf6142SJiri Olsa 			if (j > 0) {
844acf6142SJiri Olsa 				struct phys_entry *prev = &entries[j - 1];
854acf6142SJiri Olsa 
864acf6142SJiri Olsa 				if ((prev->end == start) &&
874acf6142SJiri Olsa 				    (prev->node == n->node)) {
884acf6142SJiri Olsa 					prev->end += bsize;
894acf6142SJiri Olsa 					continue;
904acf6142SJiri Olsa 				}
914acf6142SJiri Olsa 			}
924acf6142SJiri Olsa 
934acf6142SJiri Olsa 			phys_entry__init(&entries[j++], start, bsize, n->node);
944acf6142SJiri Olsa 		}
954acf6142SJiri Olsa 	}
964acf6142SJiri Olsa 
974acf6142SJiri Olsa 	/* Cut unused entries, due to merging. */
984acf6142SJiri Olsa 	tmp_entries = realloc(entries, sizeof(*entries) * j);
99*0ee281e1SLeo Yan 	if (tmp_entries ||
100*0ee281e1SLeo Yan 	    WARN_ONCE(j == 0, "No memory nodes, is CONFIG_MEMORY_HOTPLUG enabled?\n"))
1014acf6142SJiri Olsa 		entries = tmp_entries;
1024acf6142SJiri Olsa 
1034acf6142SJiri Olsa 	for (i = 0; i < j; i++) {
1044acf6142SJiri Olsa 		pr_debug("mem2node %03" PRIu64 " [0x%016" PRIx64 "-0x%016" PRIx64 "]\n",
1054acf6142SJiri Olsa 			 entries[i].node, entries[i].start, entries[i].end);
1064acf6142SJiri Olsa 
1074acf6142SJiri Olsa 		phys_entry__insert(&entries[i], &map->root);
1084acf6142SJiri Olsa 	}
1094acf6142SJiri Olsa 
1104acf6142SJiri Olsa 	map->entries = entries;
1114acf6142SJiri Olsa 	return 0;
1124acf6142SJiri Olsa }
1134acf6142SJiri Olsa 
mem2node__exit(struct mem2node * map)1144acf6142SJiri Olsa void mem2node__exit(struct mem2node *map)
1154acf6142SJiri Olsa {
1164acf6142SJiri Olsa 	zfree(&map->entries);
1174acf6142SJiri Olsa }
1184acf6142SJiri Olsa 
mem2node__node(struct mem2node * map,u64 addr)1194acf6142SJiri Olsa int mem2node__node(struct mem2node *map, u64 addr)
1204acf6142SJiri Olsa {
1214acf6142SJiri Olsa 	struct rb_node **p, *parent = NULL;
1224acf6142SJiri Olsa 	struct phys_entry *entry;
1234acf6142SJiri Olsa 
1244acf6142SJiri Olsa 	p = &map->root.rb_node;
1254acf6142SJiri Olsa 	while (*p != NULL) {
1264acf6142SJiri Olsa 		parent = *p;
1274acf6142SJiri Olsa 		entry = rb_entry(parent, struct phys_entry, rb_node);
1284acf6142SJiri Olsa 		if (addr < entry->start)
1294acf6142SJiri Olsa 			p = &(*p)->rb_left;
1304acf6142SJiri Olsa 		else if (addr >= entry->end)
1314acf6142SJiri Olsa 			p = &(*p)->rb_right;
1324acf6142SJiri Olsa 		else
1334acf6142SJiri Olsa 			goto out;
1344acf6142SJiri Olsa 	}
1354acf6142SJiri Olsa 
1364acf6142SJiri Olsa 	entry = NULL;
1374acf6142SJiri Olsa out:
1384acf6142SJiri Olsa 	return entry ? (int) entry->node : -1;
1394acf6142SJiri Olsa }
140