I seguenti test sono stati eseguiti con il compilatore Visual C ++ in quanto viene utilizzato dall'installazione predefinita di Qt Creator (suppongo senza flag di ottimizzazione). Quando si utilizza GCC, non c'è alcuna grande differenza tra la versione di Mystical e il mio codice "ottimizzato". Quindi la conclusione è che le ottimizzazioni del compilatore si prendono cura della micro ottimizzazione meglio degli umani (finalmente io). Lascio il resto della mia risposta come riferimento.
Non è efficiente elaborare le immagini in questo modo. È meglio usare matrici a dimensione singola. L'elaborazione di tutti i pixel avviene in un ciclo. L'accesso casuale ai punti potrebbe essere fatto usando:
pointer + (x + y*width)*(sizeOfOnePixel)
In questo caso particolare, è meglio calcolare e memorizzare nella cache la somma di tre gruppi di pixel in orizzontale perché vengono utilizzati tre volte ciascuno.
Ho fatto alcuni test e penso che valga la pena condividerli. Ogni risultato è una media di cinque test.
Codice originale per utente1615209:
8193: 4392 ms
8192: 9570 ms
La versione di Mystical:
8193: 2393 ms
8192: 2190 ms
Due passaggi utilizzando un array 1D: primo passaggio per somme orizzontali, secondo per somma verticale e media. Indirizzamento a due passaggi con tre puntatori e solo incrementi come questo:
imgPointer1 = &avg1[0][0];
imgPointer2 = &avg1[0][SIZE];
imgPointer3 = &avg1[0][SIZE+SIZE];
for(i=SIZE;i<totalSize-SIZE;i++){
resPointer[i]=(*(imgPointer1++)+*(imgPointer2++)+*(imgPointer3++))/9;
}
8193: 938 ms
8192: 974 ms
Due passaggi usando un array 1D e indirizzando in questo modo:
for(i=SIZE;i<totalSize-SIZE;i++){
resPointer[i]=(hsumPointer[i-SIZE]+hsumPointer[i]+hsumPointer[i+SIZE])/9;
}
8193: 932 ms
8192: 925 ms
Un passaggio memorizza nella cache le somme orizzontali solo una riga in avanti in modo da rimanere nella cache:
// Horizontal sums for the first two lines
for(i=1;i<SIZE*2;i++){
hsumPointer[i]=imgPointer[i-1]+imgPointer[i]+imgPointer[i+1];
}
// Rest of the computation
for(;i<totalSize;i++){
// Compute horizontal sum for next line
hsumPointer[i]=imgPointer[i-1]+imgPointer[i]+imgPointer[i+1];
// Final result
resPointer[i-SIZE]=(hsumPointer[i-SIZE-SIZE]+hsumPointer[i-SIZE]+hsumPointer[i])/9;
}
8193: 599 ms
8192: 652 ms
Conclusione:
- Nessun vantaggio derivante dall'utilizzo di diversi puntatori e solo incrementi (ho pensato che sarebbe stato più veloce)
- La memorizzazione nella cache delle somme orizzontali è meglio che calcolarle più volte.
- Il doppio passaggio non è tre volte più veloce, solo due volte.
- È possibile ottenere 3,6 volte più velocemente utilizzando sia un singolo passaggio sia la memorizzazione nella cache di un risultato intermedio
Sono sicuro che è possibile fare molto meglio.
NOTA
Si noti che ho scritto questa risposta per indirizzare i problemi di prestazioni generali anziché il problema di cache spiegato nella risposta eccellente di Mystical. All'inizio era solo uno pseudo codice. Mi è stato chiesto di fare dei test nei commenti ... Ecco una versione completamente refactored con i test.