了解 ARM 事务内存扩展

squ*_*rem 5 arm transactional-memory memory-model arm64 intel-tsx

ARM 事务内存扩展对如何使用它们有相当简单的描述:

sem_post:
    TSTART X0         // Start of outer transaction
    CBNZ   test_fail  // No reason for this routine to cancel or fail
    LDR    X1, [X2]   // X2 points to semaphore
    ADD    X1, X1, #1 // Increment semaphore value
    STR    X1, [X2].  // Store incremented value
    TCOMMIT           // Commit transaction and exit
Run Code Online (Sandbox Code Playgroud)

我想要弄清楚的是,这些事务是否基于与代码其他部分中的事务的冲突而重放,以及它们是否基于与任何类型的访问的冲突而重放。为了详细说明,假设我们有这个例程:

sem_wait:
    TSTART X0          // Start of outer transaction
    CBNZ   retry_check // This routine checks for retry (RTRY) and restarts transaction
    LDR    X1, [X2]   // X2 points to semaphore
    CMP    X1, #0     // Check if semaphore is already used
    CBNZ   decrement  // If it's non-zero, we can decrement the semaphore
    TCANCEL #0xFF     // If it's zero, we gotta retry
decrement:
    SUB    X1, X1, #1 // Decrement semaphore value
    STR    X1, [X2].  // Store decremented value
    TCOMMIT           // Commit transaction and exit
Run Code Online (Sandbox Code Playgroud)

因此,该事务将位于代码的另一部分,但将作为 sem_post 事务访问内存中的位置。

我的第一个问题:执行事务的线程sem_post可能会重播并发执行sem_wait事务的线程吗?

对于我的问题的第二部分,假设我们有一个像这样的简单例程:

break_semaphore:
    MOV X0, #0xFF
    STR X0, [X1]  // X1 points to semaphore
Run Code Online (Sandbox Code Playgroud)

上面的例程根本不是事务,它只是搞乱了信号量。

我的第二个问题:执行sem_post事务的线程是否可能由于对事务中要更新和提交的位置的任何并发访问sem_post而重放?

为了清楚起见,我完全理解这并不是 TME 指令真正应该使用的方式,并且锁的实现方式更像是这样的:https ://www.gem5.org/project/2020/10/27/ tme.html

我更想知道事务实际上线性化的是什么:具有公共代码区域的两个事务、所有彼此之间的事务,或者相对于所有其他内存访问的事务?

小智 2

TME 确实线性化了对共享内存区域的访问。在您的示例中,这些事务中止的原因不是因为它们正在执行相同的代码,而是因为共享内存地址。

根据ARM TME 文档,内存地址的任何冲突状态都会导致 TSTART 失败并设置 MEM 位。在信号量示例的上下文中,由于没有用于调用的回退代码sem_post,事务将取消程序执行状态将恢复到非事务状态。

出于类似的原因,事务不一定通过执行相同的代码来线性化,因为它们可能引用不同的内存区域(即具有不同指针的多个信号量),这是完全合法的。

事务之间是否线性化更难回答,因为它通常依赖于硬件。例如,两个事务可以在具有不同内存对象的不同核心上合法执行,但如果两个事务尝试在同一核心和寄存器上执行(即,使用超线程),则这种行为将更难以定义。