Ho notato che a volte MSVC 2010 non riordina affatto le istruzioni SSE. Ho pensato che non dovevo preoccuparmi dell'ordine delle istruzioni all'interno del mio ciclo, dal momento che il compilatore gestisce meglio, il che non sembra essere il caso.Ordine di micro-ottimizzazione SSE
Come dovrei pensare a questo? Cosa determina il miglior ordine di istruzioni? So che alcune istruzioni hanno una latenza maggiore di altre e che alcune istruzioni possono essere eseguite in parallelo/asincrono a livello di CPU. Quali metriche sono rilevanti nel contesto? Dove posso trovarli?
So che avrei potuto evitare questa domanda per profilatura, tuttavia tali profiler sono costosi (VTune XE) e mi piacerebbe conoscere la teoria dietro di esso, non solo i risultati empirica.
Inoltre, dovrei preoccuparmi del precaricamento del software (_mm_prefetch
) o posso presumere che la cpu farà un lavoro migliore di me?
Diciamo che ho la seguente funzione. Devo interlacciare alcune delle istruzioni? Devo fare i negozi prima dei flussi, fare tutti i carichi in ordine e poi fare i calcoli, ecc ...? Devo considerare USWC vs non USWC, e temporale vs non temporale?
auto cur128 = reinterpret_cast<__m128i*>(cur);
auto prev128 = reinterpret_cast<const __m128i*>(prev);
auto dest128 = reinterpret_cast<__m128i*>(dest;
auto end = cur128 + count/16;
while(cur128 != end)
{
auto xmm0 = _mm_add_epi8(_mm_load_si128(cur128+0), _mm_load_si128(prev128+0));
auto xmm1 = _mm_add_epi8(_mm_load_si128(cur128+1), _mm_load_si128(prev128+1));
auto xmm2 = _mm_add_epi8(_mm_load_si128(cur128+2), _mm_load_si128(prev128+2));
auto xmm3 = _mm_add_epi8(_mm_load_si128(cur128+3), _mm_load_si128(prev128+3));
// dest128 is USWC memory
_mm_stream_si128(dest128+0, xmm0);
_mm_stream_si128(dest128+1, xmm1);
_mm_stream_si128(dest128+2, xmm2);;
_mm_stream_si128(dest128+3, xmm3);
// cur128 is temporal, and will be used next time, which is why I choose store over stream
_mm_store_si128 (cur128+0, xmm0);
_mm_store_si128 (cur128+1, xmm1);
_mm_store_si128 (cur128+2, xmm2);
_mm_store_si128 (cur128+3, xmm3);
cur128 += 4;
dest128 += 4;
prev128 += 4;
}
std::swap(cur, prev);
Penso che la risposta a questo deve essere nei test misurati. Anche se x86 ha avuto [OOE] (http://en.wikipedia.org/wiki/Out-of-order_execution) per un bel po 'di tempo, che potrebbe benissimo gestire questo caso in modo ottimale indipendentemente dall'ordinazione. – Flexo
I test sono sempre i migliori. Tuttavia in questo caso richiederebbe un profiler piuttosto costoso, ad es. VTune XE. Mi piacerebbe saperne di più sulla teoria dietro di esso rispetto ai risultati empirici. Quanto lontano va OOE? E 'per latenza della memoria o latenza delle istruzioni? OOE si prende cura delle istruzioni che potrebbero essere eseguite in parallelo se riordinate? – ronag
Puoi pubblicare l'output di assembler di build di rilascio di questo? Sarebbe interessante vedere cosa fa il compilatore con questo. – Skizz