Re: [linux-pm] [PATCH] cpuidle: avoid singing capacitors



On Wed, 5 Mar 2008 09:40:23 +0100
Pierre Ossman <drzeus-list@xxxxxxxxx> wrote:


So I need to build some global algorithm instead of one per core. Ideas are welcome.


I'm currently trying this variant. No noise yet, but the time spent in C3 seems to take a massive hit. I'll see if I can get around to some kind of power measurement (ideas for doing that in a sane way are still welcome btw).

diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 78d77c5..960aa39 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -16,6 +16,11 @@

#define BREAK_FUZZ 4 /* 4 us */

+static unsigned int min_deep_sleep = 0;
+static unsigned int failed_deep = 0;
+
+static unsigned long global_last_deep;
+
struct menu_device {
int last_state_idx;

@@ -23,6 +28,8 @@ struct menu_device {
unsigned int predicted_us;
unsigned int last_measured_us;
unsigned int elapsed_us;
+
+ unsigned long last_deep;
};

static DEFINE_PER_CPU(struct menu_device, menu_devices);
@@ -50,9 +57,51 @@ static int menu_select(struct cpuidle_device *dev)
break;
if (s->exit_latency > pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY))
break;
+
+ /*
+ * In order to avoid the problem of "singing capacitors",
+ * don't enter a deep sleep for short durations (2 ms seems
+ * to do the trick). This will, hopefully, keep the problem
+ * inaudible.
+ */
+ if (min_deep_sleep && (s->flags & CPUIDLE_FLAG_DEEP)) {
+ if (time_before_eq(jiffies, data->last_deep +
+ HZ * min_deep_sleep / USEC_PER_SEC))
+ break;
+
+ rmb();
+
+ if (time_before_eq(jiffies, global_last_deep +
+ HZ * min_deep_sleep / USEC_PER_SEC))
+ break;
+
+#if 0
+ if (min_deep_sleep > data->expected_us)
+ break;
+ if (min_deep_sleep > cpuidle_get_last_residency(dev))
+ break;
+#endif
+#if 0
+ if (min_deep_sleep > data->predicted_us)
+ break;
+ if (min_deep_sleep > data->last_measured_us)
+ break;
+#endif
+ }
}

data->last_state_idx = i - 1;
+
+ if (dev->states[i - 1].flags & CPUIDLE_FLAG_DEEP) {
+#if 0
+ printk("Sleep interval: %ld jiffies\n",
+ jiffies - data->last_deep);
+#endif
+ data->last_deep = jiffies;
+ global_last_deep = jiffies;
+ wmb();
+ }
+
return i - 1;
}

@@ -80,6 +129,15 @@ static void menu_reflect(struct cpuidle_device *dev)
if (!(target->flags & CPUIDLE_FLAG_TIME_VALID))
measured_us = USEC_PER_SEC / HZ;

+ if ((target->flags & CPUIDLE_FLAG_DEEP) &&
+ (cpuidle_get_last_residency(dev) < min_deep_sleep)) {
+#if 0
+ printk("F: %d / %d,%d\n", cpuidle_get_last_residency(dev),
+ data->expected_us,data->predicted_us);
+#endif
+ failed_deep++;
+ }
+
/* Predict time remaining until next break event */
if (measured_us + BREAK_FUZZ < data->expected_us - target->exit_latency) {
data->predicted_us = max(measured_us, data->last_measured_us);
@@ -102,7 +160,14 @@ static int menu_enable_device(struct cpuidle_device *dev)
{
struct menu_device *data = &per_cpu(menu_devices, dev->cpu);

+ printk("Attaching menu governor...\n");
+
memset(data, 0, sizeof(struct menu_device));
+ /*
+ * 0 might be slightly ahead of the current jiffies count, so
+ * it's a bad initial value.
+ */
+ data->last_deep = jiffies;

return 0;
}
@@ -121,6 +186,8 @@ static struct cpuidle_governor menu_governor = {
*/
static int __init init_menu(void)
{
+ global_last_deep = jiffies;
+
return cpuidle_register_governor(&menu_governor);
}

@@ -132,6 +199,11 @@ static void __exit exit_menu(void)
cpuidle_unregister_governor(&menu_governor);
}

+module_param(min_deep_sleep, uint, 0644)
+MODULE_PARM_DESC(min_deep_sleep, "min time (us) to spend in deep sleep to avoid noise")
+
+module_param(failed_deep, uint, 0644)
+
MODULE_LICENSE("GPL");
module_init(init_menu);
module_exit(exit_menu);


Rgds
--
-- Pierre Ossman

Linux kernel, MMC maintainer http://www.kernel.org
PulseAudio, core developer http://pulseaudio.org
rdesktop, core developer http://www.rdesktop.org
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



Relevant Pages

  • Re: Still get build warnings - gcc-3.4.6 - 2.6.17.8
    ... EXPORT_SYMBOL generates "is deprecated" noise ... More majordomo info at http://vger.kernel.org/majordomo-info.html ... Please read the FAQ at http://www.tux.org/lkml/ ...
    (Linux-Kernel)
  • Re: 2.6.7-rc2-mm1: compile error in kernel/exit.c
    ... (to get rid of the noise generated by my Dell Inspiron 4000): ... To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/ ...
    (Linux-Kernel)
  • Re: csh : Existance of Environment Variable
    ... variale exists. ... grep Undefined $tempfile ... Sorry for the noise ...
    (comp.unix.shell)
  • Re: VIM - indent rules
    ... mpg wrote: ... Sorry for the noise. ...
    (comp.editors)
  • Re: Database in CE 3.0 ...
    ... To use the ADOCE in wince 3.0 not is easy. ... CLSID tClsid; ... VARIANT varConnected; ...
    (microsoft.public.windowsce.embedded.vc)