Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 2707

kernel-2.6.18-128.1.10.el5.src.rpm

From: Markus Armbruster <armbru@redhat.com>
Date: Wed, 2 Jan 2008 16:34:43 +0100
Subject: [xen] idle=poll instead of hypercall block
Message-id: 87wsqsutpo.fsf@pike.pond.sub.org
O-Subject: [PATCH RHEL-5.2] 416141: idle=poll
Bugzilla: 416141

This patch adds a idle=poll kernel parameter, which makes the kernel
use a polling loop rather than a hypercall to block.  This is useful
to profile the amount of sleep cycles when using xenoprof.

This is actually an attempt to salvage a possibly useful part from the
shipwrecked bug 241982.

The patch has been tested as part of various incarnations of bug
241982's patch.  It hasn't changed along the way.  It's been upstream
for a year.

In my personal opinion, RHEL-5's xenoprof is a lost cause, and adding
features to it feels like putting lipstick on a pig.  But the lipstick
is fully acked, so why not stick to the proper protocol: please ACK or
NACK.

xen-unstable.hg changesets trivially rediffed:
13213:bf25488db8eb
13217:338ceb7b1f09

Acked-by: Bill Burns <bburns@redhat.com>
Acked-by: "Stephen C. Tweedie" <sct@redhat.com>

diff --git a/arch/i386/kernel/process-xen.c b/arch/i386/kernel/process-xen.c
index 6cad288..11522ba 100644
--- a/arch/i386/kernel/process-xen.c
+++ b/arch/i386/kernel/process-xen.c
@@ -96,8 +96,24 @@ void enable_hlt(void)
 
 EXPORT_SYMBOL(enable_hlt);
 
-/* XXX XEN doesn't use default_idle(), poll_idle(). Use xen_idle() instead. */
-void xen_idle(void)
+/*
+ * On SMP it's slightly faster (but much more power-consuming!)
+ * to poll the ->work.need_resched flag instead of waiting for the
+ * cross-CPU IPI to arrive. Use this option with caution.
+ */
+static void poll_idle(void)
+{
+	local_irq_enable();
+
+	asm volatile(
+		"2:"
+		"testl %0, %1;"
+		"rep; nop;"
+		"je 2b;"
+		: : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags));
+}
+
+static void xen_idle(void)
 {
 	local_irq_disable();
 
@@ -148,17 +164,22 @@ void cpu_idle(void)
 	/* endless idle loop with no priority at all */
 	while (1) {
 		while (!need_resched()) {
+			void (*idle)(void);
 
 			if (__get_cpu_var(cpu_idle_state))
 				__get_cpu_var(cpu_idle_state) = 0;
 
 			rmb();
+			idle = pm_idle;
+
+			if (!idle)
+				idle = xen_idle;
 
 			if (cpu_is_offline(cpu))
 				play_dead();
 
 			__get_cpu_var(irq_stat).idle_timestamp = jiffies;
-			xen_idle();
+			idle();
 		}
 		preempt_enable_no_resched();
 		schedule();
@@ -194,9 +215,22 @@ void cpu_idle_wait(void)
 }
 EXPORT_SYMBOL_GPL(cpu_idle_wait);
 
-/* XXX XEN doesn't use mwait_idle(), select_idle_routine(), idle_setup(). */
-/* Always use xen_idle() instead. */
-void __devinit select_idle_routine(const struct cpuinfo_x86 *c) {}
+void __devinit select_idle_routine(const struct cpuinfo_x86 *c)
+{
+}
+
+static int __init idle_setup (char *str)
+{
+	if (!strncmp(str, "poll", 4)) {
+		printk("using polling idle threads.\n");
+		pm_idle = poll_idle;
+	}
+
+	boot_option_idle_override = 1;
+	return 1;
+}
+
+__setup("idle=", idle_setup);
 
 void show_regs(struct pt_regs * regs)
 {
diff --git a/arch/x86_64/kernel/process-xen.c b/arch/x86_64/kernel/process-xen.c
index fc34b29..4d40a58 100644
--- a/arch/x86_64/kernel/process-xen.c
+++ b/arch/x86_64/kernel/process-xen.c
@@ -111,8 +111,26 @@ void exit_idle(void)
 	__exit_idle();
 }
 
-/* XXX XEN doesn't use default_idle(), poll_idle(). Use xen_idle() instead. */
-void xen_idle(void)
+/*
+ * On SMP it's slightly faster (but much more power-consuming!)
+ * to poll the ->need_resched flag instead of waiting for the
+ * cross-CPU IPI to arrive. Use this option with caution.
+ */
+static void poll_idle(void)
+{
+	local_irq_enable();
+
+	asm volatile(
+		"2:"
+		"testl %0,%1;"
+		"rep; nop;"
+		"je 2b;"
+		: :
+		"i" (_TIF_NEED_RESCHED),
+		"m" (current_thread_info()->flags));
+}
+
+static void xen_idle(void)
 {
 	local_irq_disable();
 
@@ -155,14 +173,18 @@ void cpu_idle (void)
 	/* endless idle loop with no priority at all */
 	while (1) {
 		while (!need_resched()) {
+			void (*idle)(void);
+
 			if (__get_cpu_var(cpu_idle_state))
 				__get_cpu_var(cpu_idle_state) = 0;
 			rmb();
-			
+			idle = pm_idle;
+			if (!idle)
+				idle = xen_idle;
 			if (cpu_is_offline(smp_processor_id()))
 				play_dead();
 			enter_idle();
-			xen_idle();
+			idle();
 			__exit_idle();
 		}
 
@@ -201,9 +223,22 @@ void cpu_idle_wait(void)
 }
 EXPORT_SYMBOL_GPL(cpu_idle_wait);
 
-/* XXX XEN doesn't use mwait_idle(), select_idle_routine(), idle_setup(). */
-/* Always use xen_idle() instead. */
-void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) {}
+void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) 
+{
+}
+
+static int __init idle_setup (char *str)
+{
+	if (!strncmp(str, "poll", 4)) {
+		printk("using polling idle threads.\n");
+		pm_idle = poll_idle;
+	}
+
+	boot_option_idle_override = 1;
+	return 1;
+}
+
+__setup("idle=", idle_setup);
 
 /* Prints also some state that isn't saved in the pt_regs */ 
 void __show_regs(struct pt_regs * regs)