Blame numa.c

Packit 9eaa09
/* 
Packit 9eaa09
 * Copyright (C) 2006, Intel Corporation
Packit 9eaa09
 * Copyright (C) 2012, Neil Horman <nhorman@tuxdriver.com> 
Packit 9eaa09
 * 
Packit 9eaa09
 * This file is part of irqbalance
Packit 9eaa09
 *
Packit 9eaa09
 * This program file is free software; you can redistribute it and/or modify it
Packit 9eaa09
 * under the terms of the GNU General Public License as published by the
Packit 9eaa09
 * Free Software Foundation; version 2 of the License.
Packit 9eaa09
 * 
Packit 9eaa09
 * This program is distributed in the hope that it will be useful, but WITHOUT
Packit 9eaa09
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit 9eaa09
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 9eaa09
 * for more details.
Packit 9eaa09
 * 
Packit 9eaa09
 * You should have received a copy of the GNU General Public License
Packit 9eaa09
 * along with this program in a file named COPYING; if not, write to the 
Packit 9eaa09
 * Free Software Foundation, Inc., 
Packit 9eaa09
 * 51 Franklin Street, Fifth Floor, 
Packit 9eaa09
 * Boston, MA 02110-1301 USA
Packit 9eaa09
 */
Packit 9eaa09
Packit 9eaa09
/*
Packit 9eaa09
 * This file tries to map numa affinity of pci devices to their interrupts
Packit 9eaa09
 * In addition the PCI class information is used to refine the classification
Packit 9eaa09
 * of interrupt sources 
Packit 9eaa09
 */
