2014-12-22 10 views
28

Ok, ho letto il seguente Qs da SO per quanto riguarda le recinzioni CPU x86 (LFENCE, SFENCE e MFENCE):Quando sono richieste le istruzioni x86 LFENCE, SFENCE e MFENCE?

e:

e devo essere onesto non sono ancora del tutto sicuro quando è richiesta una recinzione. Sto cercando di capire dal punto di vista della rimozione di blocchi completamente bloccati e cercando di utilizzare un blocco più granulare tramite le recinzioni, per ridurre al minimo i ritardi di latenza.

In primo luogo qui ci sono due domande specifiche che non capisco:

A volte quando si fa un negozio di una CPU scriverà al suo buffer negozio invece della cache L1. Non capisco comunque i termini su cui una CPU farà questo?

CPU2 potrebbe voler caricare un valore che è stato scritto nel buffer di memoria della CPU1. A quanto ho capito, il problema è che CPU2 non può vedere il nuovo valore nel buffer di memoria di CPU1. Perché il protocollo MESI non può includere solo i buffer del flushing store come parte del suo protocollo ??

Più in generale, qualcuno potrebbe tentare di descrivere lo scenario generale e aiutare a spiegare quando sono richieste le istruzioni LFENCE/MFENCE e SFENCE?

NB Uno dei problemi di lettura intorno a questo argomento è il numero di articoli scritti "generalmente" per architetture CPU multiple, quando sono interessato solo all'architettura Intel x86-64 in particolare.

+5

"* Perché non è possibile il protocollo MESI sufficiente includere scaricare i buffer di deposito come parte del suo pr otocol ?? * "Se i buffer del negozio dovevano avere un ordine rigoroso rispetto al flusso di istruzioni, non servirebbero a nulla. Senza un simile ordine, quando li svuoti? In sostanza, il tuo suggerimento è "perché non rallentiamo tutto fino alla velocità inter-core piuttosto che richiedere alle persone di identificare le cose specifiche che devono subire questa penalità?" –

+0

