Implement user policy script callout
Issue 35: http://code.google.com/p/irqbalance/issues/detail?id=35 Indicated that the --banscript option wasn't really sufficient for user policy needs in irqbalance. As such, I've improved the implementation and added the --policyscript option, which allows for a script to return an arbitrary number of key=value pairs that can direct the behavior of irqbalance for individual irqs. Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
This commit is contained in:
parent
29ff67c301
commit
a8adea2e95
122
classify.c
122
classify.c
|
@ -51,6 +51,11 @@ static short class_codes[MAX_CLASS] = {
|
||||||
IRQ_OTHER,
|
IRQ_OTHER,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct user_irq_policy {
|
||||||
|
int ban;
|
||||||
|
int level;
|
||||||
|
};
|
||||||
|
|
||||||
static GList *interrupts_db;
|
static GList *interrupts_db;
|
||||||
static GList *new_irq_list;
|
static GList *new_irq_list;
|
||||||
static GList *banned_irqs;
|
static GList *banned_irqs;
|
||||||
|
@ -94,7 +99,7 @@ void add_banned_irq(int irq)
|
||||||
* devpath points to the device directory in sysfs for the
|
* devpath points to the device directory in sysfs for the
|
||||||
* related device
|
* related device
|
||||||
*/
|
*/
|
||||||
static struct irq_info *add_one_irq_to_db(const char *devpath, int irq)
|
static struct irq_info *add_one_irq_to_db(const char *devpath, int irq, struct user_irq_policy *pol)
|
||||||
{
|
{
|
||||||
int class = 0;
|
int class = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -158,7 +163,10 @@ static struct irq_info *add_one_irq_to_db(const char *devpath, int irq)
|
||||||
goto get_numa_node;
|
goto get_numa_node;
|
||||||
|
|
||||||
new->class = class_codes[class];
|
new->class = class_codes[class];
|
||||||
new->level = map_class_to_level[class_codes[class]];
|
if (pol->level >= 0)
|
||||||
|
new->level = pol->level;
|
||||||
|
else
|
||||||
|
new->level = map_class_to_level[class_codes[class]];
|
||||||
|
|
||||||
get_numa_node:
|
get_numa_node:
|
||||||
numa_node = -1;
|
numa_node = -1;
|
||||||
|
@ -208,6 +216,103 @@ out:
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void parse_user_policy_key(char *buf, struct user_irq_policy *pol)
|
||||||
|
{
|
||||||
|
char *key, *value, *end;
|
||||||
|
char *levelvals[] = { "none", "package", "cache", "core" };
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
key = buf;
|
||||||
|
value = strchr(buf, '=');
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
syslog(LOG_WARNING, "Bad format for policy, ignoring: %s\n", buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NULL terminate the key and advance value to the start of the value
|
||||||
|
* string
|
||||||
|
*/
|
||||||
|
*value = '\0';
|
||||||
|
value++;
|
||||||
|
end = strchr(value, '\n');
|
||||||
|
if (end)
|
||||||
|
*end = '\0';
|
||||||
|
|
||||||
|
if (!strcasecmp("ban", key)) {
|
||||||
|
if (!strcasecmp("false", value))
|
||||||
|
pol->ban = 0;
|
||||||
|
else if (!strcasecmp("true", value))
|
||||||
|
pol->ban = 1;
|
||||||
|
else {
|
||||||
|
if (!debug_mode)
|
||||||
|
syslog(LOG_WARNING, "Unknown value for ban poilcy: %s\n", value);
|
||||||
|
else
|
||||||
|
printf("Unknown value for ban poilcy: %s\n", value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (!strcasecmp("balance_level", key)) {
|
||||||
|
for (idx=0; idx<4; idx++) {
|
||||||
|
if (!strcasecmp(levelvals[idx], value))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx>3)
|
||||||
|
if (!debug_mode)
|
||||||
|
syslog(LOG_WARNING, "Bad value for balance_level policy: %s\n", value);
|
||||||
|
else
|
||||||
|
printf("Bad value for balance_level policy: %s\n", value);
|
||||||
|
else
|
||||||
|
pol->level = idx;
|
||||||
|
} else
|
||||||
|
if (!debug_mode)
|
||||||
|
syslog(LOG_WARNING, "Unknown key returned, ignoring: %s\n", key);
|
||||||
|
else
|
||||||
|
printf("Unknown key returned, ignoring: %s\n", key);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calls out to a possibly user defined script to get user assigned poilcy
|
||||||
|
* aspects for a given irq. A value of -1 in a given field indicates no
|
||||||
|
* policy was given and that system defaults should be used
|
||||||
|
*/
|
||||||
|
static void get_irq_user_policy(char *path, int irq, struct user_irq_policy *pol)
|
||||||
|
{
|
||||||
|
char *cmd;
|
||||||
|
FILE *output;
|
||||||
|
char buffer[128];
|
||||||
|
char *brc;
|
||||||
|
|
||||||
|
pol->ban = -1;
|
||||||
|
pol->level = -1;
|
||||||
|
|
||||||
|
/* Return defaults if no script was given */
|
||||||
|
if (!polscript)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cmd = alloca(strlen(path)+strlen(polscript)+64);
|
||||||
|
if (!cmd)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sprintf(cmd, "exec %s %s %d", polscript, path, irq);
|
||||||
|
output = popen(cmd, "r");
|
||||||
|
if (!output) {
|
||||||
|
if (debug_mode)
|
||||||
|
printf("Unable to execute user policy script %s\n", polscript);
|
||||||
|
else
|
||||||
|
syslog(LOG_WARNING, "Unable to execute user policy script %s\n", polscript);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!feof(output)) {
|
||||||
|
brc = fgets(buffer, 128, output);
|
||||||
|
if (brc)
|
||||||
|
parse_user_policy_key(brc, pol);
|
||||||
|
}
|
||||||
|
pclose(output);
|
||||||
|
}
|
||||||
|
|
||||||
static int check_for_irq_ban(char *path, int irq)
|
static int check_for_irq_ban(char *path, int irq)
|
||||||
{
|
{
|
||||||
char *cmd;
|
char *cmd;
|
||||||
|
@ -220,7 +325,7 @@ static int check_for_irq_ban(char *path, int irq)
|
||||||
if (!cmd)
|
if (!cmd)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sprintf(cmd, "%s %s %d",banscript, path, irq);
|
sprintf(cmd, "%s %s %d > /dev/null",banscript, path, irq);
|
||||||
rc = system(cmd);
|
rc = system(cmd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -256,6 +361,7 @@ static void build_one_dev_entry(const char *dirname)
|
||||||
int irqnum;
|
int irqnum;
|
||||||
struct irq_info *new;
|
struct irq_info *new;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
|
struct user_irq_policy pol;
|
||||||
|
|
||||||
sprintf(path, "%s/%s/msi_irqs", SYSDEV_DIR, dirname);
|
sprintf(path, "%s/%s/msi_irqs", SYSDEV_DIR, dirname);
|
||||||
|
|
||||||
|
@ -268,12 +374,13 @@ static void build_one_dev_entry(const char *dirname)
|
||||||
break;
|
break;
|
||||||
irqnum = strtol(entry->d_name, NULL, 10);
|
irqnum = strtol(entry->d_name, NULL, 10);
|
||||||
if (irqnum) {
|
if (irqnum) {
|
||||||
|
get_irq_user_policy(path, irqnum, &pol);
|
||||||
sprintf(path, "%s/%s", SYSDEV_DIR, dirname);
|
sprintf(path, "%s/%s", SYSDEV_DIR, dirname);
|
||||||
if (check_for_irq_ban(path, irqnum)) {
|
if ((pol.ban == 1) || (check_for_irq_ban(path, irqnum))) {
|
||||||
add_banned_irq(irqnum);
|
add_banned_irq(irqnum);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
new = add_one_irq_to_db(path, irqnum);
|
new = add_one_irq_to_db(path, irqnum, &pol);
|
||||||
if (!new)
|
if (!new)
|
||||||
continue;
|
continue;
|
||||||
new->type = IRQ_TYPE_MSIX;
|
new->type = IRQ_TYPE_MSIX;
|
||||||
|
@ -295,12 +402,13 @@ static void build_one_dev_entry(const char *dirname)
|
||||||
*/
|
*/
|
||||||
if (irqnum) {
|
if (irqnum) {
|
||||||
sprintf(path, "%s/%s", SYSDEV_DIR, dirname);
|
sprintf(path, "%s/%s", SYSDEV_DIR, dirname);
|
||||||
if (check_for_irq_ban(path, irqnum)) {
|
get_irq_user_policy(path, irqnum, &pol);
|
||||||
|
if ((pol.ban == 1) || (check_for_irq_ban(path, irqnum))) {
|
||||||
add_banned_irq(irqnum);
|
add_banned_irq(irqnum);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = add_one_irq_to_db(path, irqnum);
|
new = add_one_irq_to_db(path, irqnum, &pol);
|
||||||
if (!new)
|
if (!new)
|
||||||
goto done;
|
goto done;
|
||||||
new->type = IRQ_TYPE_LEGACY;
|
new->type = IRQ_TYPE_LEGACY;
|
||||||
|
|
22
irqbalance.1
22
irqbalance.1
|
@ -86,6 +86,28 @@ should be ignored by irqbalance completely (see --banirq above). Use of this
|
||||||
script provides users the ability to dynamically select which irqs get exluded
|
script provides users the ability to dynamically select which irqs get exluded
|
||||||
from balancing, and provides an opportunity for manual affinity setting in one
|
from balancing, and provides an opportunity for manual affinity setting in one
|
||||||
single code point.
|
single code point.
|
||||||
|
.B NOTE: The banscript option is deprecated. Please use the
|
||||||
|
.B --polscript option instead
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B --policyscript=<script>
|
||||||
|
An superset of the functionality found in the --banscript option. When
|
||||||
|
specified, the referenced script will execute once for each discovered irq The
|
||||||
|
script may specify zero or more key=value pairs that will guide irqbalance in
|
||||||
|
the management of that irq. The script will be passed the path to the sysfs
|
||||||
|
device that owns the irq and the irq number itself as the first and second
|
||||||
|
arguments. Key=value pairs are printed by the script on stdout, and will be
|
||||||
|
captured and interpreted by irqbalance. Irqbalance expects a zero exit code
|
||||||
|
from the provided utility. Recognized key=value pairs are:
|
||||||
|
.TP
|
||||||
|
.I ban=[true | false]
|
||||||
|
.tP
|
||||||
|
Directs irqbalance to exclude the passed in irq from balancing
|
||||||
|
.TP
|
||||||
|
.I balance_level=[none | package | cache | core]
|
||||||
|
This allows a user to override the balance level of a given irq. By default the
|
||||||
|
balance level is determined automatically based on the pci device class of the
|
||||||
|
device that owns the irq.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B --pid=<file>
|
.B --pid=<file>
|
||||||
|
|
17
irqbalance.c
17
irqbalance.c
|
@ -53,6 +53,7 @@ unsigned long power_thresh = ULONG_MAX;
|
||||||
unsigned long long cycle_count = 0;
|
unsigned long long cycle_count = 0;
|
||||||
char *pidfile = NULL;
|
char *pidfile = NULL;
|
||||||
char *banscript = NULL;
|
char *banscript = NULL;
|
||||||
|
char *polscript = NULL;
|
||||||
|
|
||||||
void sleep_approx(int seconds)
|
void sleep_approx(int seconds)
|
||||||
{
|
{
|
||||||
|
@ -77,6 +78,7 @@ struct option lopts[] = {
|
||||||
{"powerthresh", 1, NULL, 'p'},
|
{"powerthresh", 1, NULL, 'p'},
|
||||||
{"banirq", 1 , NULL, 'i'},
|
{"banirq", 1 , NULL, 'i'},
|
||||||
{"banscript", 1, NULL, 'b'},
|
{"banscript", 1, NULL, 'b'},
|
||||||
|
{"policyscript", 1, NULL, 'l'},
|
||||||
{"pid", 1, NULL, 's'},
|
{"pid", 1, NULL, 's'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
@ -84,7 +86,7 @@ struct option lopts[] = {
|
||||||
static void usage(void)
|
static void usage(void)
|
||||||
{
|
{
|
||||||
printf("irqbalance [--oneshot | -o] [--debug | -d] [--foreground | -f] [--hintpolicy= | -h [exact|subset|ignore]]\n");
|
printf("irqbalance [--oneshot | -o] [--debug | -d] [--foreground | -f] [--hintpolicy= | -h [exact|subset|ignore]]\n");
|
||||||
printf(" [--powerthresh= | -p <off> | <n>] [--banirq= | -i <n>]\n");
|
printf(" [--powerthresh= | -p <off> | <n>] [--banirq= | -i <n>] [--policyscript=<script>]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_command_line(int argc, char **argv)
|
static void parse_command_line(int argc, char **argv)
|
||||||
|
@ -94,7 +96,7 @@ static void parse_command_line(int argc, char **argv)
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
|
|
||||||
while ((opt = getopt_long(argc, argv,
|
while ((opt = getopt_long(argc, argv,
|
||||||
"odfh:i:p:s:b:",
|
"odfh:i:p:s:b:l:",
|
||||||
lopts, &longind)) != -1) {
|
lopts, &longind)) != -1) {
|
||||||
|
|
||||||
switch(opt) {
|
switch(opt) {
|
||||||
|
@ -132,6 +134,9 @@ static void parse_command_line(int argc, char **argv)
|
||||||
}
|
}
|
||||||
add_banned_irq((int)val);
|
add_banned_irq((int)val);
|
||||||
break;
|
break;
|
||||||
|
case 'l':
|
||||||
|
polscript = strdup(optarg);
|
||||||
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
if (!strncmp(optarg, "off", strlen(optarg)))
|
if (!strncmp(optarg, "off", strlen(optarg)))
|
||||||
power_thresh = ULONG_MAX;
|
power_thresh = ULONG_MAX;
|
||||||
|
@ -249,6 +254,14 @@ int main(int argc, char** argv)
|
||||||
printf("This machine seems not NUMA capable.\n");
|
printf("This machine seems not NUMA capable.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (banscript) {
|
||||||
|
char *note = "Please note that --banscript is deprecated, please use --policyscript instead";
|
||||||
|
if (debug_mode)
|
||||||
|
printf("%s\n", note);
|
||||||
|
else
|
||||||
|
syslog(LOG_WARNING, "%s\n", note);
|
||||||
|
}
|
||||||
|
|
||||||
action.sa_handler = handler;
|
action.sa_handler = handler;
|
||||||
sigemptyset(&action.sa_mask);
|
sigemptyset(&action.sa_mask);
|
||||||
action.sa_flags = 0;
|
action.sa_flags = 0;
|
||||||
|
|
|
@ -69,6 +69,7 @@ extern enum hp_e hint_policy;
|
||||||
extern unsigned long long cycle_count;
|
extern unsigned long long cycle_count;
|
||||||
extern unsigned long power_thresh;
|
extern unsigned long power_thresh;
|
||||||
extern char *banscript;
|
extern char *banscript;
|
||||||
|
extern char *polscript;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Numa node access routines
|
* Numa node access routines
|
||||||
|
|
Loading…
Reference in a new issue