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

标签 c linux assembly linux-kernel spinlock

我看了linux内核中的自旋锁函数代码。与自旋锁相关的函数有两个。请看下面的代码:

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.如何监控自旋锁等待时间(从第一次尝试锁到最后拿到锁的时间)?变量inc是指自旋锁等待时间吗?

最佳答案

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

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 更新为锁的当前值,然后重试。

(我相信实际上有可能发生溢出,如果 28 个线程同时尝试获取自旋锁。在这种情况下,slock 将更新为 0x0100、0x0200 , ... 0xFF00, 0x0000, 然后似乎被解锁了。也许这就是代码的第二个版本使用 16 位宽计数器的原因,这将需要 216 同时尝试。)

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

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

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

关于c - 如何监控linux自旋锁等待时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17400261/

相关文章:

c - 有没有办法将 stderr 重定向到在 bash、csh 和 dash 中工作的文件?

c - C语言更新表格格式

c - 在创建 RAW_SOCKET 错误时,如不允许操作

linux - shell 中的 for 循环

c - 用于图像处理的非常快的 memcpy?

java - 从 C 文件中提取 int 数组

linux - 在 Linux 中使用 WebSphere MQ 的默认 CCSID 连接到 Windows 中的客户端应用程序

linux - 在 Linux mint 17 上编译 Linux 内核时出错

assembly - MIPS 程序集中的语法错误

class - 从 x86-64 可执行文件中查找类和函数名称