Add new workload computation to irqbalance

This new workload calculator computes the average load at every balance level
and identifies each object at each level that is more than a standard deviation
away from the average.  For those above the average with more than one irq
assigned to them, those irqs are placed on the re-assignment list for
rebalancing until such time as the approximate reduction in load brings that
object back to the average.
This commit is contained in:
Neil Horman 2011-10-05 16:35:09 -04:00
parent d04c853443
commit 3953fec6e4
3 changed files with 98 additions and 3 deletions

View file

@ -24,7 +24,7 @@ AUTOMAKE_OPTIONS = no-dependencies
EXTRA_DIST = README INSTALL COPYING autogen.sh cap-ng.m4
INCLUDES = -I${top_srcdir}
LIBS = $(CAPNG_LDADD) $(GLIB_LIBS) -lnuma
LIBS = $(CAPNG_LDADD) $(GLIB_LIBS) -lnuma -lm
AM_CFLAGS = -g -Os -W -Wall -Wshadow -Wformat -Wundef $(GLIB_CFLAGS) -D_GNU_SOURCE
noinst_HEADERS = bitmap.h constants.h cpumask.h irqbalance.h non-atomic.h \
types.h

View file

@ -29,6 +29,7 @@
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <math.h>
#include "types.h"
#include "irqbalance.h"
@ -65,13 +66,107 @@ void build_workload(struct irq_info *info, void *unused __attribute__((unused)))
info->last_irq_count = info->irq_count;
}
struct load_balance_info {
unsigned long long int total_load;
unsigned long long avg_load;
int load_sources;
unsigned long long int deviations;
long double std_deviation;
};
static void gather_load_stats(struct common_obj_data *obj, void *data)
{
struct load_balance_info *info = data;
info->total_load += obj->load;
info->load_sources += 1;
}
static void compute_deviations(struct common_obj_data *obj, void *data)
{
struct load_balance_info *info = data;
unsigned long long int deviation;
deviation = (obj->load > info->avg_load) ?
obj->load - info->avg_load :
info->avg_load - obj->load;
info->deviations += (deviation * deviation);
}
static void move_candidate_irqs(struct irq_info *info, void *data)
{
int *remaining_deviation = (int *)data;
if (g_list_length(info->assigned_obj->interrupts) <= 1)
return;
if (*remaining_deviation <= 0)
return;
*remaining_deviation -= info->load;
migrate_irq(&info->assigned_obj->interrupts, &rebalance_irq_list, info);
info->assigned_obj = NULL;
}
static void migrate_overloaded_irqs(struct common_obj_data *obj, void *data)
{
struct load_balance_info *info = data;
int deviation;
/*
* Don't rebalance irqs on objects whos load is below the average
*/
if (obj->load <= info->avg_load)
return;
deviation = obj->load - info->avg_load;
if ((deviation > info->std_deviation) &&
(g_list_length(obj->interrupts) > 1)) {
/*
* We have a cpu that is overloaded and
* has irqs that can be moved to fix that
*/
/* order the list from least to greatest workload */
sort_irq_list(&obj->interrupts);
/*
* Each irq carries a weighted average amount of load
* we think its responsible for. Set deviation to be the load
* of the difference between this objects load and the averate,
* and migrate irqs until we only have one left, or until that
* difference reaches zero
*/
for_each_irq(NULL, move_candidate_irqs, &deviation);
}
}
#define find_overloaded_objs(name, info) do {\
memset(&(info), 0, sizeof(struct load_balance_info));\
for_each_##name(NULL, gather_load_stats, &(info));\
(info).avg_load = (info).total_load / (info).load_sources;\
for_each_##name(NULL, compute_deviations, &(info));\
(info).std_deviation = (long double)((info).deviations / ((info).load_sources));\
(info).std_deviation = sqrt((info).std_deviation);\
for_each_##name(NULL, migrate_overloaded_irqs, &(info));\
}while(0)
void calculate_workload(void)
{
int i;
struct load_balance_info info;
for (i=0; i<7; i++)
class_counts[i]=0;
for_each_irq(NULL, build_workload, NULL);
find_overloaded_objs(cpu_core, info);
find_overloaded_objs(cache_domain, info);
find_overloaded_objs(package, info);
find_overloaded_objs(numa_node, info);
}
static void reset_irq_count(struct irq_info *info, void *unused __attribute__((unused)))

View file

@ -127,8 +127,9 @@ static void assign_load_slice(struct irq_info *info, void *data)
info->load = (info->irq_count - info->last_irq_count) * *load_slice;
}
static void compute_irq_load_share(struct cpu_core *cpu, void *data __attribute__((unused)))
static void compute_irq_load_share(struct common_obj_data *d, void *data __attribute__((unused)))
{
struct cpu_core *cpu = (struct cpu_core *)d;
uint64_t total_irq_counts = 0;
uint64_t load_slice;
@ -146,7 +147,6 @@ void parse_proc_stat()
size_t size = 0;
int cpunr, rc, cpucount;
struct cpu_core *cpu;
struct common_obj_data *parent;
int irq_load, softirq_load;
file = fopen("/proc/stat", "r");