【ARMv8/v9 异常模型入门及渐进 10 -- WFI 与 WFE 使用详细介绍 1】

请阅读【ARMv8/v9 ARM64 System Exception】


文章目录

WFI 与 WFE

ARMv8架构提供了几个与事件相关的指令,包括等待事件(WFE)、发送事件(SEV)和本地发送事件(SEVL),这些指令有助于减少因处理器元素(PE,Processor Element)反复尝试获取自旋锁(spin-lock)而导致的功耗和总线竞争。这些指令在应用层面上是可用的,但要完全理解它们的行为,需要系统级别的异常处理知识。下面详细介绍这三个指令的功能及其对系统性能优化的影响。

等待事件(WFE)

WFE指令使得一个处理器元素可以进入低功耗状态,直到发生以下情况之一:

  • 发生了一个异常。
  • 接收到一个事件信号。
  • 如果存在外部中断,处理器也可能被唤醒,即使这个中断最终被处理器的状态所屏蔽。

WFE指令通常用于自旋锁等待循环中,允许处理器在等待锁释放的时候降低功耗。

发送事件(SEV)

SEV指令用于在同一系统中的一个或多个处理器元素之间发送事件信号。当一个处理器执行SEV指令时,它将触发系统中所有正在执行WFE指令等待事件的处理器元素退出等待状态。 在自旋锁释放后使用SEV指令可以唤醒等待该锁的其他处理器元素,这有助于减少等待时间和功耗。

关于spin_lock与独占访问的关系推荐阅读
【ARM AMBA AXI 入门 7 - AXI 协议中的独占访问 使用背景介绍】
【ARM AMBA AXI 入门 6 - AXI3 协议中的锁定访问之AxLOCK信号】

本地发送事件(SEVL)

SEVL指令与SEV类似,但它只确保发出事件信号的处理器元素本身在下一次执行WFE指令时立即返回,而不进入等待状态。这有助于优化特定的同步模式,其中处理器元素可能需要在检查某个条件后立即继续执行,而不是等待。

WFE 唤醒事件

WFE(Wait For Event)指令让处理器进入等待状态,直到发生特定的唤醒事件(Wake-up Events)。这些事件可以来自多种不同的源,以下介绍了在AArch64状态下可以触发WFE指令唤醒处理器的事件:

  1. 执行SEV指令 :在多处理器系统中,任何处理器元素(PE)执行SEV(Send Event)指令都可以作为一个唤醒事件。SEV指令用于在PE之间发送全局事件信号。
  2. 物理SError中断、IRQ中断或FIQ中断:如果PE收到物理SError中断、IRQ(Interrupt Request)中断或FIQ(Fast Interrupt Request)中断,并且该中断没有被EDSCR.INTDIS(一个调试寄存器的一部分,用于禁用中断)禁用,那么这个中断会作为一个唤醒事件。
  3. 异步外部调试请求:如果允许暂停执行(Halting),那么一个异步外部调试请求也可以作为一个唤醒事件。这种情况通常与调试过程有关。
  4. 由处理器元素的定时器事件流发送的事件:处理器元素的定时器可以配置为在特定时间点发送事件,这些事件也能唤醒处于WFE等待状态的PE。
  5. 全局监视器清除造成的事件:当PE的全局监视器从独占访问状态变为开放访问状态时,会生成一个事件,这也可以唤醒等待的PE。
  6. 由某些实现定义机制发送的事件:特定的硬件实现可能提供了其他机制来生成唤醒事件,这些机制依赖于具体的硬件设计和配置。
  7. 实现FEAT_WFXT特性时的本地超时事件 :当实现了FEAT_WFXT特性,并且使用WFET指令时,如果虚拟计数器阈值(在CNTVCT_EL0寄存器中表示)被等于或超过,就会产生本地超时事件作为唤醒事件。

WFE 使用场景举例与代码实现

这里以 多核系统中主核 core0 启动后去唤醒处于睡眠状态的从核 core1 为例 并测试。

首先使用汇编代码实现 sevwfe 的调用函数:

wfe睡眠函数

c 复制代码
func enter_wfe
    wfe
    ret
endfunc enter_wfe

sev 事件唤醒函数

c 复制代码
func arm_sev
    sev
    ret
endfunc arm_sev

从核启动函数(截取部分)

c 复制代码
    ...
    log_debug("\rcore%d run wfe then goto sleep\n", coreid_get());
    enter_wfe ();
    log_debug("\rcore%d wakeup from wfe\n", coreid_get());
    enter_wfe ();
  • 场景是主核core0先启动,然后使用命令手动去启动从核core1, core1 启动后后面执行到 enter_wfe 之后就会睡眠,
  • 然后主核执行 sev 指令来唤醒从核,然后从核醒后执行一句打印,然后再去执行 enter_wfe 继续睡眠。

全局监视器和自旋锁

ARMv8架构中引入了全局监视器的概念,当处理器元素(PE)的全局监视器从独占访问状态变为开放访问状态时,会自动生成一个事件。这相当于在PE上执行了SEVL指令。因此,当一个PE释放自旋锁时,不再需要在代码中显式包含SEV指令来唤醒等待锁的其他PE,系统会自动生成相应的事件,

这简化了编程模型并有助于提高效率。 这种机制特别适用于多核处理器环境中的同步问题,可以减少因PE反复尝试获取自旋锁而导致的功耗和总线竞争,进而提升系统性能和能效。