J'ai une application qui parcourt 250 Mo de données, en appliquant une fonction de seuil neural-net simple et rapide aux blocs de données (qui ne sont que 2 mots de 32 bits chacun). Basé sur le résultat du calcul (très simple), le morceau est poussé de façon imprévisible dans l'un des 64 casiers. Il y a donc un grand flux dans et 64 flux plus courts (de longueur variable).Utilisation efficace de la bande passante mémoire pour le streaming
Ceci est répété plusieurs fois avec différentes fonctions de détection.
Le calcul est limité par la bande passante mémoire. Je peux le dire parce qu'il n'y a pas de changement de vitesse, même si j'utilise une fonction discriminante qui est beaucoup plus computationnelle. Quel est le meilleur moyen de structurer les écritures des nouveaux flux pour optimiser ma bande passante mémoire?
Je pense surtout que la compréhension de l'utilisation du cache et de la taille de la ligne de cache peut jouer un grand rôle dans ce domaine. Imaginez le pire des cas où j'ai mes 64 flux de sortie et par malchance, beaucoup mappent sur la même ligne de cache. Ensuite, lorsque j'écris les 64 bits de données suivants dans un flux, le processeur doit vider une ligne de cache périmée dans la mémoire principale et charger dans la ligne de cache appropriée. Chacun d'entre eux utilise 64 octets de bande passante ... donc mon application limitée en bande passante peut gaspiller 95% de la bande passante mémoire (dans ce cas hypothétique, cependant).
Il est difficile d'essayer même de mesurer l'effet, donc la conception des façons de le contourner est encore plus vague. Ou suis-je même à la poursuite d'un goulot d'étranglement que le matériel optimise d'une manière ou d'une autre? J'utilise des processeurs Core II x86 si cela fait une différence.
Editer: Voici un exemple de code. Il circule dans un tableau et copie ses éléments dans différents tableaux de sortie choisis de manière pseudo-aléatoire. L'exécution du même programme avec un nombre différent de bacs de destination donne différents runtimes, même si la même quantité de calcul et de mémoire lectures et écritures ont été faites:
2 flux de sortie: 13 secondes
8 flux de sortie: 13 secondes
32 flux de sortie: 19 secs
128 streams de sortie: 29 secondes
512 streams de sortie: 47 secondes
La différence entre l'utilisation de 512 par rapport à 2 flux de sortie est 4X, (probablement ??) causée par les frais généraux d'expulsion de ligne de cache.
#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 .. peut-être s'il y avait du code? –
Comme écrit, ce code ne compilera pas (point-virgule manquant, que j'ai ajouté), mais je me méfie de tout exemple qui a été édité pour publication. –