Domanda

usi Linux Kernel lock; addl $0,0(%%esp) come barriera di scrittura, mentre gli utilizzi di libreria RE2 xchgl (%0),%0 come barriera di scrittura. Qual è la differenza e che è meglio?

non x86 richiedono anche istruzioni barriera di lettura? RE2 definisce la sua funzione di barriera di lettura come non presente in 86 mentre Linux definisce come sia lfence o no-op seconda che SSE2 è disponibile. Quando è necessario lfence?

È stato utile?

Soluzione

Il " serratura; addl $ 0,0 (%% esp) " è più veloce nel caso in cui abbiamo testare il 0 stato di variabili di blocco a (esp %%) indirizzo. Poiché aggiungiamo 0 al valore variabile serratura e il flag di zero è impostato a 1 se il valore della variabile di blocco all'indirizzo (%% esp) è 0.


lfence di Intel foglio di dati:

  

Esegue un'operazione serializzazione su   tutte le istruzioni del carico di memoria che   sono stati rilasciati prima della LFENCE   istruzioni. Questo serializzazione   garantisce un funzionamento che ogni carico   istruzione che precede in programma   ordinare l'istruzione è LFENCE   visibili globalmente prima di qualsiasi carico   istruzione che segue il LFENCE   istruzione è globalmente visibile.

( Nota del redattore: mfence o un'operazione locked è il recinto solo utile (dopo un negozio) per sequenziale coerenza . lfence non blocco StoreLoad riordino dal buffer negozio.)


Per esempio: istruzione di scrittura memoria come 'mov' sono atomiche (che non hanno bisogno del prefisso lock) se ci siano correttamente allineati. Ma questa operazione viene normalmente eseguita nella cache CPU e non saranno visibili globalmente in questo momento per tutti gli altri thread, perché la memoria recinzione deve essere eseguita prima di fare questa discussione attendere esercizi precedenti sono visibili ad altri thread.


Quindi, la differenza principale tra queste due istruzioni è che xchgl istruzione non avrà alcun effetto sulle bandiere condizionali. Certamente possiamo testare la variabile di stato serratura con Blocco cmpxchg di istruzioni ma questo è ancora più complesso di quello di Blocco aggiungere $ 0 di istruzioni.

Altri suggerimenti

Citando le IA32 manuali (Vol 3A, capitolo 8.2: Memoria di ordinazione):

  

In un sistema a singolo processore per regioni di memoria definita come cacheable write-back, il modello di memoria di ordinamento rispetta i seguenti principi [..]

     
      
  • Letture non vengono riordinati con altri legge
  •   
  • scritture non sono riordinati con anziani legge
  •   
  • scrive di memoria non vengono riordinati con le altre scritture, con l'eccezione di   
        
    • scrive eseguito con l'istruzione CLFLUSH
    •   
    • streaming di negozi (scrive) eseguito con le istruzioni di movimento non-temporali ([elenco di istruzioni qui])
    •   
    • operazioni sulle stringhe (vedi paragrafo 8.2.4.1)
    •   
  •   
  • Letture può essere riordinata con scritture più anziani in luoghi diversi, ma non con le scritture più anziani nella stessa posizione.
  •   
  • legge o scrive non può essere riordinata con le istruzioni di I / O, istruzioni bloccate, o istruzioni serializzazione
  •   
  • Legge non può passare istruzioni LFENCE e MFENCE
  •   
  • Scrive non può passare istruzioni SFENCE e MFENCE
  •   

Nota: L ' "In un sistema a singolo processore" sopra è leggermente fuorviante. Le stesse regole valgono per ogni (logico) processore individualmente; il manuale passa poi a descrivere le regole di ordinamento addizionali tra più processori. L'unica parte su di esso di pertinenza la questione è che

  
      
  • istruzioni Locked hanno un ordine totale.
  •   

In breve, fino a quando si sta scrivendo nella memoria write-back (che è tutta la memoria potrai mai vedere finché non sei un programmatore di driver o grafica), la maggior parte delle istruzioni x86 sono quasi in sequenza coerente - l'unico riordino una CPU x86 in grado di eseguire è di riordino in seguito (indipendente) legge da eseguire prima di operazioni di scrittura. La cosa principale di barriere scrittura è che hanno un prefisso lock (implicita o esplicita), che vieta qualsiasi riordino e assicura che le operazioni è visto nello stesso ordine da tutti i processori in un sistema multi-processore.

Inoltre, nella memoria write-back, legge non sono mai riordinate, quindi non c'è bisogno di barriere leggere. processori x86 recenti hanno un modello di coerenza di memoria più debole per lo streaming di negozi e la memoria write-combinata (comunemente usato per la memoria grafica mappato). Ecco dove le varie istruzioni fence entrano in gioco; non sono necessari per qualsiasi altro tipo di memoria, ma alcuni driver del kernel di Linux fanno patto con la memoria write-combinata in modo che appena definiti la loro lettura barriera che modo. L'elenco dei modelli ordinazione per ogni tipo di memoria è nella Sezione 11.3.1 nel Vol. 3A del IA-32 manuali. Versione corta: write-through, write-back e Write-Protected consentire speculativa legge (seguendo le regole come sopra), la memoria Uncacheable uncachable e Strong ha forti garanzie di ordinazione (nessun riordino processore, letture / scritture vengono immediatamente eseguite, utilizzati per MMIO ) e scrittura della memoria combinato ha ordinamento debole (per esempio le regole di ordinamento rilassato che le recinzioni bisogno).

lock addl $0, (%esp) è un sostituto per mfence, non lfence.

L'uso a caso è quando avete bisogno di bloccare StoreLoad riordino (l'unica che forte modello di memoria di 86 permette), ma non è necessario un intervento RMW atomica su una variabile condivisa. https://preshing.com/20120515/memory-reordering-caught- in-the-act /

