基于 UMONITOR/UMWAIT 的汇编 (asm) 自旋等待循环的工作示例,作为基于 PAUSE 的测试测试和设置循环的替代品

问题描述 投票:0回答:1

Intel 64 和 IA-32 架构优化参考手册中,Intel 给出了基于 PAUSE 的自旋等待循环的示例(“示例 11-4. 自旋等待循环和 PAUSE 指令”)。

但是,对于 UMONITOR/UMWAIT 指令,仅提及而没有任何示例(“支持用户级低功耗和低延迟自旋循环指令 UMWAIT/UMONITOR 和 TPAUSE”和“UMWAIT/UMONITOR/TPAUSE 指令”)在用户级旋转循环中实现节能”)。这些新指令随英特尔于 2020 年 9 月在 Elkhart Lake 平台中发布的 Tremont 微架构一起推出。

您能否给出一个关于汇编语言的SpinWaitAndAquireLockReleaseLock函数的工作示例,它们使用字节值作为同步变量(在64位或32位寻址模式下),以便该字节只能处于两种状态之一,即仅包含两个值:

cLockByteLocked
(例如,
0FFh
)和
cLockByteAvailable
(例如,
0
)!?我可以使用 PAUSE 指令作为参考示例来给出这样的函数,可以通过
nasm -f win64
:

进行编译
section .text

; This code exposes two global functions: (1) SpinWaitAndAquireLock; (2) ReleaseLock.


cLockByteLocked     equ 0FFh
cLockByteAvailable  equ 0

; wait for the byte to not be locked and lock it
global SpinWaitAndAquireLock

; release lock obtained previously by SpinWaitAndAquireLock
global ReleaseLock

SpinWaitAndAquireLock:
; input: rcx - address of the synchronization variable lock byte
   mov  eax, cLockByteLocked ; load the value that denotes "locked" into al; use eax to clear remaining bits to avoid false dependency on existing eax value, bits 32-63 of rax are also cleared
   jmp  @FirstCompare
@NormalLoadLoop:
   pause  
@FirstCompare:
; use the "test, test-and-set" technique
   cmp  [rcx], al   ; try normal load first instead of the locked load - "test" is a first part of "test, test-and-set"
   je   @NormalLoadLoop ; for static branch prediction, jump backward means "likely"
   lock xchg [rcx], al  ; since normal load shows the synchronization variable is available, try locked load and store ("test-and-set")
   cmp  al, cLockByteLocked
   je   @NormalLoadLoop
   ret

ReleaseLock:
; input: rcx - address of the synchronization variable lock byte
   mov   byte [rcx], cLockByteAvailable ; just use normal store
   ret 
assembly x86 intel thread-synchronization spinlock
1个回答
0
投票

这是一个关于汇编语言的 SpinWaitAndAquireLock 和 ReleaseLock 函数的工作示例,它们在 64 位模式下使用字节值作为同步变量。此示例可以由

nasm
使用
-f win64
参数进行编译。它改编自https://github.com/maximmasiutin/FastMM4-AVX/blob/master/FastMM4.pas

本示例中的函数使用 Microsoft 的 Win64“x64 ABI”调用约定,即该示例无需修改即可在 Windows 下运行。在此调用约定中,第一个参数在

rcx
寄存器中传递。如果您希望在 Linux 下使用此示例,其中使用“System V AMD64 ABI”调用约定,并且第一个参数在
rdi
寄存器中传递,请将 `rcx' 替换为 'rdi'。

当程序使用的虚拟线程数量超过CPU提供的物理线程数量时,本例中的umonitor/umwait会带来显着的好处;否则没有任何好处。在 FastMM4-AVX 中,对于具有 64 个逻辑线程的 12 线程 CPU 上的 Linux,使用 umonitor/umwait 实现的程序比“暂停”之一快 6(!) 倍,基准代码位于 Tests/Benchmarks/Realloc FastMM 存储库中的 .dpr。

; wait for the byte to not be locked and lock it
global SpinWaitAndAquireLock

; release lock obtained previously by SpinWaitAndAquireLock
global ReleaseLock


cLockByteLocked     equ 109
cLockByteAvailable  equ 0
cUMWaitTime     equ 7000000

; input: rcx - address of the synchronization variable lock byte

   jmp  @FirstLockMonitor

@DidntLockUmonitor:
   mov  eax, cLockByteLocked
   cmp  [rcx], al
   jne  @TryXchgAfterUmonitor

@FirstLockMonitor:
   umonitor rcx
   cmp  [rcx], al
   jne  @TryXchgAfterUmonitor

   mov  eax, cUMWaitTime
   xor  rdx, rdx

;       bit[0] = 0  C0.2    Slower  Larger  Improves performance of the other SMT thread(s) on the same core.
;       bit[0] = 1  C0.1    Faster  Smaller NA
   xor  r9, r9

   umwait r9d

@TryXchgAfterUmonitor:
   mov  eax, cLockByteLocked
   lock xchg [rcx], al
   cmp  al, cLockByteLocked
   je   @DidntLockUmonitor

; Locked after umonitor
   ret


ReleaseLock:
; input: rcx - address of the synchronization variable lock byte
   mov   byte [rcx], cLockByteAvailable ; just use normal store
   ret 
© www.soinside.com 2019 - 2024. All rights reserved.