X86 Linux/SMP自旋锁是否太慢了?
通过阅读X86 Linux/SMP自旋锁是否太慢了?,x86,linux-kernel,spinlock,X86,Linux Kernel,Spinlock,通过阅读了解Linux内核(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 这会简单得多。但是,我明白他们为什么这样做了,因为锁会影响其他CPU,b
了解Linux内核(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
这会简单得多。但是,我明白他们为什么这样做了,因为锁
会影响其他CPU,btsl
的计时比简单的testb
的计时要大
有一件事我还没有弄清楚,那就是随后的自旋锁的释放。该书指出,其结果如下:
lock:
btrl $0, slp
我的问题是为什么?在我看来,lock/mov immediate
组合更快
您不需要将旧状态设置为carry标志,因为按照内核没有bug的规则(假设在内核中的许多其他地方),旧状态将为1(如果您还没有获得它,您就不会尝试释放它)
而且mov
比btrl
快得多,至少在386上是这样
那么我错过了什么
在以后的芯片上,这些指令的计时是否改变了
自从这本书出版以来,内核已经更新了吗
这本书是不是完全错了(或者显示了简化的说明)
我是否错过了其他一些涉及CPU之间同步的方面,而这些方面是更快的指令无法满足的?好吧,
理解Linux内核已经很老了。自编写以来,Linux内核被更新为使用所谓的票据自旋锁。锁基本上是一个16位的数量,分为两个字节:让我们调用一个Next
(就像自动售票机中的下一张票)和另一个Owner
(就像柜台上的“正在服务”号码)。自旋锁在两个部分都设置为零的情况下初始化。锁定记录spinlock的值,然后按原子顺序递增。如果递增前的Next值等于Owner,则已获得锁。否则,它会旋转,直到所有者增加到正确的值,依此类推
相关代码位于中(对于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倍
希望这有帮助;如果没有,我很乐意深入挖掘