Tengo una aplicación que transmite 250 MB de datos, aplicando una función de umbral neuronal simple y rápida a los fragmentos de datos (que son solo 2 palabras de 32 bits cada uno). Basado en el resultado del cálculo (muy simple), el fragmento es empujado imprevistamente en uno de los 64 bins. Por lo tanto, se trata de una gran transmisión y 64 secuencias más cortas (longitud variable).Uso eficiente del ancho de banda de memoria para la transmisión
Esto se repite muchas veces con diferentes funciones de detección.
El cálculo es el ancho de banda de memoria limitado. Puedo decir esto porque no hay cambio de velocidad incluso si uso una función discriminante que es mucho más intensiva en términos de computación.
¿Cuál es la mejor forma de estructurar las escrituras de las nuevas transmisiones para optimizar el ancho de banda de mi memoria? Estoy especialmente pensando que comprender el uso de la memoria caché y el tamaño de la línea de caché puede jugar un papel importante en esto. Imagine el peor caso en el que tengo mis 64 flujos de salida y, por mala suerte, muchos se asignan a la misma línea de caché. Luego, cuando escribo los siguientes 64 bits de datos en una secuencia, la CPU tiene que vaciar una línea de caché obsoleta a la memoria principal y cargar en la línea de caché adecuada. Cada uno de ellos usa 64 BYTES de ancho de banda ... por lo que mi aplicación de ancho de banda limitado puede estar desperdiciando el 95% del ancho de banda de la memoria (en este caso hipotético más desfavorable).
Incluso es difícil intentar medir el efecto, por lo que diseñar formas de evitarlo es aún más vago. ¿O incluso estoy persiguiendo un cuello de botella fantasma que de alguna manera el hardware optimiza mejor que yo podría?
Estoy usando procesadores Core II x86 si eso hace alguna diferencia.
Editar: Aquí hay un código de ejemplo. Fluye a través de una matriz y copia sus elementos a varias matrices de salida elegidas pseudoaleatoriamente. Al ejecutar el mismo programa con diferente número de bandejas de destino da diferentes tiempos de ejecución, a pesar de que la misma cantidad de cálculo y la memoria lee y se realizaron escribe:
2 flujos de salida: 13 segundos
8 flujos de salida: 13 segundos
32 corrientes de salida: 19 secs
128 flujos de salida: 29 segundos
512 flujos de salida: 47 segundos
La diferencia entre el uso de 512 frente a 2 flujos de salida es 4X, (probablemente ??) causada por línea de caché overhead desalojo.
#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 .. ¿tal vez si hubiera código? –
Tal como está escrito, ese código no se compilará (falta el punto y coma, que he agregado), pero sospecho que algún ejemplo ha sido editado para su publicación. –