Chandler Carruth ha introdotto due funzioni nel suo CppCon2015 talk che possono essere utilizzate per eseguire un'inibizione a grana fine dell'ottimizzatore. Sono utili per scrivere dei micro-benchmark che l'ottimizzatore non metterà semplicemente a bada in assenza di significato.Barriera di ottimizzazione per i microbenchmarks in MSVC: indicare all'ottimizzatore che memoria del clobber?
void clobber() {
asm volatile("" : : : "memory");
}
void escape(void* p) {
asm volatile("" : : "g"(p) : "memory");
}
Queste istruzioni di assembly in linea consentono di modificare le ipotesi dell'ottimizzatore.
La dichiarazione di assemblaggio in clobber
indica che il codice assembly in esso può leggere e scrivere in qualsiasi punto della memoria. Il codice assembly effettivo è vuoto, ma l'ottimizzatore non lo esaminerà perché è asm volatile
. Ci crede quando diciamo che il codice potrebbe leggere e scrivere ovunque nella memoria. Ciò impedisce efficacemente all'ottimizzatore di riordinare o eliminare le scritture di memoria prima della chiamata a clobber
e impone la lettura della memoria dopo la chiamata a clobber
& dagger ;.
Quello in escape
rende inoltre visibile il puntatore p
al blocco di assiemi. Anche in questo caso, poiché l'ottimizzatore non esaminerà il codice di assembly inline effettivo, il codice può essere vuoto e l'ottimizzatore continuerà a ritenere che il blocco utilizzi l'indirizzo puntato dal puntatore p
. Ciò forza efficacemente qualsiasi punto p
in memoria e non in un registro, poiché il blocco di assiemi potrebbe eseguire una lettura da tale indirizzo.
(Questo è importante perché la funzione clobber
non imporrà le letture né le scritture per qualsiasi cosa che i compilatori decidano di inserire in un registro, poiché l'istruzione di assemblaggio in clobber
non specifica che qualcosa in particolare deve essere visibile al assemblaggio.)
Tutto questo accade senza alcun codice aggiuntivo generato direttamente da queste "barriere". Sono artefatti puramente in fase di compilazione.
Queste estensioni di linguaggio di utilizzo supportate in GCC e in Clang, però. C'è un modo per avere un comportamento simile quando si usa MSVC?
e pugnale; Per capire perché l'ottimizzatore deve pensare in questo modo, immagina se il blocco di assiemi fosse un ciclo che aggiunge 1 a ogni byte in memoria.
Sembra [come] (http://stackoverflow.com/ a/8845503/786653) '_ReadWriteBarrier' potrebbe essere la risposta per' clobber'. Però non so di "fuga". Forse '_ReadWriteBarrier' oltre a distribuire il puntatore ad una funzione definita esternamente. – user786653
Oh, ho dimenticato di menzionare un'altra caratteristica di questi: non generano alcun codice. Qualsiasi effetto scompare dopo aver completato l'ottimizzatore. Niente rimane fino al runtime. Sono semplicemente in fase di compilazione. –
Come @ utente786653 ha detto, '_ReadWriteBarrier' (o forse solo' _ReadBarrier'/'_WriteBarrier' se è tutto ciò che serve) avrà lo stesso effetto in MSVC come' clobber'. Per 'escape', la mia esperienza nell'analisi dell'output di assembly è che MSVC farà la cosa giusta se si contrassegna la variabile' volatile'. Naturalmente, vi è un sovraccarico di runtime in quanto, poiché il codice generato * * * manterrà la variabile aggiornata in memoria. Non è una soluzione perfetta, ma non ho trovato niente di meglio. –