x86 - Linux/SMP 自旋锁不必要地慢吗?

标签 x86 linux-kernel spinlock

已通读 Understanding the Linux kernel (Bovet & Cesati),内核同步一章指出自旋锁获取代码归结为:

1: lock:
   btsl    $0, slp
   jnc     3
2: testb   $1, slp
   jne     2
   jmp     1
3: 

现在我最初认为嵌套循环似乎很浪费,您可以实现以下内容:
1: lock:
   btsl    $0, slp
   jc      1

这会简单得多。然而,我明白他们为什么这样做了,因为 lock影响其他 CPU 和 btsl 的计时比简单 testb 的大.

我一直无法理解的一件事是随后释放自旋锁。该书指出,它产生以下结果:
   lock:
   btrl    $0, slp

我的问题基本上是为什么?在我看来,lock/mov-immediate组合更快。

您不需要将旧状态设置为进位标志,因为遵循内核无错误的规则(假设在所述内核中的许多其他地方),旧状态将为 1(您不会如果您还没有获得它,请尝试释放它)。

还有一个 movbtrl 快得多,至少在 386 上。

那么我错过了什么?

以后芯片上的这些指令的时间是否改变了?

书出版后内核有没有更新?

这本书是完全错误的(或显示了简化的说明)吗?

我是否错过了涉及更快指令不满足的 CPU 之间同步的其他方面?

最佳答案

那么,Understanding the Linux Kernel老了。自编写以来,Linux 内核已更新为使用所谓的票证自旋锁。锁基本上是一个分成两个字节的 16 位数量:我们称之为 Next (就像取款机中的下一张票)和另一个 Owner (例如柜台上的“现在服务”号码)。自旋锁初始化时两个部分都设置为零。锁定记录自旋锁的值,并以原子方式递增 Next。如果递增前Next的值等于Owner,则表示已经获得锁。否则,它会一直旋转,直到 Owner 增加到正确的值,依此类推。

相关代码在asm/spinlock.h (对于 x86)。解锁操作确实比书上说的要快得多,也简单得多:

static __always_inline void __ticket_spin_unlock(arch_spinlock_t *lock)
{
    asm volatile(UNLOCK_LOCK_PREFIX "incb %0"
         : "+m" (lock->slock)
         :
         : "memory", "cc");
}

inc大约比 btr 快 8 或 9 倍.

希望这可以帮助;如果没有,我很乐意深入挖掘。

关于x86 - Linux/SMP 自旋锁不必要地慢吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4733246/

相关文章:

linux-kernel - linux内核如何实现2个进程之间的共享内存

linux - 如何使用 DKMS 构 build 备树覆盖?

c# - 为什么每个人都说 SpinLock 更快?

c++ - 在 C++ openmp 中使用自旋锁

assembly - MESI 协议(protocol)是否足够,还是仍然需要内存屏障? (英特尔 CPU)

encoding - 如何在汇编器中实现相对 JMP (x86)?

linux - 为 x86 Linux 桌面构建 yocto

c - 这些时钟之间有什么区别, `real-time clock` ,`wall clock` ,`system clock` ?

c - 如果需要调用copy_to_user,如何使用自旋锁?

c++ - CMAKE - 调试/交叉构建?