Являются ли спин-блокировки Linux/SMP излишне медленными?

Прочитав 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 влияет на другие процессоры и время для btsl больше, чем для простого testb,

Единственное, что я не смог обдумать, - это последующее освобождение спин-блокировки. Книга утверждает, что она дает следующее:

   lock:
   btrl    $0, slp

Мой вопрос в основном почему? Мне кажется, что lock/mov-immediate комбо быстрее.

Вам не нужно возвращать старое состояние к флагу переноса, поскольку, следуя правилу, согласно которому ядро ​​не содержит ошибок (предполагается, что во многих других местах внутри этого ядра) старое состояние будет равно 1 (вы не будете пытаясь выпустить его, если вы его еще не приобрели).

И mov гораздо быстрее, чем btrl по крайней мере на 386.

Так чего мне не хватает?

Изменились ли сроки для этих инструкций на более поздних чипах?

Было ли ядро ​​обновлено с тех пор, как книга была напечатана?

Книга просто неверна (или показывает упрощенные инструкции)?

Я пропустил какой-то другой аспект, связанный с синхронизацией между процессорами, который не удовлетворяет более быстрая инструкция?

1 ответ

Решение

Что ж, Understanding the Linux Kernel Старый. С тех пор как было написано, ядро ​​Linux было обновлено для использования так называемых спин-блокировок билетов. Блокировка - это 16-битная величина, разделенная на два байта: Next (как следующий билет в раздаточном устройстве) и другие Owner (например, номер "Сейчас на службе" за прилавком). Спин-блокировка инициализируется с обеими частями, установленными на ноль. Locking отмечает значение спин-блокировки и увеличивает 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 примерно в 8 или 9 раз быстрее, чем btr,

Надеюсь это поможет; если нет, я был бы счастлив копать глубже.

Другие вопросы по тегам