Blame numa.c

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