Ho un'applicazione che trasmette 250 MB di dati, applicando una funzione di soglia neurale semplice e veloce ai blocchi di dati (che sono solo 2 parole di 32 bit ciascuno). In base al risultato del calcolo (molto semplice), il blocco viene imprevedibilmente inserito in uno dei 64 contenitori. Quindi è un grande stream in e 64 stream più brevi (di lunghezza variabile) fuori.Uso efficiente della larghezza di banda di memoria per lo streaming
Questo viene ripetuto molte volte con diverse funzioni di rilevamento.
Il calcolo è limitato dalla larghezza di banda della memoria. Posso dire questo perché non ci sono cambiamenti di velocità, anche se uso una funzione discriminante che è molto più intensiva dal punto di vista computazionale.
Qual è il modo migliore per strutturare le scritture dei nuovi stream per ottimizzare la larghezza di banda della mia memoria? Penso soprattutto che la comprensione dell'uso della cache e della dimensione della linea della cache possa giocare un ruolo importante in questo. Immagina il caso peggiore in cui ho i miei 64 flussi in uscita e, sfortunatamente, molti mappano sulla stessa linea della cache. Quindi, quando scrivo i successivi 64 bit di dati in un flusso, la CPU deve svuotare una riga di cache non aggiornata nella memoria principale e caricare nella riga della cache corretta. Ognuno di questi utilizza 64 BYTES di larghezza di banda ... quindi l'applicazione limitata della mia larghezza di banda potrebbe sprecare il 95% della larghezza di banda della memoria (in questo ipotetico caso peggiore, però).
È difficile persino provare a misurare l'effetto, quindi progettare i modi per aggirarlo è ancora più vago. O sto addirittura inseguendo un collo di bottiglia fantasma che in qualche modo l'hardware si ottimizza meglio di quanto potrei?
Sto utilizzando processori Core II x86 se questo fa alcuna differenza.
Modifica: ecco alcuni esempi di codice. Passa attraverso una matrice e copia i suoi elementi su vari array di output scelti in modo pseudo-casuale. L'esecuzione lo stesso programma con un diverso numero di bidoni di destinazione dà diversi tempi di esecuzione, anche se la stessa quantità di calcolo e di memoria di lettura e scrittura sono stati fatti:
2 flussi in uscita: 13 secondi
8 flussi di uscita: 13 secondi
32 flussi di uscita: 19 sec
128 flussi di uscita: 29 secondi
512 flussi di uscita: 47 secondi
La differenza tra l'utilizzo 512 contro 2 flussi in uscita è 4X, (probabilmente ??) causata da linea di cache sgombero aerea.
#include <stdio.h>
#include <stdlib.h>
#include <ctime>
int main()
{
const int size=1<<19;
int streambits=3;
int streamcount=1UL<<streambits; // # of output bins
int *instore=(int *)malloc(size*sizeof(int));
int **outstore=(int **)malloc(streamcount*sizeof(int *));
int **out=(int **)malloc(streamcount*sizeof(int));
unsigned int seed=0;
for (int j=0; j<size; j++) instore[j]=j;
for (int i=0; i< streamcount; ++i)
outstore[i]=(int *)malloc(size*sizeof(int));
int startTime=time(NULL);
for (int k=0; k<10000; k++) {
for (int i=0; i<streamcount; i++) out[i]=outstore[i];
int *in=instore;
for (int j=0; j<size/2; j++) {
seed=seed*0x1234567+0x7162521;
int bin=seed>>(32-streambits); // pseudorandom destination bin
*(out[bin]++)=*(in++);
*(out[bin]++)=*(in++);
}
}
int endTime=time(NULL);
printf("Eval time=%ld\n", endTime-startTime);
}
errr .. forse se c'era il codice? –
Come scritto, quel codice non verrà compilato (punto e virgola mancante, che ho aggiunto), ma sono sospettoso di qualsiasi esempio che è stato modificato per la pubblicazione. –