2011-01-19 15 views
6

Essendo stato la lettura attraverso Understanding the Linux kernel (Bovet & Cesati), il capitolo sul kernel di sincronizzazione afferma che il codice di acquisizione spin lock si riduce a:Gli spinlock di Linux/SMP sono inutilmente lenti?

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

Ora ho inizialmente pensato che sembrava uno spreco avere cicli annidati e si potrebbe implementare qualcosa di simile :

1: lock: 
    btsl $0, slp 
    jc  1 

che sarebbe molto più semplice. Tuttavia, vedo perché lo hanno fatto poiché lo lock ha effetto sulle altre CPU e le tempificazioni per lo btsl sono maggiori di quelle per un semplice testb.

L'unica cosa che io non ho stato in grado di capirmi è la successiva versione dello spin lock. Il libro afferma che ottengono i seguenti:

lock: 
    btrl $0, slp 

La mia domanda è fondamentalmente perché? Mi sembra che una combo lock/mov-immediate sia più veloce.

Non è necessario riportare il vecchio stato al flag di trasporto poiché, seguendo la regola che il kernel è privo di errori (assunto in molti altri punti all'interno di detto kernel), il vecchio stato sarà 1 (tu non proverei a rilasciarlo se non lo avessi già acquisito).

E un mov è molto più veloce di un btrl, almeno sulla 386.

Allora, cosa mi manca?

I tempi sono cambiati per quelle istruzioni sui chip successivi?

Il kernel è stato aggiornato da quando è stato stampato il libro?

Il libro è semplicemente errato (o mostra istruzioni semplificate)?

Ho perso qualche altro aspetto che coinvolge la sincronizzazione tra le CPU che l'istruzione più veloce non soddisfa?

risposta

10

Beh, Understanding the Linux Kernel è vecchio. Da quando è stato scritto, il kernel di Linux è stato aggiornato per utilizzare i cosiddetti spinlock dei ticket. Il blocco è fondamentalmente una quantità di 16 bit divisa in due byte: chiamiamo uno Next (come il prossimo ticket in un distributore) e l'altro Owner (come il numero "Ora in servizio" su un contatore). Uno spinlock viene inizializzato con entrambe le parti impostate su zero. Il blocco indica il valore dello spinlock e l'incremento successivo, atomicamente. Se il valore di Avanti prima dell'incremento è uguale a Proprietario, il blocco è stato ottenuto. Altrimenti, ruota finché il proprietario non viene incrementato al valore corretto e così via.

Il codice pertinente è asm/spinlock.h (per x86). L'operazione di sblocco è infatti molto più veloce e più semplice del libro dice:

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

dal inc è di circa 8 o 9 volte più veloce di btr.

Spero che questo aiuti; se no, sarei felice di scavare più a fondo.

Problemi correlati