mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC-PATCH] Improve Menu Governor Prediction of interrupted C states.
@ 2008-07-14 21:02 Woodruff, Richard
  2008-07-22  7:59 ` [linux-pm] " Wei, Gang
  0 siblings, 1 reply; 5+ messages in thread
From: Woodruff, Richard @ 2008-07-14 21:02 UTC (permalink / raw)
  To: Linux Power Management List; +Cc: Linux Kernel Mailing List

[-- Attachment #1: Type: text/plain, Size: 3606 bytes --]

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@ti.com>

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 #2: menu_gov_irq_guess.diff --]
[-- Type: application/octet-stream, Size: 2725 bytes --]

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);

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2008-08-06  1:52 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-07-14 21:02 [RFC-PATCH] Improve Menu Governor Prediction of interrupted C states Woodruff, Richard
2008-07-22  7:59 ` [linux-pm] " Wei, Gang
2008-07-23 18:59   ` Woodruff, Richard
2008-08-06  1:24   ` Woodruff, Richard
2008-08-06  1:51     ` Wei, Gang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®