Blame placement.c

Packit 9eaa09
/* 
Packit 9eaa09
 * Copyright (C) 2006, Intel Corporation
Packit 9eaa09
 * Copyright (C) 2012, Neil Horman <nhoramn@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
#include "config.h"
Packit 9eaa09
#include <stdio.h>
Packit 9eaa09
#include <stdlib.h>
Packit 9eaa09
#include <unistd.h>
Packit 9eaa09
#include <stdint.h>
Packit 9eaa09
Packit 9eaa09
#include "types.h"
Packit 9eaa09
#include "irqbalance.h"
Packit 9eaa09
Packit 9eaa09
Packit 9eaa09
GList *rebalance_irq_list;
Packit 9eaa09
Packit 9eaa09
struct obj_placement {
Packit 9eaa09
		struct topo_obj *best;
Packit 9eaa09
		uint64_t best_cost;
Packit 9eaa09
		struct irq_info *info;
Packit 9eaa09
};
Packit 9eaa09
Packit 9eaa09
static void find_best_object(struct topo_obj *d, void *data)
Packit 9eaa09
{
Packit 9eaa09
	struct obj_placement *best = (struct obj_placement *)data;
Packit 9eaa09
	uint64_t newload;
Packit 9eaa09
Packit 9eaa09
	/*
Packit 9eaa09
 	 * Don't consider the unspecified numa node here
Packit 9eaa09
 	 */
Packit 9eaa09
	if (numa_avail && (d->obj_type == OBJ_TYPE_NODE) && (d->number == -1))
Packit 9eaa09
		return;
Packit 9eaa09
Packit 9eaa09
	/*
Packit 9eaa09
	 * also don't consider any node that doesn't have at least one cpu in
Packit 9eaa09
	 * the unbanned list
Packit 9eaa09
	 */
Packit 9eaa09
	if ((d->obj_type == OBJ_TYPE_NODE) &&
Packit 9eaa09
	    (!cpus_intersects(d->mask, unbanned_cpus)))
Packit 9eaa09
		return;
Packit 9eaa09
Packit 9eaa09
	if (d->powersave_mode)
Packit 9eaa09
		return;
Packit 9eaa09
Packit 9eaa09
	newload = d->load;
