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:
parent
d04c853443
commit
3953fec6e4
|
@ -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
|
||||
|
|
95
irqlist.c
95
irqlist.c
|
@ -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)))
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in a new issue