本文将介绍hltpausemonitormwait 这四个指令的相关知识点。

hlt

X86架构中,hlt指令使CPU进入HALT状态,在Linux的进程调度模块中,当某CPU处于idle状态时,可能会执行hlt命令使其进入HALT状态,目的显而易见,是为了节能。

那CPU进入HALT状态后,如何Resume呢?谁来将其唤醒?
答案是:中断(包括NMI和SMI),debug exception,BINIT# signal,INIT# signal,或者RESET# signal。

pause

先阅读What is the purpose of the “PAUSE” instruction in x86?

Improves the performance of spin-wait loops. When executing a “spin-wait loop,” processors will suffer a severe performance penalty when exiting the loop because it detects a possible memory order violation. The PAUSE instruction provides a hint to the processor that the code sequence is a spin-wait loop. The processor uses this hint to avoid the memory order violation in most situations, which greatly improves processor performance. For this reason, it is recommended that a PAUSE instruction be placed in all spin-wait loops.
An additional function of the PAUSE instruction is to reduce the power consumed by a processor while executing a spin loop. A processor can execute a spin-wait loop extremely quickly, causing the processor to consume a lot of power while it waits for the resource it is spinning on to become available. Inserting a pause instruction in a spinwait loop greatly reduces the processor’s power consumption.

monitor and mwait

Executing the HLT instruction on a idle logical processor puts the targeted processor in a non-execution state. This requires another processor (when posting work for the halted logical processor) to wake up the halted processor using an inter-processor interrupt. The posting and servicing of such an interrupt introduces a delay in the servicing of new work requests.

MONITOR sets up an effective address range that is monitored for write-to-memory activities; MWAIT places the processor in an optimized state (this may vary between different implementations) until a write to the monitored address range occurs.

引入了monitormwait指令后,避免了hlt导致的the posting and servicing of such an interrupt introduces a delay in the servicing of new work requests.

acrn-hypervisor中的用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* wait until *sync == wake_sync */
void wait_sync_change(volatile const uint64_t *sync, uint64_t wake_sync)
{
if (has_monitor_cap()) {
/* Wait for the event to be set using monitor/mwait */
while ((*sync) != wake_sync) {
asm_monitor(sync, 0UL, 0UL);
if ((*sync) != wake_sync) {
asm_mwait(0UL, 0UL);
}
}
} else {
...
}
}

static
inline void asm_monitor(volatile const uint64_t *addr, uint64_t ecx, uint64_t edx)
{
asm volatile("monitor\n" : : "a" (addr), "c" (ecx), "d" (edx));
}

static
inline void asm_mwait(uint64_t eax, uint64_t ecx)
{
asm volatile("mwait\n" : : "a" (eax), "c" (ecx));
}

Uses of monitor/mwait in the Linux kernel请参考Uses of the monitor/mwait instructions


参考资料:

  1. Intel SDM
  2. X86 HLT指令相关