es. supponendo std::atomic<int> a,b allineato:

movl   $1, a             a = 1;    Atomic for aligned a
# barrier needed here
movl   b, %eax           tmp = b;  Atomic for aligned b

Le opzioni disponibili sono:

  • Fare un negozio sequenziale-coerenza con xchg , per esempio mov $1, %eax / xchg %eax, a in modo da non avete bisogno di una barriera separata; è parte del negozio. Penso che questa sia l'opzione più efficiente sulla maggior parte dell'hardware moderno; C ++ 11 compilatori diversi dall'uso gcc xchg per i negozi seq_cst.
  • Usa mfence come una barriera. (Usi gcc mov + mfence per i negozi seq_cst).
  • Usa lock addl $0, (%esp) come una barriera. Qualsiasi istruzione locked è una barriera piena. Blocco fa xchg hanno lo stesso comportamento come mfence?

    (o ad un altro luogo, ma la pila è quasi sempre privata e caldo in L1d, quindi è un po 'buon candidato. Tuttavia, ciò può creare una catena di dipendenza di qualcosa che usando i dati in fondo alla pila.)

Si può utilizzare solo xchg come una barriera piegandolo in un negozio perché scrive incondizionatamente la posizione di memoria con un valore che non dipende il vecchio valore.

Quando è possibile, utilizzando xchg per un negozio seq-CST è probabilmente la cosa migliore, anche se si legge anche dalla posizione condivisa. mfence è più lento del previsto sulla recente CPU Intel ( sono un sacco e memorizza le uniche istruzioni che viene riordinati? ), anche il blocco out-of-ordine di esecuzione delle istruzioni non di memoria indipendenti allo stesso modo lfence fa.

Potrebbe anche essere la pena utilizzare lock addl $0, (%esp)/(%rsp) invece di mfence anche quando mfence è disponibile, ma non ho sperimentato con i lati negativi. Utilizzando -64(%rsp) o qualcosa potrebbe rendere meno probabilità di allungare una dipendenza di dati su qualcosa di caldo (un locale o un indirizzo di ritorno), ma che può rendere strumenti come valgrind infelice.


lfence non è mai utile per l'ordinazione di memoria a meno che non si sta leggendo da RAM video (o qualche altro WC debolmente ordinato regione) con carichi MOVNTDQA.

serializzazione esecuzione fuori ordine (ma non il buffer negozio) non è utile per fermare StoreLoad riordino (l'unica che forte modello di memoria di 86 permette il normale WB (write-back) regioni di memoria).

I casi d'uso reali per lfence sono per bloccare esecuzione fuori ordine di rdtsc per tempi molto brevi blocchi di codice, o per la mitigazione Spettro bloccando speculazione attraverso un salto condizionato o indiretta.

Quando devo utilizzare _mm_sfence _mm_lfence e _mm_mfence (la mia risposta e @ risposta di BeeOnRope) per di più sul perché lfence non è utile, e quando utilizzare ciascuna delle istruzioni barriera. (O in miniera, le intrinseche C ++ durante la programmazione in C ++, invece di asm).

Per inciso alle altre risposte, gli sviluppatori HotSpot trovarono che lock; addl $0,0(%%esp) con uno spostamento potrebbe non essere ottimale, su alcuni processori esso può introdurre falsi dipendenze dei dati ; relativi JDK bug .

Toccando una posizione stack con un offset in grado di migliorare le prestazioni in alcune circostanze diverse.

La parte importante di lock; addl e xchgl è il prefisso lock. E 'implicito per xchgl. Non c'è davvero nessuna differenza tra i due. Mi piacerebbe guardare a come assemblare e scegliere quello che è più breve (in byte) dal momento che di solito è più veloce per le operazioni equivalenti a 86 (da qui trucchi come xorl eax,eax)

La presenza di SSE2 è probabilmente solo un proxy per la condizione reale che è in ultima analisi, una funzione di cpuid. Probabilmente scopre che SSE2 implica l'esistenza di lfence e la disponibilità di SSE2 è stata controllata / cache in fase di boot. lfence è richiesto quando è disponibile.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top