[RFC-PATCH] Improve Menu Governor Prediction of interrupted Cstates.

From: Woodruff, Richard
Date: Mon Jul 14 2008 - 17:02:25 EST


Hi,

Any comments on the following?

I'm finding with high interrupt rates for some USB devices the menu governor guesses wrong enough that throughput drops.

With the below tweak tests with fixed data sizes which were taking 12s to complete drop back to 9s. Also my standby idle doesn't change before and after activity with our with out the patch.

What it does is simply timestamp incoming irqs, then in the menu governor will use current & last irq time delta to refine its guess as to how long sleep will happen.

Regards,
Richard W.

Signed-off-by: Richard Woodruff <r-woodruff2@xxxxxx>

diff -purN img/2.6_kernel/arch/arm/kernel/irq.c 2.6_kernel/arch/arm/kernel/irq.c
--- img/2.6_kernel/arch/arm/kernel/irq.c 2008-04-03 22:43:09.000000000 -0500
+++ 2.6_kernel/arch/arm/kernel/irq.c 2008-07-14 15:09:48.000000000 -0500
@@ -122,6 +131,8 @@ asmlinkage void __exception asm_do_IRQ(u

irq_enter();

+ kstat_irq_stamp();
+
desc_handle_irq(irq, desc);

/* AT91 specific workaround */
diff -purN img/2.6_kernel/drivers/cpuidle/governors/menu.c 2.6_kernel/drivers/cpuidle/governors/menu.c
--- img/2.6_kernel/drivers/cpuidle/governors/menu.c 2008-07-04 15:31:23.000000000 -0500
+++ 2.6_kernel/drivers/cpuidle/governors/menu.c 2008-07-14 15:22:55.000000000 -0500
@@ -7,6 +7,7 @@
*/

#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
#include <linux/cpuidle.h>
#include <linux/latency.h>
#include <linux/time.h>
@@ -70,6 +71,7 @@ static void menu_reflect(struct cpuidle_
unsigned int measured_us =
cpuidle_get_last_residency(dev) + data->elapsed_us;
struct cpuidle_state *target = &dev->states[last_idx];
+ const unsigned int cpu = smp_processor_id();

/*
* Ugh, this idle state doesn't support residency measurements, so we
@@ -92,6 +94,10 @@ static void menu_reflect(struct cpuidle_
data->elapsed_us = -1;
data->predicted_us = max(measured_us, data->last_measured_us);
}
+
+ /* Guess & factor in interrupt wake rate */
+ data->predicted_us = min((s64)data->predicted_us, ktime_to_us(
+ ktime_sub(kstat_cpu(cpu).irq_now, kstat_cpu(cpu).irq_last)));
}

/**
diff -purN img/2.6_kernel/include/linux/kernel_stat.h 2.6_kernel/include/linux/kernel_stat.h
--- img/2.6_kernel/include/linux/kernel_stat.h 2008-04-03 21:51:50.000000000 -0500
+++ 2.6_kernel/include/linux/kernel_stat.h 2008-07-14 13:11:09.000000000 -0500
@@ -7,6 +7,7 @@
#include <linux/percpu.h>
#include <linux/cpumask.h>
#include <asm/cputime.h>
+#include <linux/hrtimer.h>

/*
* 'kernel_stat.h' contains the definitions needed for doing
@@ -29,6 +30,8 @@ struct cpu_usage_stat {
struct kernel_stat {
struct cpu_usage_stat cpustat;
unsigned int irqs[NR_IRQS];
+ ktime_t irq_now;
+ ktime_t irq_last;
};

DECLARE_PER_CPU(struct kernel_stat, kstat);
@@ -52,6 +55,16 @@ static inline int kstat_irqs(int irq)
return sum;
}

+/*
+ * Provide hook to try and understand interrupt rate on a processor
+ */
+static inline void kstat_irq_stamp(void)
+{
+ const unsigned int cpu = smp_processor_id();
+ kstat_cpu(cpu).irq_last = kstat_cpu(cpu).irq_now;
+ kstat_cpu(cpu).irq_now = ktime_get();
+}
+
extern void account_user_time(struct task_struct *, cputime_t);
extern void account_user_time_scaled(struct task_struct *, cputime_t);
extern void account_system_time(struct task_struct *, int, cputime_t);

Attachment: menu_gov_irq_guess.diff
Description: menu_gov_irq_guess.diff