Browse Source

Add irq choose strategy

Serj Kalichev 10 years ago
parent
commit
1be921fddb
3 changed files with 79 additions and 24 deletions
  1. 49 21
      balance.c
  2. 8 1
      balance.h
  3. 22 2
      birq.c

+ 49 - 21
balance.c

@@ -13,6 +13,7 @@
 #include "statistics.h"
 #include "cpu.h"
 #include "irq.h"
+#include "balance.h"
 
 /* Drop the dont_move flag on all IRQs for specified CPU */
 static int dec_weight(cpu_t *cpu, int value)
@@ -201,23 +202,35 @@ int apply_affinity(lub_list_t *balance_irqs)
 
 
 /* Count the number of intr-not-null IRQs and minimal IRQ weight */
-static int irq_list_info(lub_list_t *irqs, int *min_weight, unsigned int *irq_num)
+static int irq_list_info(lub_list_t *irqs, int *min_weight,
+	unsigned int *irq_num, unsigned int *candidates_num)
 {
 	lub_list_node_t *iter;
 
 	if (!irqs)
 		return -1;
 
-	*min_weight = -1;
-	*irq_num = 0;
+	if (min_weight)
+		*min_weight = -1;
+	if (irq_num)
+		*irq_num = 0;
+	if (candidates_num)
+		*candidates_num = 0;
 	for (iter = lub_list_iterator_init(irqs); iter;
 		iter = lub_list_iterator_next(iter)) {
 		irq_t *irq = (irq_t *)lub_list_node__get_data(iter);
 		if (irq->intr == 0)
 			continue;
-		if ((*min_weight < 0) || (irq->weight < *min_weight))
-			*min_weight = irq->weight;
-		*irq_num += 1;
+		if (min_weight) {
+			if ((*min_weight < 0) || (irq->weight < *min_weight))
+				*min_weight = irq->weight;
+		}
+		if (irq_num)
+			*irq_num += 1;
+		if (irq->weight)
+			continue;
+		if (candidates_num)
+			*candidates_num += 1;
 	}
 
 	return 0;
@@ -247,7 +260,7 @@ static cpu_t * most_overloaded_cpu(lub_list_t *cpus, float threshold)
 		if (lub_list_len(cpu->irqs) <= 1)
 			continue;
 
-		irq_list_info(cpu->irqs, &min_weight, &irq_num);
+		irq_list_info(cpu->irqs, &min_weight, &irq_num, NULL);
 		/* All IRQs has intr=0 */
 		if (irq_num == 0)
 			continue;
@@ -266,20 +279,29 @@ static cpu_t * most_overloaded_cpu(lub_list_t *cpus, float threshold)
    another CPU. The best IRQ is IRQ with maximum number of interrupts.
    The IRQs with small number of interrupts have very low load or very
    high load (in a case of NAPI). */
-int choose_irqs_to_move(lub_list_t *cpus, lub_list_t *balance_irqs, float threshold)
+int choose_irqs_to_move(lub_list_t *cpus, lub_list_t *balance_irqs,
+	float threshold, birq_choose_strategy_e strategy)
 {
 	lub_list_node_t *iter;
 	cpu_t *overloaded_cpu = NULL;
-	irq_t *max_irq = NULL;
-	irq_t *min_irq = NULL;
 	irq_t *irq_to_move = NULL;
 	unsigned long long max_intr = 0;
 	unsigned long long min_intr = (unsigned long long)(-1);
+	unsigned int choose = 0;
+	unsigned int current = 0;
 
 	/* Search for overloaded CPUs */
 	if (!(overloaded_cpu = most_overloaded_cpu(cpus, threshold)))
 		return 0;
 
+	if (strategy == BIRQ_CHOOSE_RND) {
+		unsigned int candidates = 0;
+		irq_list_info(overloaded_cpu->irqs, NULL, NULL, &candidates);
+		if (candidates == 0)
+			return 0;
+		choose = rand() % candidates;
+	}
+
 	/* Search for the IRQ (owned by overloaded CPU) with
 	   maximum/minimum number of interrupts. */
 	for (iter = lub_list_iterator_init(overloaded_cpu->irqs); iter;
@@ -292,20 +314,26 @@ int choose_irqs_to_move(lub_list_t *cpus, lub_list_t *balance_irqs, float thresh
 			continue;
 		if (irq->weight)
 			continue;
-		/* Get IRQ with max intr */
-		if (irq->intr > max_intr) {
-			max_intr = irq->intr;
-			max_irq = irq;
-		}
-		/* Get IRQ with min intr */
-		if (irq->intr < min_intr) {
-			min_intr = irq->intr;
-			min_irq = irq;
+		if (strategy == BIRQ_CHOOSE_MAX) {
+			/* Get IRQ with max intr */
+			if (irq->intr > max_intr) {
+				max_intr = irq->intr;
+				irq_to_move = irq;
+			}
+		} else if (strategy == BIRQ_CHOOSE_MIN) {
+			/* Get IRQ with min intr */
+			if (irq->intr < min_intr) {
+				min_intr = irq->intr;
+				irq_to_move = irq;
+			}
+		} else if (strategy == BIRQ_CHOOSE_RND) {
+			if (current == choose)
+				irq_to_move = irq;
+			break;
 		}
+		current++;
 	}
 
-	irq_to_move = min_irq;
-	irq_to_move = max_irq;
 	if (irq_to_move) {
 		/* Don't move this IRQ while next iteration. */
 		irq_to_move->weight = 1;

+ 8 - 1
balance.h

@@ -5,8 +5,15 @@
 #include "irq.h"
 #include "cpu.h"
 
+typedef enum {
+	BIRQ_CHOOSE_MAX,
+	BIRQ_CHOOSE_MIN,
+	BIRQ_CHOOSE_RND
+} birq_choose_strategy_e;
+
 int balance(lub_list_t *cpus, lub_list_t *balance_irqs, float threshold);
 int apply_affinity(lub_list_t *balance_irqs);
-int choose_irqs_to_move(lub_list_t *cpus, lub_list_t *balance_irqs, float threshold);
+int choose_irqs_to_move(lub_list_t *cpus, lub_list_t *balance_irqs,
+	float threshold, birq_choose_strategy_e strategy);
 
 #endif

+ 22 - 2
birq.c

@@ -55,6 +55,7 @@ struct options {
 	int ht;
 	unsigned int long_interval;
 	unsigned int short_interval;
+	birq_choose_strategy_e strategy;
 };
 
 /*--------------------------------------------------------- */
@@ -122,6 +123,9 @@ int main(int argc, char **argv)
 	sigaction(SIGINT, &sig_act, NULL);
 	sigaction(SIGQUIT, &sig_act, NULL);
 
+	/* Randomize */
+	srand(time(NULL));
+
 	/* Scan CPUs */
 	cpus = lub_list_new(cpu_list_compare);
 	scan_cpus(cpus, opts->ht);
@@ -157,7 +161,7 @@ int main(int argc, char **argv)
 		   Don't choose IRQ if we already have new IRQs to balance */
 		if (lub_list_len(balance_irqs) == 0) {
 			choose_irqs_to_move(cpus, balance_irqs,
-				opts->threshold);
+				opts->threshold, opts->strategy);
 		}
 		/* If nothing to balance */
 		if (lub_list_len(balance_irqs) != 0) {
@@ -228,6 +232,7 @@ static struct options *opts_init(void)
 	opts->ht = 0;
 	opts->long_interval = BIRQ_LONG_INTERVAL;
 	opts->short_interval = BIRQ_SHORT_INTERVAL;
+	opts->strategy = BIRQ_CHOOSE_MAX;
 
 	return opts;
 }
@@ -245,7 +250,7 @@ static void opts_free(struct options *opts)
 /* Parse command line options */
 static int opts_parse(int argc, char *argv[], struct options *opts)
 {
-	static const char *shortopts = "hp:dO:t:vri:I:";
+	static const char *shortopts = "hp:dO:t:vri:I:c:";
 #ifdef HAVE_GETOPT_H
 	static const struct option longopts[] = {
 		{"help",		0, NULL, 'h'},
@@ -257,6 +262,7 @@ static int opts_parse(int argc, char *argv[], struct options *opts)
 		{"ht",			0, NULL, 'r'},
 		{"short-interval",	1, NULL, 'i'},
 		{"long-interval",	1, NULL, 'i'},
+		{"choose",		1, NULL, 'c'},
 		{NULL,			0, NULL, 0}
 	};
 #endif
@@ -325,6 +331,19 @@ static int opts_parse(int argc, char *argv[], struct options *opts)
 				opts->long_interval = val;
 			}
 			break;
+		case 'c':
+			if (!strcmp(optarg, "max"))
+				opts->strategy = BIRQ_CHOOSE_MAX;
+			else if (!strcmp(optarg, "min"))
+				opts->strategy = BIRQ_CHOOSE_MIN;
+			else if (!strcmp(optarg, "rnd"))
+				opts->strategy = BIRQ_CHOOSE_RND;
+			else {
+				fprintf(stderr, "Error: Illegal strategy value %s.\n", optarg);
+				help(-1, argv[0]);
+				exit(-1);
+			}
+			break;
 		case 'h':
 			help(0, argv[0]);
 			exit(0);
@@ -373,5 +392,6 @@ static void help(int status, const char *argv0)
 		printf("\t-t <float>, --threshold=<float>\tThreshold to consider CPU is overloaded, in percents.\n");
 		printf("\t-i <sec>, --short-interval=<sec>\tShort iteration interval.\n");
 		printf("\t-I <sec>, --long-interval=<sec>\tLong iteration interval.\n");
+		printf("\t-c <strategy>, --choose=<strategy>\tStrategy to choose IRQ to move (min/max/rnd).\n");
 	}
 }