如何监控linux自旋锁等待时间?

我在linux内核中读取了spinlock函数代码。 有两个与自旋锁相关的function。 请参阅下面的代码:

static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock) { short inc = 0x0100; asm volatile ( LOCK_PREFIX "xaddw %w0, %1\n" "1:\t" "cmpb %h0, %b0\n\t" "je 2f\n\t" "rep ; nop\n\t" "movb %1, %b0\n\t" /* don't need lfence here, because loads are in-order */ "jmp 1b\n" "2:" : "+Q" (inc), "+m" (lock->slock) : : "memory", "cc"); } static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock) { int inc = 0x00010000; int tmp; asm volatile(LOCK_PREFIX "xaddl %0, %1\n" "movzwl %w0, %2\n\t" "shrl $16, %0\n\t" "1:\t" "cmpl %0, %2\n\t" "je 2f\n\t" "rep ; nop\n\t" "movzwl %1, %2\n\t" /* don't need lfence here, because loads are in-order */ "jmp 1b\n" "2:" : "+r" (inc), "+m" (lock->slock), "=&r" (tmp) : : "memory", "cc"); } 

我有两个问题:

1.上面两个函数有什么区别?

2.我能做些什么来监控自旋锁的等待时间(第一次尝试锁的时间并最终获得锁)?variablesinc是指自旋锁的等待时间吗?

让我先解释一下spinlock代码是如何工作的。 我们有变数

 uint16_t inc = 0x0100, lock->slock; // I'll just call this "slock" 

在汇编程序代码中, inc被称为%0slock称为%1 。 而且, %b0表示低8位,即inc % 0x100%h0inc / 0x100

现在:

 lock xaddw %w0, %1 ;; "inc := slock" and "slock := inc + slock" ;; simultaneously (atomic exchange and increment) 1: cmpb %h0, %b0 ;; "if (inc / 256 == inc % 256)" je 2f ;; " goto 2;" rep ; nop ;; "yield();" movb %1, %b0 ;; "inc = slock;" jmp 1b ;; "goto 1;" 2: 

如果inc为零,则比较inc的高位字节和低位字节。 由于inc具有原始锁的值,所以如果锁被解锁,则会发生这种情况。 在这种情况下,锁已经被原子交换和增量增加到非零,所以现在它被锁定了。

否则,即,如果锁已经被锁定,我们暂停一下,然后更新inc到当前的锁的值,然后再试一次。

(我相信实际上有一个溢出的可能性,如果2 8个线程同时试图获得自旋锁,在这种情况下, slock更新为0x0100,0x0200,… 0xFF00,0x0000,然后似乎是解锁。这就是为什么代码的第二个版本使用一个16位宽的计数器,这将需要2 16个同时尝试。)

现在让我们插入一个计数器:

 uint32_t spincounter = 0; asm volatile( /* code below */ : "+Q" (inc), "+m" (lock->slock) : "=r" (spincounter) : "memory", "cc"); 

现在spincounter可能被称为%2 。 我们只需要每次递增计数器:

 1: inc %2 cmpb %h0, %b0 ;; etc etc 

我没有测试过这个,但是这是一般的想法。