2011-01-19 17 views
6

Będąc czytania Understanding the Linux kernel (Bovet & Cesati), rozdział na Kernel synchronizacji wskazuje, że spin lock code nabycie sprowadza się do:Czy blokady systemu Linux/SMP niepotrzebnie spowalniają?

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

Teraz początkowo sądzono, że wydawało marnotrawstwem mieć zagnieżdżone pętle i można zaimplementować coś podobnego :

1: lock: 
    btsl $0, slp 
    jc  1 

co byłoby o wiele prostsze. Jednak widzę, dlaczego to zrobili, ponieważ lock wpływa na inne procesory i czasy dla btsl są większe niż te dla prostego testb.

Jedną rzeczą, którą nie miałem udało mi się zdobyć głowę jest kolejne wydanie blokady spin. Książka wyjaśnia, że ​​daje następujące:

lock: 
    btrl $0, slp 

Moje pytanie jest w zasadzie dlaczego? Wydaje mi się, że kombinacja lock/mov-immediate jest szybsza.

Nie trzeba przenosić starego stanu do flagi carry, ponieważ zgodnie z zasadą, że jądro nie zawiera błędów (jest ono zakładane w wielu innych miejscach wewnątrz wspomnianego jądra), stary stan będzie wynosił 1 (ty nie próbowałby go uwolnić, gdybyś go jeszcze nie nabył).

I mov jest znacznie szybsze niż btrl, przynajmniej na 386.

więc co mi brakuje?

Czy zmieniono czasy na instrukcje dotyczące późniejszych układów?

Czy jądro zostało zaktualizowane od czasu wydrukowania książki?

Czy książka jest po prostu błędna (lub pokazuje uproszczone instrukcje)?

Czy brakowało mi jakiegoś innego aspektu synchronizacji pomiędzy procesorami, którego szybsze instrukcje nie spełniają?

Odpowiedz

10

Cóż, Understanding the Linux Kernel jest stary. Od kiedy zostało napisane, jądro Linuksa zostało zaktualizowane, aby używać tak zwanych spinlocków biletów. Blokada to w zasadzie 16-bitowa ilość podzielona na dwa bajty: nazwijmy jeden Next (jak następny bilet w dozowniku) i drugi Owner (jak numer "Teraz serwujemy" nad kontuarem). Blokada jest inicjalizowana, gdy obie części są ustawione na zero. Blokowanie zwraca wartość spinlock i inkrementuje Next, atomically. Jeśli wartość Next przed inkrementacją jest równa Owner, zamek został uzyskany. W przeciwnym razie obraca się, aż właściciel zostanie zwiększony do odpowiedniej wartości i tak dalej.

Właściwy kod znajduje się w asm/spinlock.h (dla x86). Operacja odblokowania jest rzeczywiście znacznie szybsze i prostsze niż książka mówi:

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

od inc wynosi około 8 lub 9 razy szybciej niż btr.

Mam nadzieję, że to pomaga; jeśli nie, chętnie kopnę głębiej.

Powiązane problemy