Skip to content

Commit 2ed53c0

Browse files
Lan TianyuIngo Molnar
authored andcommitted
x86/smpboot: Speed up suspend/resume by avoiding 100ms sleep for CPU offline during S3
With certain kernel configurations, CPU offline consumes more than 100ms during S3. It's a timing related issue: native_cpu_die() would occasionally fall into a 100ms sleep when the CPU idle loop thread marked the CPU state to DEAD too slowly. What native_cpu_die() does is that it polls the CPU state and waits for 100ms if CPU state hasn't been marked to DEAD. The 100ms sleep doesn't make sense and is purely historic. To avoid such long sleeping, this patch adds a 'struct completion' to each CPU, waits for the completion in native_cpu_die() and wakes up the completion when the CPU state is marked to DEAD. Tested on an Intel Xeon server with 48 cores, Ivybridge and on Haswell laptops. The CPU offlining cost on these machines is reduced from more than 100ms to less than 5ms. The system suspend time is reduced by 2.3s on the servers. Borislav and Prarit also helped to test the patch on an AMD machine and a few systems of various sizes and configurations (multi-socket, single-socket, no hyper threading, etc.). No issues were seen. Tested-by: Prarit Bhargava <[email protected]> Signed-off-by: Lan Tianyu <[email protected]> Acked-by: Borislav Petkov <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: Linus Torvalds <[email protected]> Link: http://lkml.kernel.org/r/[email protected] [ Improved a few minor details in the code, cleaned up the changelog. ] Signed-off-by: Ingo Molnar <[email protected]>
1 parent f367039 commit 2ed53c0

File tree

1 file changed

+12
-11
lines changed

1 file changed

+12
-11
lines changed

arch/x86/kernel/smpboot.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map);
102102
DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);
103103
EXPORT_PER_CPU_SYMBOL(cpu_info);
104104

105+
static DEFINE_PER_CPU(struct completion, die_complete);
106+
105107
atomic_t init_deasserted;
106108

107109
/*
@@ -1323,26 +1325,24 @@ int native_cpu_disable(void)
13231325
return ret;
13241326

13251327
clear_local_APIC();
1326-
1328+
init_completion(&per_cpu(die_complete, smp_processor_id()));
13271329
cpu_disable_common();
1330+
13281331
return 0;
13291332
}
13301333

13311334
void native_cpu_die(unsigned int cpu)
13321335
{
13331336
/* We don't do anything here: idle task is faking death itself. */
1334-
unsigned int i;
1337+
wait_for_completion_timeout(&per_cpu(die_complete, cpu), HZ);
13351338

1336-
for (i = 0; i < 10; i++) {
1337-
/* They ack this in play_dead by setting CPU_DEAD */
1338-
if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
1339-
if (system_state == SYSTEM_RUNNING)
1340-
pr_info("CPU %u is now offline\n", cpu);
1341-
return;
1342-
}
1343-
msleep(100);
1339+
/* They ack this in play_dead() by setting CPU_DEAD */
1340+
if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
1341+
if (system_state == SYSTEM_RUNNING)
1342+
pr_info("CPU %u is now offline\n", cpu);
1343+
} else {
1344+
pr_err("CPU %u didn't die...\n", cpu);
13441345
}
1345-
pr_err("CPU %u didn't die...\n", cpu);
13461346
}
13471347

13481348
void play_dead_common(void)
@@ -1354,6 +1354,7 @@ void play_dead_common(void)
13541354
mb();
13551355
/* Ack it */
13561356
__this_cpu_write(cpu_state, CPU_DEAD);
1357+
complete(&per_cpu(die_complete, smp_processor_id()));
13571358

13581359
/*
13591360
* With physical CPU hotplug, we should halt the cpu

0 commit comments

Comments
 (0)