Blame irqlist.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 has the basic functions to manipulate interrupt metadata
Packit Service 2212bb
 */
Packit Service 2212bb
#include "config.h"
Packit Service 2212bb
#include <stdio.h>
Packit Service 2212bb
#include <stdlib.h>
Packit Service 2212bb
#include <unistd.h>
Packit Service 2212bb
#include <sys/types.h>
Packit Service 2212bb
#include <dirent.h>
Packit Service 2212bb
#include <errno.h>
Packit Service 2212bb
#include <math.h>
Packit Service 2212bb
Packit Service 2212bb
#include "types.h"
Packit Service 2212bb
#include "irqbalance.h"
Packit Service 2212bb
Packit Service 2212bb
Packit Service 2212bb
Packit Service 2212bb
struct load_balance_info {
Packit Service 2212bb
	unsigned long long int total_load;
Packit Service 2212bb
	unsigned long long avg_load;
Packit Service 2212bb
	unsigned long long min_load;
Packit Service 2212bb
	unsigned long long adjustment_load;
Packit Service 2212bb
	int load_sources;
Packit Service 2212bb
	unsigned long long int deviations;
Packit Service 2212bb
	long double std_deviation;
Packit Service 2212bb
	unsigned int num_over;
Packit Service 2212bb
	unsigned int num_under;
Packit Service 2212bb
	unsigned int num_powersave;
Packit Service 2212bb
	struct topo_obj *powersave;
Packit Service 2212bb
};
Packit Service 2212bb
Packit Service 2212bb
static void gather_load_stats(struct topo_obj *obj, void *data)
Packit Service 2212bb
{
Packit Service 2212bb
	struct load_balance_info *info = data;
Packit Service 2212bb
Packit Service 2212bb
	if (info->load_sources == 0 || obj->load < info->min_load)
Packit Service 2212bb
		info->min_load = obj->load;
Packit Service 2212bb
	info->total_load += obj->load;
Packit Service 2212bb
	info->load_sources += 1;
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
static void compute_deviations(struct topo_obj *obj, void *data)
Packit Service 2212bb
{
Packit Service 2212bb
	struct load_balance_info *info = data;
Packit Service 2212bb
	unsigned long long int deviation;
Packit Service 2212bb
Packit Service 2212bb
	deviation = (obj->load > info->avg_load) ?
Packit Service 2212bb
		obj->load - info->avg_load :
Packit Service 2212bb
		info->avg_load - obj->load;
Packit Service 2212bb
Packit Service 2212bb
	info->deviations += (deviation * deviation);
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
static void move_candidate_irqs(struct irq_info *info, void *data)
Packit Service 2212bb
{
Packit Service 2212bb
	struct load_balance_info *lb_info = data;
Packit Service 2212bb
Packit Service 2212bb
	/* Don't rebalance irqs that don't want it */
Packit Service 2212bb
	if (info->level == BALANCE_NONE)
Packit Service 2212bb
		return;
Packit Service 2212bb
Packit Service 2212bb
	/* Don't move cpus that only have one irq, regardless of load */
Packit Service 2212bb
	if (g_list_length(info->assigned_obj->interrupts) <= 1)
Packit Service 2212bb
		return;
Packit Service 2212bb
Packit Service 2212bb
	/* IRQs with a load of 1 have most likely not had any interrupts and
Packit Service 2212bb
	 * aren't worth migrating
Packit Service 2212bb
	 */
Packit Service 2212bb
	if (info->load <= 1)
Packit Service 2212bb
		return;
Packit Service 2212bb
Packit Service 2212bb
	/* If we can migrate an irq without swapping the imbalance do it. */
Packit Service 2212bb
	if ((lb_info->adjustment_load - info->load) > (lb_info->min_load + info->load)) {
Packit Service 2212bb
		lb_info->adjustment_load -= info->load;
Packit Service 2212bb
		lb_info->min_load += info->load;
Packit Service 2212bb
	} else
Packit Service 2212bb
		return;
Packit Service 2212bb
Packit Service 2212bb
	log(TO_CONSOLE, LOG_INFO, "Selecting irq %d for rebalancing\n", info->irq);
Packit Service 2212bb
Packit Service 2212bb
	migrate_irq(&info->assigned_obj->interrupts, &rebalance_irq_list, info);
Packit Service 2212bb
Packit Service 2212bb
	info->assigned_obj = NULL;
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
static void migrate_overloaded_irqs(struct topo_obj *obj, void *data)
Packit Service 2212bb
{
Packit Service 2212bb
	struct load_balance_info *info = data;
Packit Service 2212bb
Packit Service 2212bb
	if (obj->powersave_mode)
Packit Service 2212bb
		info->num_powersave++;
Packit Service 2212bb
Packit Service 2212bb
	if ((obj->load + info->std_deviation) <= info->avg_load) {
Packit Service 2212bb
		info->num_under++;
Packit Service 2212bb
		if (power_thresh != ULONG_MAX && !info->powersave)
Packit Service 2212bb
			if (!obj->powersave_mode)
Packit Service 2212bb
				info->powersave = obj;
Packit Service 2212bb
	} else if ((obj->load - info->std_deviation) >=info->avg_load) {
Packit Service 2212bb
		info->num_over++;
Packit Service 2212bb
	}
Packit Service 2212bb
Packit Service 2212bb
	if ((obj->load > info->min_load) &&
Packit Service 2212bb
	    (g_list_length(obj->interrupts) > 1)) {
Packit Service 2212bb
		/* order the list from greatest to least workload */
Packit Service 2212bb
		sort_irq_list(&obj->interrupts);
Packit Service 2212bb
		/*
Packit Service 2212bb
		 * Each irq carries a weighted average amount of load
Packit Service 2212bb
		 * we think it's responsible for. This object's load is larger
Packit Service 2212bb
		 * than the object with the minimum load. Select irqs for
Packit Service 2212bb
		 * migration if we could move them to the minimum object
Packit Service 2212bb
		 * without reversing the imbalance or until we only have one
Packit Service 2212bb
		 * left.
Packit Service 2212bb
		 */
Packit Service 2212bb
		info->adjustment_load = obj->load;
Packit Service 2212bb
		for_each_irq(obj->interrupts, move_candidate_irqs, info);
Packit Service 2212bb
	}
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
static void force_irq_migration(struct irq_info *info, void *data __attribute__((unused)))
Packit Service 2212bb
{
Packit Service 2212bb
	migrate_irq(&info->assigned_obj->interrupts, &rebalance_irq_list, info);
Packit Service 2212bb
	info->assigned_obj = NULL;
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
static void clear_powersave_mode(struct topo_obj *obj, void *data __attribute__((unused)))
Packit Service 2212bb
{
Packit Service 2212bb
	obj->powersave_mode = 0;
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
static void find_overloaded_objs(GList *name, struct load_balance_info *info) {
Packit Service 2212bb
	memset(info, 0, sizeof(struct load_balance_info));
Packit Service 2212bb
	for_each_object(name, gather_load_stats, info);
Packit Service 2212bb
	info->load_sources = (info->load_sources == 0) ? 1 : (info->load_sources);
Packit Service 2212bb
	info->avg_load = info->total_load / info->load_sources;
Packit Service 2212bb
	for_each_object(name, compute_deviations, info);
Packit Service 2212bb
	/* Don't divide by zero if there is a single load source */
Packit Service 2212bb
	if (info->load_sources == 1)
Packit Service 2212bb
		info->std_deviation = 0;
Packit Service 2212bb
	else {
Packit Service 2212bb
		info->std_deviation = (long double)(info->deviations / (info->load_sources - 1));
Packit Service 2212bb
		info->std_deviation = sqrt(info->std_deviation);
Packit Service 2212bb
	}
Packit Service 2212bb
Packit Service 2212bb
	for_each_object(name, migrate_overloaded_irqs, info);
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
void update_migration_status(void)
Packit Service 2212bb
{
Packit Service 2212bb
	struct load_balance_info info;
Packit Service 2212bb
	find_overloaded_objs(cpus, &info;;
Packit Service 2212bb
	if (power_thresh != ULONG_MAX && cycle_count > 5) {
Packit Service 2212bb
		if (!info.num_over && (info.num_under >= power_thresh) && info.powersave) {
Packit Service 2212bb
			log(TO_ALL, LOG_INFO, "cpu %d entering powersave mode\n", info.powersave->number);
Packit Service 2212bb
			info.powersave->powersave_mode = 1;
Packit Service 2212bb
			if (g_list_length(info.powersave->interrupts) > 0)
Packit Service 2212bb
				for_each_irq(info.powersave->interrupts, force_irq_migration, NULL);
Packit Service 2212bb
		} else if ((info.num_over) && (info.num_powersave)) {
Packit Service 2212bb
			log(TO_ALL, LOG_INFO, "Load average increasing, re-enabling all cpus for irq balancing\n");
Packit Service 2212bb
			for_each_object(cpus, clear_powersave_mode, NULL);
Packit Service 2212bb
		}
Packit Service 2212bb
	}
Packit Service 2212bb
	find_overloaded_objs(cache_domains, &info;;
Packit Service 2212bb
	find_overloaded_objs(packages, &info;;
Packit Service 2212bb
	find_overloaded_objs(numa_nodes, &info;;
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
static void dump_workload(struct irq_info *info, void *unused __attribute__((unused)))
Packit Service 2212bb
{
Packit Service 2212bb
	log(TO_CONSOLE, LOG_INFO, "Interrupt %i node_num %d (class %s) has workload %lu \n",
Packit Service 2212bb
	    info->irq, irq_numa_node(info)->number, classes[info->class], (unsigned long)info->load);
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
void dump_workloads(void)
Packit Service 2212bb
{
Packit Service 2212bb
	for_each_irq(NULL, dump_workload, NULL);
Packit Service 2212bb
}
Packit Service 2212bb