Su x86 è praticamente necessario utilizzare la scherma solo se si utilizza un tipo di memoria diverso dalla cache di write-back o se si utilizzano istruzioni non temporali.Vedi anche [questa risposta] (http://stackoverflow.com/a/8883426/547981), e la sezione manuale a cui si fa riferimento. – Jester

+1

Senza alcuna sincronizzazione esplicita, CPU2 potrebbe vedere il vecchio valore anche se il negozio è già stato memorizzato nel buffer del buffer di CPU1, non c'è niente di sbagliato in questo. Solo una volta che CPU1 rende visibile il negozio, CPU2 "deve" vederlo. – Leeor

risposta

29

La risposta più semplice: è necessario utilizzare uno dei 3 recinzioni (LFENCE, SFENCE, MFENCE) per fornire uno di coerenza dei dati 6:

  • Relaxed
  • Consumare
  • Acquisisci
  • uscita
  • Acquire-Release
  • Sequenziale

C++ 11:

Inizialmente, si dovrebbe prendere in considerazione questo problema dal punto di vista del grado di ordine di accesso alla memoria, che è ben documentato e standardizzato in C++ 11.Si consiglia di leggere prima: http://en.cppreference.com/w/cpp/atomic/memory_order

x86/x86_64:

1. Coerenza Acquire-uscita: Quindi, è importante capire che nel x86 per accedere alla RAM convenzionale (contrassegnato da predefinito come WB - Write Back, e lo stesso effetto con WT (Write Throught) o UC (Uncacheable)) usando asm MOV senza alcun comando aggiuntivo fornisce automaticamente l'ordine di memoria per la coerenza di acquisizione - std::memory_order_acq_rel. I.e. per questa memoria ha senso usare solo std::memory_order_seq_cst solo per fornire coerenza sequenziale. Vale a dire quando si utilizza: std::memory_order_relaxed o std::memory_order_acq_rel quindi il codice assembler compilato per std::atomic::store() (o std::atomic::load()) sarà lo stesso - solo MOV senza alcun L/S/MFENCE.

Nota: Ma devi sapere, che non solo CPU, ma e C++ - compilatore può riordinare le operazioni con la memoria, e tutti i 6 barriere di memoria influiscono sempre sul C++ - il compilatore a prescindere dalla architettura della CPU.

Quindi, è necessario sapere, come può essere compilato da C++ a ASM (codice macchina nativo) o come si può scrivere sull'assembler. Per fornire qualsiasi consistenza escludere sequenziale è possibile semplice scrittura MOV, ad esempio MOV reg, [addr] e MOV [addr], reg ecc

2. sequenziale Consistenza: Ma per fornire coerenza sequenziale è necessario utilizzare implicita (LOCK) o recinzioni espliciti (L/S/MFENCE) come descritto qui: Why GCC does not use LOAD(without fence) and STORE+SFENCE for Sequential Consistency?

  1. LOAD (senza recinto) e STORE + MFENCE
  2. LOAD (senza recinto) e LOCK XCHG
  3. MFENCE + LOAD e STORE (senza recinzione)
  4. LOCK XADD (0) e STORE (senza recinzione)

Ad esempio, GCC utilizzi 1, ma usa MSVC 2. (Ma dovete sapere, che MSVS2012 ha un bug: Does the semantics of `std::memory_order_acquire` requires processor instructions on x86/x86_64?)

Poi, si può leggere Herb Sutter, il tuo link: https://onedrive.live.com/view.aspx?resid=4E86B0CF20EF15AD!24884&app=WordPdf&authkey=!AMtj_EflYn2507c

eccezione alla regola:

Questa regola vale per l'accesso utilizzando MOV di RAM convenzionale segnata per impostazione predefinita come WB - Write Back. La memoria è contrassegnata nel Page Table, in ciascuna PTE (tabella pagina Enrty) per ogni pagina (memoria continua da 4 KB).

Ma ci sono alcune eccezioni:

  1. Se noi segni di memoria Page Table come Scrivi combinato (ioremap_wc() in POSIX), quindi automaticamente fornisce Acquisire solo coerenza, e dobbiamo agire come nel paragrafo successivo.

  2. See risposta alla mia domanda: https://stackoverflow.com/a/27302931/1558037

  • scrive di memoria non vengono riordinati con le altre scritture, con le seguenti eccezioni:
    • scrive eseguiti con l'CLFLUSH l'istruzione;
    • archivi di streaming (scritture) eseguiti con le istruzioni di spostamento non temporali (MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS e MOVNTPD); e
    • operazioni di stringa (vedere Sezione 8.2.4.1).

In entrambi i casi 1 & 2 è necessario utilizzare ulteriori SFENCE tra due operazioni di scrittura allo stesso indirizzo anche se si vuole acquisire-Release coerenza, perché qui automaticamente fornisce solo Acquisire Coerenza e si deve fare di uscita (SFENCE) da soli.

risposta alle vostre due domande:

A volte quando si fa un negozio di una CPU scriverà al suo buffer negozio invece della cache L1. Non capisco comunque i termini su che una CPU farà questo?

Dal punto di vista dell'utente, la cache L1 e il buffer di memorizzazione si comportano in modo diverso. L1 veloce, ma Store-Buffer più veloce.

  • Store-buffer - è un semplice coda dove i negozi scrive solo, e che non possono essere riordinate - è fatto per aumentare le prestazioni e nascondere latenza di accesso alla cache (L1 - 1 ns, L2 - 3ns, L3 - 10ns) (CPU-Core pensa che Write sia memorizzato nella cache ed esegua il comando successivo, ma allo stesso tempo le tue scritture vengono salvate solo nello Store-Buffer e saranno salvate nella cache L1/2/3 in seguito), cioè CPU-Core non ha bisogno di aspettare quando le scritture saranno state archiviate nella cache.

  • Cache L1/2/3 - assomigliano all'array associato trasparente (indirizzo - valore). È veloce ma non il più veloce, perché x86 fornisce automaticamente la coerenza di acquisizione utilizzando il protocollo cache coherentMESIF/MOESI. È fatto per una programmazione multithread più semplice, ma diminuisce le prestazioni. (Veramente, possiamo usare algoritmi e strutture dati di Content Contentions senza usare cache coerente, cioè senza MESIF/MOESI per esempio su PCI Express). Protocolli MESIF/MOESI funziona su QPI che collega Core in CPU e Core tra diverse CPU in sistemi multiprocessore (ccNUMA).

CPU2 potrebbe desiderare di caricare un valore che è stato scritto in al buffer negozio di CPU1. A quanto ho capito, il problema è che CPU2 non può vedere il nuovo valore nel buffer di memoria della CPU1.

Sì.

Perché il protocollo MESI solo include buffer di svuotamento come parte del protocollo ??

protocollo MESI non può semplicemente includere i buffer negozio vampate di calore come parte del suo protocollo, in quanto:

  • MESI/MOESI/protoclos MESIF non sono legati alla Store-buffer e non sanno su di esso .
  • Automatic flushing Store Buffer ad ogni Writes ridurrebbe le prestazioni e lo renderebbe inutile.
  • Flusso manuale Memorizza buffer su tutti i core della CPU remoti (non sappiamo su quale core store-buffer contenga la scrittura richiesta) utilizzando un comando - ridurrebbe le prestazioni (in 8 CPU x 15 core = 120 core allo stesso tempo di lavaggio Store-Buffer - questo è terribile)

Ma manualy Conservare Svuotamento buffer sulle attuali CPU-core - Sì, è possibile farlo eseguire SFENCE comando. È possibile utilizzare SFENCE in due casi:

  • Per garantire la coerenza sequenziale sulla RAM con Write Torna cacheable
  • Per garantire la coerenza Acquire-uscita sul eccezioni alla regola: RAM con Scrivere combinato memorizzabile nella cache, per le scritture eseguite con l'istruzione CLFLUSH e per i non-temporale SSE/AVX comandi

Nota:

Abbiamo bisogno di LFENCE in ogni caso su x86/x86_64? - la questione non è sempre chiaro: Does it make any sense instruction LFENCE in processors x86/x86_64?

altra piattaforma:

Poi, si può leggere come nella teoria (per un processore sferica sotto vuoto), con Store-Buffer e invalidare-coda, il tuo link: http://www.puppetmastertrading.com/images/hwViewForSwHackers.pdf

e come è possibile fornire la consistenza sequenziale su altre piattaforme, non solo con L/S/MFENCE e BLOCCO ma con LL/SC: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html

Problemi correlati