Packit 9eaa09
	if (newload < best->best_cost) {
Packit 9eaa09
		best->best = d;
Packit 9eaa09
		best->best_cost = newload;
Packit 9eaa09
	} else if (newload == best->best_cost) {
Packit 9eaa09
		if (g_list_length(d->interrupts) < g_list_length(best->best->interrupts)) {
Packit 9eaa09
			best->best = d;
Packit 9eaa09
		}
Packit 9eaa09
	}
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
static void find_best_object_for_irq(struct irq_info *info, void *data)
Packit 9eaa09
{
Packit 9eaa09
	struct obj_placement place;
Packit 9eaa09
	struct topo_obj *d = data;
Packit 9eaa09
	struct topo_obj *asign;
Packit 9eaa09
Packit 9eaa09
	if (!info->moved)
Packit 9eaa09
		return;
Packit 9eaa09
Packit 9eaa09
	switch (d->obj_type) {
Packit 9eaa09
	case OBJ_TYPE_NODE:
Packit 9eaa09
		if (info->level == BALANCE_NONE)
Packit 9eaa09
			return;
Packit 9eaa09
		break;
Packit 9eaa09
Packit 9eaa09
	case OBJ_TYPE_PACKAGE:
Packit 9eaa09
		if (info->level == BALANCE_PACKAGE)
Packit 9eaa09
			return;
Packit 9eaa09
		break;
Packit 9eaa09
Packit 9eaa09
	case OBJ_TYPE_CACHE:
Packit 9eaa09
		if (info->level == BALANCE_CACHE)
Packit 9eaa09
			return;
Packit 9eaa09
		break;
Packit 9eaa09
Packit 9eaa09
	case OBJ_TYPE_CPU:
Packit 9eaa09
		if (info->level == BALANCE_CORE)
Packit 9eaa09
			return;
Packit 9eaa09
		break;
Packit 9eaa09
	}
Packit 9eaa09
Packit 9eaa09
	place.info = info;
Packit 9eaa09
	place.best = NULL;
Packit 9eaa09
	place.best_cost = ULLONG_MAX;
Packit 9eaa09
Packit 9eaa09
	for_each_object(d->children, find_best_object, &place);
Packit 9eaa09
Packit 9eaa09
	asign = place.best;
Packit 9eaa09
Packit 9eaa09
	if (asign) {
Packit 9eaa09
		migrate_irq(&d->interrupts, &asign->interrupts, info);
Packit 9eaa09
		info->assigned_obj = asign;
Packit 9eaa09
		asign->load += info->load;
Packit 9eaa09
	}
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
static void place_irq_in_object(struct topo_obj *d, void *data __attribute__((unused)))
Packit 9eaa09
{
Packit 9eaa09
	if (g_list_length(d->interrupts) > 0)
Packit 9eaa09
		for_each_irq(d->interrupts, find_best_object_for_irq, d);
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
static void place_irq_in_node(struct irq_info *info, void *data __attribute__((unused)))
Packit 9eaa09
{
Packit 9eaa09
	struct obj_placement place;
Packit 9eaa09
	struct topo_obj *asign;
Packit 9eaa09
Packit 9eaa09
	if ((info->level == BALANCE_NONE) && cpus_empty(banned_cpus))
Packit 9eaa09
		return;
Packit 9eaa09
Packit 9eaa09
	if (irq_numa_node(info)->number != -1) {
Packit 9eaa09
		/*
Packit 9eaa09
		 * Need to make sure this node is elligible for migration
Packit 9eaa09
		 * given the banned cpu list
Packit 9eaa09
		 */
Packit 9eaa09
		if (!cpus_intersects(irq_numa_node(info)->mask, unbanned_cpus))
Packit 9eaa09
			goto find_placement;
Packit 9eaa09
		/*
Packit 9eaa09
 		 * This irq belongs to a device with a preferred numa node
Packit 9eaa09
 		 * put it on that node
Packit 9eaa09
 		 */
Packit 9eaa09
		migrate_irq(&rebalance_irq_list, &irq_numa_node(info)->interrupts, info);
Packit 9eaa09
		info->assigned_obj = irq_numa_node(info);
Packit 9eaa09
		irq_numa_node(info)->load += info->load + 1;
Packit 9eaa09
		return;
Packit 9eaa09
	}
Packit 9eaa09
Packit 9eaa09
find_placement:
Packit 9eaa09
	place.best_cost = ULLONG_MAX;
Packit 9eaa09
	place.best = NULL;
Packit 9eaa09
	place.info = info;
Packit 9eaa09
Packit 9eaa09
	for_each_object(numa_nodes, find_best_object, &place);
Packit 9eaa09
Packit 9eaa09
	asign = place.best;
Packit 9eaa09
Packit 9eaa09
	if (asign) {
Packit 9eaa09
		migrate_irq(&rebalance_irq_list, &asign->interrupts, info);
Packit 9eaa09
		info->assigned_obj = asign;
Packit 9eaa09
		asign->load += info->load;
Packit 9eaa09
	}
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
static void validate_irq(struct irq_info *info, void *data)
Packit 9eaa09
{
Packit 9eaa09
	if (info->assigned_obj != data)
Packit 9eaa09
		log(TO_CONSOLE, LOG_INFO, "object validation error: irq %d is wrong, points to %p, should be %p\n",
Packit 9eaa09
			info->irq, info->assigned_obj, data);
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
static void validate_object(struct topo_obj *d, void *data __attribute__((unused)))
Packit 9eaa09
{
Packit 9eaa09
	if (g_list_length(d->interrupts) > 0)
Packit 9eaa09
		for_each_irq(d->interrupts, validate_irq, d);
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
static void validate_object_tree_placement(void)
Packit 9eaa09
{
Packit 9eaa09
	for_each_object(packages, validate_object, NULL);	
Packit 9eaa09
	for_each_object(cache_domains, validate_object, NULL);
Packit 9eaa09
	for_each_object(cpus, validate_object, NULL);
Packit 9eaa09
}
Packit 9eaa09
Packit 9eaa09
void calculate_placement(void)
Packit 9eaa09
{
Packit 9eaa09
	sort_irq_list(&rebalance_irq_list);
Packit 9eaa09
	if (g_list_length(rebalance_irq_list) > 0) {
Packit 9eaa09
		for_each_irq(rebalance_irq_list, place_irq_in_node, NULL);
Packit 9eaa09
		for_each_object(numa_nodes, place_irq_in_object, NULL);
Packit 9eaa09
		for_each_object(packages, place_irq_in_object, NULL);
Packit 9eaa09
		for_each_object(cache_domains, place_irq_in_object, NULL);
Packit 9eaa09
	}
Packit 9eaa09
	if (debug_mode)
Packit 9eaa09
		validate_object_tree_placement();
Packit 9eaa09
}