Packit 9eaa09
#include "config.h"
Packit 9eaa09
#include <unistd.h>
Packit 9eaa09
#include <stdlib.h>
Packit 9eaa09
#include <stdio.h>
Packit 9eaa09
#include <sys/types.h>
Packit 9eaa09
#include <dirent.h>
Packit 9eaa09
Packit 9eaa09
#include "irqbalance.h"
Packit 9eaa09
Packit 9eaa09
#define SYSFS_NODE_PATH "/sys/devices/system/node"
Packit 9eaa09
Packit 9eaa09
GList *numa_nodes = NULL;
Packit 9eaa09
Packit 9eaa09
static struct topo_obj unspecified_node_template = {
Packit 9eaa09
	.load = 0,
Packit 9eaa09
	.number = -1,
Packit 9eaa09
	.obj_type = OBJ_TYPE_NODE,
Packit 9eaa09
	.mask = CPU_MASK_ALL,
Packit 9eaa09
	.interrupts = NULL,
Packit 9eaa09
	.children = NULL,
Packit 9eaa09
	.parent = NULL,
Packit 9eaa09
	.obj_type_list = &numa_nodes,
Packit 9eaa09
};
Packit 9eaa09
Packit 9eaa09
static struct topo_obj unspecified_node;
Packit 9eaa09
Packit 9eaa09
static void add_one_node(const char *nodename)
Packit 9eaa09
{
Packit 9eaa09
	char path[PATH_MAX];
Packit 9eaa09
	struct topo_obj *new;
Packit 9eaa09
	char *cpustr = NULL;
Packit 9eaa09
	FILE *f;
Packit 9eaa09
	ssize_t ret;
Packit 9eaa09
	size_t blen;
Packit 9eaa09
Packit 9eaa09
	new = calloc(1, sizeof(struct topo_obj));
Packit 9eaa09
	if (!new)
Packit 9eaa09
		return;
Packit 9eaa09
	sprintf(path, "%s/%s/cpumap", SYSFS_NODE_PATH, nodename);
Packit 9eaa09
	f = fopen(path, "r");
Packit 9eaa09
	if (!f) {
Packit 9eaa09
		free(new);
Packit 9eaa09
		return;
Packit 9eaa09
	}
Packit 9eaa09
	if (ferror(f)) {
Packit 9eaa09
		cpus_clear(new->mask);
Packit 9eaa09
	} else {
Packit 9eaa09
		ret = getline(&cpustr, &blen, f);
Packit 9eaa09
		if (ret <= 0) {
Packit 9eaa09
			cpus_clear(new->mask);
Packit 9eaa09
		} else {
Packit 9eaa09
			cpumask_parse_user(cpustr, ret, new->mask);
Packit 9eaa09
			free(cpustr);
Packit 9eaa09
		}
Packit 9eaa09
	}
Packit 9eaa09
	fclose(f);
Packit 9eaa09
	new->obj_type = OBJ_TYPE_NODE;	
Packit 9eaa09
	new->number = strtoul(&nodename[4], NULL, 10);
Packit 9eaa09
	new->obj_type_list = &numa_nodes;
Packit 9eaa09
	numa_nodes = g_list_append(numa_nodes, new);
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
void build_numa_node_list(void)
Packit 9eaa09
{
Packit 9eaa09
	DIR *dir;
Packit 9eaa09
	struct dirent *entry;
Packit 9eaa09
Packit 9eaa09
	/*
Packit 9eaa09
	 * Note that we copy the unspcified node from the template here
Packit 9eaa09
	 * in the event we just freed the object tree during a rescan.
Packit 9eaa09
	 * This ensures we don't get stale list pointers anywhere
Packit 9eaa09
	 */
Packit 9eaa09
	memcpy(&unspecified_node, &unspecified_node_template, sizeof (struct topo_obj));
Packit 9eaa09
Packit 9eaa09
	/*
Packit 9eaa09
	 * Add the unspecified node
Packit 9eaa09
	 */
Packit 9eaa09
	numa_nodes = g_list_append(numa_nodes, &unspecified_node);
Packit 9eaa09
Packit 9eaa09
	if (!numa_avail)
Packit 9eaa09
		return;
Packit 9eaa09
Packit 9eaa09
	dir = opendir(SYSFS_NODE_PATH);
Packit 9eaa09
	if (!dir)
Packit 9eaa09
		return;
Packit 9eaa09
Packit 9eaa09
	do {
Packit 9eaa09
		entry = readdir(dir);
Packit 9eaa09
		if (!entry)
Packit 9eaa09
			break;
Packit 9eaa09
		if ((entry->d_type == DT_DIR) && (strstr(entry->d_name, "node"))) {
Packit 9eaa09
			add_one_node(entry->d_name);
Packit 9eaa09
		}
Packit 9eaa09
	} while (entry);
Packit 9eaa09
	closedir(dir);
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
static void free_numa_node(gpointer data)
Packit 9eaa09
{
Packit 9eaa09
	struct topo_obj *obj = data;
Packit 9eaa09
	g_list_free(obj->children);
Packit 9eaa09
	g_list_free(obj->interrupts);
Packit 9eaa09
Packit 9eaa09
	if (data != &unspecified_node)
Packit 9eaa09
		free(data);
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
void free_numa_node_list(void)
Packit 9eaa09
{
Packit 9eaa09
	g_list_free_full(numa_nodes, free_numa_node);
Packit 9eaa09
	numa_nodes = NULL;
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
static gint compare_node(gconstpointer a, gconstpointer b)
Packit 9eaa09
{
Packit 9eaa09
	const struct topo_obj *ai = a;
Packit 9eaa09
	const struct topo_obj *bi = b;
Packit 9eaa09
Packit 9eaa09
	return (ai->number == bi->number) ? 0 : 1;
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
void connect_cpu_mem_topo(struct topo_obj *p, void *data __attribute__((unused)))
Packit 9eaa09
{
Packit 9eaa09
	GList *entry;
Packit 9eaa09
	struct topo_obj *node;
Packit 9eaa09
	struct topo_obj *lchild;
Packit 9eaa09
	int len;
Packit 9eaa09
Packit 9eaa09
	len = g_list_length(p->numa_nodes);
Packit 9eaa09
Packit 9eaa09
	if (len == 0) {
Packit 9eaa09
		return;
Packit 9eaa09
	} else if (len > 1) {
Packit 9eaa09
		for_each_object(p->children, connect_cpu_mem_topo, NULL);
Packit 9eaa09
		return;
Packit 9eaa09
	}
Packit 9eaa09
Packit 9eaa09
	entry = g_list_first(p->numa_nodes);
Packit 9eaa09
	node = entry->data;
Packit 9eaa09
Packit 9eaa09
	if (p->obj_type == OBJ_TYPE_PACKAGE && !p->parent)
Packit 9eaa09
		p->parent = node;
Packit 9eaa09
Packit 9eaa09
	entry = g_list_first(node->children);
Packit 9eaa09
	while (entry) {
Packit 9eaa09
		lchild = entry->data;
Packit 9eaa09
		if (lchild == p)
Packit 9eaa09
			break;
Packit 9eaa09
		entry = g_list_next(entry);
Packit 9eaa09
	}
Packit 9eaa09
Packit 9eaa09
	if (!entry)
Packit 9eaa09
		node->children = g_list_append(node->children, p);
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
void dump_numa_node_info(struct topo_obj *d, void *unused __attribute__((unused)))
Packit 9eaa09
{
Packit 9eaa09
	char buffer[4096];
Packit 9eaa09
Packit 9eaa09
	log(TO_CONSOLE, LOG_INFO, "NUMA NODE NUMBER: %d\n", d->number);
Packit 9eaa09
	cpumask_scnprintf(buffer, 4096, d->mask); 
Packit 9eaa09
	log(TO_CONSOLE, LOG_INFO, "LOCAL CPU MASK: %s\n", buffer);
Packit 9eaa09
	log(TO_CONSOLE, LOG_INFO, "\n");
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
struct topo_obj *get_numa_node(int nodeid)
Packit 9eaa09
{
Packit 9eaa09
	struct topo_obj find;
Packit 9eaa09
	GList *entry;
Packit 9eaa09
Packit 9eaa09
	if (!numa_avail)
Packit 9eaa09
		return &unspecified_node;
Packit 9eaa09
Packit 9eaa09
	if (nodeid == -1)
Packit 9eaa09
		return &unspecified_node;
Packit 9eaa09
Packit 9eaa09
	find.number = nodeid;
Packit 9eaa09
Packit 9eaa09
	entry = g_list_find_custom(numa_nodes, &find, compare_node);
Packit 9eaa09
	return entry ? entry->data : NULL;
Packit 9eaa09
}
Packit 9eaa09