2016-05-26 15 views
5

Sto cercando di capire il modo corretto di utilizzare le recinzioni quando si misura il tempo con RDTSC/RDTSCP. Diverse domande su SO relative a questo hanno già avuto una risposta elaborata. Ne ho esaminati alcuni. Ho anche letto questo articolo molto utile sullo stesso argomento: http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdfx86-64 utilizzo di LFENCE

Tuttavia, in un altro blog online, c'è un esempio di utilizzo di LFENCE anziché CPUID su x86. Mi stavo chiedendo come LFENCE impedisce ai negozi precedenti di contaminare le misurazioni RDTSC. E.g.

<Instr A> 
LFENCE/CPUID 
RDTSC 
<Code to be benchmarked> 
LFENCE/CPUID 
RDTSC 

Nel caso di cui sopra, LFENCE assicura tutti i carichi precedenti si completa prima di esso (Dal SDM dice:. Istruzioni LFENCE non può passare in precedenza si legge). Ma che dire dei negozi precedenti (ad esempio, Instr A era un negozio)? Capisco perché CPUID funziona perché è un'istruzione di serializzazione, ma LFENCE non lo è.

Una spiegazione che ho trovato era in Intel SDM VOL 3A Sezione 8.3, la seguente nota:

LFENCE non fornisce alcune garanzie su istruzione ordinazione. Non viene eseguito fino a quando tutte le istruzioni precedenti non sono state completate localmente e nessuna istruzione successiva inizia l'esecuzione fino al completamento di LFENCE.

Quindi essenzialmente LFENCE si comporta come un MFENCE. In tal caso, perché abbiamo bisogno di due istruzioni separate LFENCE e MFENCE?

Probabilmente mi manca qualcosa.

Grazie in anticipo.

risposta

5

Il punto chiave è l'avverbio localmente nella frase citata "Esso non viene eseguito fino a quando tutte le istruzioni precedenti hanno completato localmente".

Non sono riuscito a trovare una definizione chiara di "completare localmente" l'intero set di manuale Intel, la mia speculazione è illustrata di seguito.


Per essere completato localmente un'istruzione deve avere uscita calcolato e disposizione delle altre istruzioni più in basso nella sua catena di dipendenza. Inoltre qualsiasi effetto collaterale di tale istruzione deve essere visibile all'interno del nucleo.

Per essere completato a livello mondiale un'istruzione deve avere i suoi effetti collaterali visibili ad altri componenti di sistema (come altre CPU).

Se non si qualifica il tipo di "completezza" di cui stiamo parlando generalmente significa che non interessa o che è implicito nel contesto.


Per un sacco di istruzioni da completare a livello locale e globale, è lo stesso.
Per un caricare ad esempio, per poter essere completato localmente, alcuni dati devono essere recuperati dalla memoria o dalle cache. Questo è come essere completato globalmente, poiché non possiamo contrassegnare il carico completo se non si legge prima dalla gerarchia della memoria.

Per un negozio tuttavia la situazione è diversa.

processori

Intel hanno un Conservare Buffer gestire scritture nella memoria, dal capitolo 11.10 del manuale 3:

Intel 64 e IA-32 processori memorizzare temporaneamente ogni processo di scrittura (negozio) per la memoria in un memorizzare il buffer. Il buffer del negozio migliora le prestazioni del processore consentendo al processore di continuare a eseguire le istruzioni senza dover attendere finché non viene completata la scrittura in memoria e/o in una cache. Consente inoltre di ritardare le scritture per un utilizzo più efficiente dello dei cicli del bus di accesso alla memoria.

Così un negozio può essere completato localmente inserendolo nel buffer del negozio, dal punto di vista del nucleo la scrittura è come se fosse andata fino in fondo alla memoria.
Un carico proveniente dallo stesso core del negozio, in determinate circostanze, può persino leggere il valore (questo è chiamato Inoltro archivio).

Per essere completato a livello globale, tuttavia, un negozio deve essere esaurito dal buffer di archiviazione.

Infine è obbligatorio aggiungere che il buffer negozio è drenato da istruzioni Serializzazione:

Il contenuto del buffer di deposito sono sempre drenato alla memoria nelle seguenti situazioni:
• (P6 e processore più recente solo famiglie) Quando viene eseguita un'istruzione di serializzazione.
• (solo per famiglie di processori Pentium III e più recenti) Quando si utilizza un'istruzione SFENCE per ordinare i negozi.
• (solo per famiglie di processori Pentium 4 e più recenti) Quando si utilizza un'istruzione MFENCE per ordinare i negozi.


stato fatto con l'introduzione, vediamo cosa lfence, mfence e sfence fare:

LFENCE non viene eseguito fino a quando tutte le istruzioni precedenti hanno completato a livello locale, e nessuna istruzione in seguito inizia l'esecuzione fino a quando LFENCE completa.

MFENCE esegue un'operazione di serializzazione su tutte le istruzioni di caricamento da memoria e di memoria in memoria emesse prima dell'istruzione MFENCE. MFENCE non serializza il flusso di istruzioni.

SFENCE esegue un'operazione di serializzazione su tutte le istruzioni store-to-memory che sono state emesse prima dell'istruzione SFENCE.

Così lfence è forma più debole di serializzazione che non scarica Store Buffer, dal momento che serializzare in modo efficace le istruzioni a livello locale, tutti i carichi prima di esso devono essere completati prima del completamento.

sfence serializza solo i negozi, in pratica non consente al processo di eseguire altri negozi finché sfence non è in uso. Drena anche il buffer dello Store.

mfence è non una semplice combinazione dei due perché non è serializzazione in senso classico, è un sfence che impediscono anche carichi futuri da eseguire.


Può valere la pena nulla che è stato introdotto sfence primo e gli altri due a due è venuto in seguito per ottenere un controllo più granulare su l'ordinamento della memoria.

Infine, sono stato utilizzato per chiudere un'istruzione rdtsc tra due istruzioni lfence, per garantire che non fosse possibile riordinare "indietro" e "avanti".
Tuttavia sono sicuro di questa tecnica.

+0

Grazie per l'elaborata risposta. Quindi, se ho capito bene, LFENCE non scarica il buffer del negozio, ma fa in modo che la CPU attenda fino a quando tutte le istruzioni precedenti sul carico e sul negozio non siano state completate localmente. In tal caso, non possiamo fare affidamento su di esso per la misurazione del tempo (RDTSC) alla fine del nostro codice benchmark giusto? Perché, vuoi assicurarti che le scritture siano state fatte globali (scaricate in memoria) prima di misurare il tempo. Grazie. –

+0

'lfence' può essere usato per la misurazione * se non si desidera attendere * affinché i negozi diventino globalmente visibili. Scrivere in memoria richiede molti cicli e se non si tiene conto della memorizzazione nella cache con attenzione, si ottengono risultati incoerenti. Di solito un permesso scrive a memoria il benchmark, a meno che non si voglia testarlo esplicitamente. In questo caso usa 'lfence' con' sfence' o un'istruzione serializzante che non sovrascrive i registri necessari. –

+0

Ha senso. Grazie mille. –

1

Come giustamente osservato, è una questione di serializzazione . Per quanto riguarda la tua domanda

perché abbiamo bisogno di due istruzioni separate LFENCE e MFENCE?

venga risolta Intel SDM nella sezione "5.6.4 - SSE2 Cache di controllo e l'ordinazione Istruzioni":

LFENCE Serializza le operazioni di carico
MFENCE serializza le operazioni di carico e memorizzare

Pertanto, LFENCE è probabilmente utilizzato perché MFENCE non è necessario per RDTSC.