aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2008-01-30 07:33:17 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:33:17 -0500
commitca74a6f84e68b44867022f4a4f3ec17c087c864e (patch)
treea5e84b251b1574b09288fb2636b4e4ea088ae70e
parent751752789162fde69474edfa15935d0a77c0bc17 (diff)
x86: optimize lock prefix switching to run less frequently
On VMs implemented using JITs that cache translated code changing the lock prefixes is a quite costly operation that forces the JIT to throw away and retranslate a lot of code. Previously a SMP kernel would rewrite the locks once for each CPU which is quite unnecessary. This patch changes the code to never switch at boot in the normal case (SMP kernel booting with >1 CPU) or only once for SMP kernel on UP. This makes a significant difference in boot up performance on AMD SimNow! Also I expect it to be a little faster on native systems too because a smp switch does a lot of text_poke()s which each synchronize the pipeline. v1->v2: Rename max_cpus v1->v2: Fix off by one in UP check (Thomas Gleixner) Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/kernel/alternative.c16
-rw-r--r--include/linux/smp.h2
-rw-r--r--init/main.c16
3 files changed, 24 insertions, 10 deletions
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index cdc43242da92..318a4f9b7ece 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -273,6 +273,7 @@ struct smp_alt_module {
273}; 273};
274static LIST_HEAD(smp_alt_modules); 274static LIST_HEAD(smp_alt_modules);
275static DEFINE_SPINLOCK(smp_alt); 275static DEFINE_SPINLOCK(smp_alt);
276static int smp_mode = 1; /* protected by smp_alt */
276 277
277void alternatives_smp_module_add(struct module *mod, char *name, 278void alternatives_smp_module_add(struct module *mod, char *name,
278 void *locks, void *locks_end, 279 void *locks, void *locks_end,
@@ -354,7 +355,14 @@ void alternatives_smp_switch(int smp)
354 BUG_ON(!smp && (num_online_cpus() > 1)); 355 BUG_ON(!smp && (num_online_cpus() > 1));
355 356
356 spin_lock_irqsave(&smp_alt, flags); 357 spin_lock_irqsave(&smp_alt, flags);
357 if (smp) { 358
359 /*
360 * Avoid unnecessary switches because it forces JIT based VMs to
361 * throw away all cached translations, which can be quite costly.
362 */
363 if (smp == smp_mode) {
364 /* nothing */
365 } else if (smp) {
358 printk(KERN_INFO "SMP alternatives: switching to SMP code\n"); 366 printk(KERN_INFO "SMP alternatives: switching to SMP code\n");
359 clear_cpu_cap(&boot_cpu_data, X86_FEATURE_UP); 367 clear_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
360 clear_cpu_cap(&cpu_data(0), X86_FEATURE_UP); 368 clear_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
@@ -369,6 +377,7 @@ void alternatives_smp_switch(int smp)
369 alternatives_smp_unlock(mod->locks, mod->locks_end, 377 alternatives_smp_unlock(mod->locks, mod->locks_end,
370 mod->text, mod->text_end); 378 mod->text, mod->text_end);
371 } 379 }
380 smp_mode = smp;
372 spin_unlock_irqrestore(&smp_alt, flags); 381 spin_unlock_irqrestore(&smp_alt, flags);
373} 382}
374 383
@@ -441,7 +450,10 @@ void __init alternative_instructions(void)
441 alternatives_smp_module_add(NULL, "core kernel", 450 alternatives_smp_module_add(NULL, "core kernel",
442 __smp_locks, __smp_locks_end, 451 __smp_locks, __smp_locks_end,
443 _text, _etext); 452 _text, _etext);
444 alternatives_smp_switch(0); 453
454 /* Only switch to UP mode if we don't immediately boot others */
455 if (num_possible_cpus() == 1 || setup_max_cpus <= 1)
456 alternatives_smp_switch(0);
445 } 457 }
446#endif 458#endif
447 apply_paravirt(__parainstructions, __parainstructions_end); 459 apply_paravirt(__parainstructions, __parainstructions_end);
diff --git a/include/linux/smp.h b/include/linux/smp.h
index c25e66bcecf3..55232ccf9cfd 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -78,6 +78,8 @@ int on_each_cpu(void (*func) (void *info), void *info, int retry, int wait);
78 */ 78 */
79void smp_prepare_boot_cpu(void); 79void smp_prepare_boot_cpu(void);
80 80
81extern unsigned int setup_max_cpus;
82
81#else /* !SMP */ 83#else /* !SMP */
82 84
83/* 85/*
diff --git a/init/main.c b/init/main.c
index 3f8aba291ed3..5843fe996703 100644
--- a/init/main.c
+++ b/init/main.c
@@ -128,7 +128,7 @@ static char *ramdisk_execute_command;
128 128
129#ifdef CONFIG_SMP 129#ifdef CONFIG_SMP
130/* Setup configured maximum number of CPUs to activate */ 130/* Setup configured maximum number of CPUs to activate */
131static unsigned int __initdata max_cpus = NR_CPUS; 131unsigned int __initdata setup_max_cpus = NR_CPUS;
132 132
133/* 133/*
134 * Setup routine for controlling SMP activation 134 * Setup routine for controlling SMP activation
@@ -146,7 +146,7 @@ static inline void disable_ioapic_setup(void) {};
146 146
147static int __init nosmp(char *str) 147static int __init nosmp(char *str)
148{ 148{
149 max_cpus = 0; 149 setup_max_cpus = 0;
150 disable_ioapic_setup(); 150 disable_ioapic_setup();
151 return 0; 151 return 0;
152} 152}
@@ -155,8 +155,8 @@ early_param("nosmp", nosmp);
155 155
156static int __init maxcpus(char *str) 156static int __init maxcpus(char *str)
157{ 157{
158 get_option(&str, &max_cpus); 158 get_option(&str, &setup_max_cpus);
159 if (max_cpus == 0) 159 if (setup_max_cpus == 0)
160 disable_ioapic_setup(); 160 disable_ioapic_setup();
161 161
162 return 0; 162 return 0;
@@ -164,7 +164,7 @@ static int __init maxcpus(char *str)
164 164
165early_param("maxcpus", maxcpus); 165early_param("maxcpus", maxcpus);
166#else 166#else
167#define max_cpus NR_CPUS 167#define setup_max_cpus NR_CPUS
168#endif 168#endif
169 169
170/* 170/*
@@ -393,7 +393,7 @@ static void __init smp_init(void)
393 393
394 /* FIXME: This should be done in userspace --RR */ 394 /* FIXME: This should be done in userspace --RR */
395 for_each_present_cpu(cpu) { 395 for_each_present_cpu(cpu) {
396 if (num_online_cpus() >= max_cpus) 396 if (num_online_cpus() >= setup_max_cpus)
397 break; 397 break;
398 if (!cpu_online(cpu)) 398 if (!cpu_online(cpu))
399 cpu_up(cpu); 399 cpu_up(cpu);
@@ -401,7 +401,7 @@ static void __init smp_init(void)
401 401
402 /* Any cleanup work */ 402 /* Any cleanup work */
403 printk(KERN_INFO "Brought up %ld CPUs\n", (long)num_online_cpus()); 403 printk(KERN_INFO "Brought up %ld CPUs\n", (long)num_online_cpus());
404 smp_cpus_done(max_cpus); 404 smp_cpus_done(setup_max_cpus);
405} 405}
406 406
407#endif 407#endif
@@ -824,7 +824,7 @@ static int __init kernel_init(void * unused)
824 __set_special_pids(1, 1); 824 __set_special_pids(1, 1);
825 cad_pid = task_pid(current); 825 cad_pid = task_pid(current);
826 826
827 smp_prepare_cpus(max_cpus); 827 smp_prepare_cpus(setup_max_cpus);
828 828
829 do_pre_smp_initcalls(); 829 do_pre_smp_initcalls();
830 830