ChangeSet 1.1713.1.13, 2005/06/16 12:44:16+01:00, sos22@xxxxxxxxxxxxxxxxxxxx
Slightly disgusting hack to avoid using lots of lock instructions on a
uniprocessor
machine just because we happened to compile with CONFIG_SMP.
Essentially, we
make a big table of all of the instruction sequences which differ in
``easy''
ways between UP and SMP kernels, and then select which one to use at
run time.
Signed-off-by: Steven Smith <sos22@xxxxxxxxx>
linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig | 13
linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile | 1
linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c | 17
linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h | 57 ++
patches/linux-2.6.11/smp-alts.patch | 302 ++++++++++++++
5 files changed, 384 insertions(+), 6 deletions(-)
diff -Nru a/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig
b/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig
--- a/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig 2005-06-17 21:02:25
-04:00
+++ b/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig 2005-06-17 21:02:25
-04:00
@@ -372,6 +372,19 @@
If you don't know what to do here, say N.
+config SMP_ALTERNATIVES
+ bool "SMP alternatives support (EXPERIMENTAL)"
+ depends on SMP && EXPERIMENTAL
+ help
+ Try to reduce the overhead of running an SMP kernel on a uniprocessor
+ host slightly by replacing certain key instruction sequences
+ according to whether we currently have more than one CPU available.
+ This should provide a noticeable boost to performance when
+ running SMP kernels on UP machines, and have negligible impact
+ when running on an true SMP host.
+
+ If unsure, say N.
+
config NR_CPUS
int "Maximum number of CPUs (2-255)"
range 2 255
diff -Nru a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile
b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile
--- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile 2005-06-17
21:02:25 -04:00
+++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile 2005-06-17
21:02:25 -04:00
@@ -42,6 +42,7 @@
c-obj-$(CONFIG_HPET_TIMER) += time_hpet.o
c-obj-$(CONFIG_EFI) += efi.o efi_stub.o
c-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+c-obj-$(CONFIG_SMP_ALTERNATIVES)+= smpalts.o
EXTRA_AFLAGS := -traditional
diff -Nru a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c
b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c
--- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c 2005-06-17
21:02:25 -04:00
+++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c 2005-06-17
21:02:25 -04:00
@@ -54,6 +54,8 @@
#include <asm/desc.h>
#include <asm/arch_hooks.h>
+#include <asm/smp_alt.h>
+
#ifndef CONFIG_X86_IO_APIC
#define Dprintk(args...)
#endif
@@ -1186,6 +1188,10 @@
if (max_cpus <= cpucount+1)
continue;
+#ifdef CONFIG_SMP_ALTERNATIVES
+ if (kicked == 1)
+ prepare_for_smp();
+#endif
if (do_boot_cpu(cpu))
printk("CPU #%d not responding - cannot use it.\n",
cpu);
@@ -1301,6 +1307,11 @@
/* must be called with the cpucontrol mutex held */
static int __devinit cpu_enable(unsigned int cpu)
{
+#ifdef CONFIG_SMP_ALTERNATIVES
+ if (num_online_cpus() == 1)
+ prepare_for_smp();
+#endif
+
/* get the target out of its holding state */
per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
wmb();
@@ -1340,6 +1351,12 @@
fixup_irqs(map);
/* It's now safe to remove this processor from the online map */
cpu_clear(cpu, cpu_online_map);
+
+#ifdef CONFIG_SMP_ALTERNATIVES
+ if (num_online_cpus() == 1)
+ unprepare_for_smp();
+#endif
+
return 0;
}
diff -Nru a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h
b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h
--- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h 2005-06-17
21:02:25 -04:00
+++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h 2005-06-17
21:02:25 -04:00
@@ -8,6 +8,7 @@
#include <asm/segment.h>
#include <asm/cpufeature.h>
#include <asm-xen/hypervisor.h>
+#include <asm/smp_alt.h>
#ifdef __KERNEL__
@@ -251,19 +252,19 @@
unsigned long prev;
switch (size) {
case 1:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
+ __asm__ __volatile__(LOCK "cmpxchgb %b1,%2"
: "=a"(prev)
: "q"(new), "m"(*__xg(ptr)), "0"(old)
: "memory");
return prev;
case 2:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
+ __asm__ __volatile__(LOCK "cmpxchgw %w1,%2"
: "=a"(prev)
: "q"(new), "m"(*__xg(ptr)), "0"(old)
: "memory");
return prev;
case 4:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
+ __asm__ __volatile__(LOCK "cmpxchgl %1,%2"
: "=a"(prev)
: "q"(new), "m"(*__xg(ptr)), "0"(old)
: "memory");
@@ -427,11 +428,55 @@
#endif
#ifdef CONFIG_SMP
-#define smp_mb() mb()
-#define smp_rmb() rmb()
#define smp_wmb() wmb()
-#define smp_read_barrier_depends() read_barrier_depends()
+#if defined(CONFIG_SMP_ALTERNATIVES) && !defined(MODULE)
+#define smp_alt_mb(instr) \
+__asm__ __volatile__("6667:\nnop\nnop\nnop\nnop\nnop\nnop\n6668:\n" \
+ ".section __smp_alternatives,\"a\"\n" \
+ ".long 6667b\n" \
+ ".long 6673f\n" \
+ ".previous\n" \
+ ".section __smp_replacements,\"a\"\n" \
+ "6673:.byte 6668b-6667b\n" \
+ ".byte 6670f-6669f\n" \
+ ".byte 6671f-6670f\n" \
+ ".byte 0\n" \
+ ".byte %c0\n" \
+ "6669:lock;addl $0,0(%%esp)\n" \
+ "6670:" instr "\n" \
+ "6671:\n" \
+ ".previous\n" \
+ : \
+ : "i" (X86_FEATURE_XMM2) \
+ : "memory")
+#define smp_rmb() smp_alt_mb("lfence")
+#define smp_mb() smp_alt_mb("mfence")
+#define set_mb(var, value) do { \
+unsigned long __set_mb_temp; \
+__asm__ __volatile__("6667:movl %1, %0\n6668:\n" \
+ ".section __smp_alternatives,\"a\"\n" \
+ ".long 6667b\n" \
+ ".long 6673f\n" \
+ ".previous\n" \
+ ".section __smp_replacements,\"a\"\n" \
+ "6673: .byte 6668b-6667b\n" \
+ ".byte 6670f-6669f\n" \
+ ".byte 0\n" \
+ ".byte 6671f-6670f\n" \
+ ".byte -1\n" \
+ "6669: xchg %1, %0\n" \
+ "6670:movl %1, %0\n" \
+ "6671:\n" \
+ ".previous\n" \
+ : "=m" (var), "=r" (__set_mb_temp) \
+ : "1" (value) \
+ : "memory"); } while (0)
+#else
+#define smp_rmb() rmb()
+#define smp_mb() mb()
#define set_mb(var, value) do { xchg(&var, value); } while (0)
+#endif
+#define smp_read_barrier_depends() read_barrier_depends()
#else
#define smp_mb() barrier()
#define smp_rmb() barrier()
diff -Nru a/patches/linux-2.6.11/smp-alts.patch
b/patches/linux-2.6.11/smp-alts.patch
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/patches/linux-2.6.11/smp-alts.patch 2005-06-17 21:02:25 -04:00
@@ -0,0 +1,554 @@
+diff -Naur linux-2.6.11/arch/i386/Kconfig linux-2.6.11.post/arch/i386/Kconfig
+--- linux-2.6.11/arch/i386/Kconfig 2005-03-02 07:37:49.000000000 +0000
++++ linux-2.6.11.post/arch/i386/Kconfig 2005-06-10 13:42:35.000000000
+0100
+@@ -481,6 +481,19 @@
+
+ If you don't know what to do here, say N.
+
++config SMP_ALTERNATIVES
++ bool "SMP alternatives support (EXPERIMENTAL)"
++ depends on SMP && EXPERIMENTAL
++ help
++ Try to reduce the overhead of running an SMP kernel on a uniprocessor
++ host slightly by replacing certain key instruction sequences
++ according to whether we currently have more than one CPU available.
++ This should provide a noticeable boost to performance when
++ running SMP kernels on UP machines, and have negligible impact
++ when running on an true SMP host.
++
++ If unsure, say N.
++
+ config NR_CPUS
+ int "Maximum number of CPUs (2-255)"
+ range 2 255
+diff -Naur linux-2.6.11/arch/i386/kernel/Makefile
linux-2.6.11.post/arch/i386/kernel/Makefile
+--- linux-2.6.11/arch/i386/kernel/Makefile 2005-03-02 07:37:49.000000000
+0000
++++ linux-2.6.11.post/arch/i386/kernel/Makefile 2005-06-16
11:16:18.555332435 +0100
+@@ -32,6 +32,7 @@
+ obj-$(CONFIG_HPET_TIMER) += time_hpet.o
+ obj-$(CONFIG_EFI) += efi.o efi_stub.o
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
++obj-$(CONFIG_SMP_ALTERNATIVES) += smpalts.o
+
+ EXTRA_AFLAGS := -traditional
+
+diff -Naur linux-2.6.11/arch/i386/kernel/smpalts.c
linux-2.6.11.post/arch/i386/kernel/smpalts.c
+--- linux-2.6.11/arch/i386/kernel/smpalts.c 1970-01-01 01:00:00.000000000
+0100
++++ linux-2.6.11.post/arch/i386/kernel/smpalts.c 2005-06-16
11:23:39.300902424 +0100
+@@ -0,0 +1,76 @@
++#include <linux/kernel.h>
++#include <asm/system.h>
++#include <asm/smp_alt.h>
++#include <asm/processor.h>
++#include <asm/string.h>
++
++struct smp_replacement_record {
++ unsigned char targ_size;
++ unsigned char smp1_size;
++ unsigned char smp2_size;
++ unsigned char up_size;
++ unsigned char feature;
++ unsigned char data[0];
++};
++
++struct smp_alternative_record {
++ void *targ_start;
++ struct smp_replacement_record *repl;
++};
++
++extern struct smp_alternative_record __start_smp_alternatives_table,
++ __stop_smp_alternatives_table;
++
++void prepare_for_smp(void)
++{
++ struct smp_alternative_record *r;
++ printk(KERN_INFO "Enabling SMP...\n");
++ for (r = &__start_smp_alternatives_table;
++ r != &__stop_smp_alternatives_table;
++ r++) {
++ BUG_ON(r->repl->targ_size < r->repl->smp1_size);
++ BUG_ON(r->repl->targ_size < r->repl->smp2_size);
++ BUG_ON(r->repl->targ_size < r->repl->up_size);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|