tous Hy,Test - Odd résultats
me demandais l'autre jour comment les modèles d'accès très différentes affecté la vitesse de lecture mémoire (pensée principalement sur la fréquence vs discussion de la taille du bus, et l'impact du taux de succès de cache) , donc fait un petit programme pour tester la vitesse de la mémoire en faisant des accès séquentiels et entièrement aléatoires, mais les résultats que j'ai obtenus sont assez bizarres, donc je ne fais pas confiance à mon code.
Mon idée était assez simple, juste en boucle sur un tableau et déplacer les données dans un registre. Fait 3 versions, on déplace 128 bits à la fois avec sse, l'autre 32, et le dernier 32 encore mais en faisant deux movs, le premier chargeant un nombre aléatoire d'un tableau, et le deuxième lisant à partir de la position spécifiée par la valeur prev. J'ai obtenu ~ 40 Go/s pour la version sse, que c'est raisonnable considérant que j'utilise un i7 4790K avec DDR3 1600 cl9 mémoire à double canal, qui donne environ 25 Go/s, alors ajoutez à ce cache et ça me fait plaisir, mais alors j'ai 3,3 Go/s pour le séquentiel normal, et le pire, 15 Go/s pour le hasard. Ce dernier résultat me fait penser que le banc est bidon.
Ci-dessous est le code, si quelqu'un pouvait faire la lumière sur ce qu'il serait apprécié. Est-ce que la boucle interne dans l'assemblage pour s'assurer qu'il a seulement fait un mov.
EDIT: Nous avons réussi à obtenir un peu plus de performance en utilisant vlddqu ymm0, buffL [esi] (AVX) au lieu de movlps, est passé de 38 Go/s à 41 Go/s
EDIT 2: Est-ce un peu plus tester, dérouler la boucle de l'assemblage interne, faire une version qui charge 4 fois par itération et une autre qui charge 8 fois. Obtenu ~ 35 GB/s pour la version x4 et ~ 24 GB/s pour la version x8
#define PASSES 1000000
double bw = 0;
int main()
{
cout << "Running : ";
bw = 0;
for(int n = 0; n < PASSES;n++)
{
if(n % 100000 == 0) cout << ".";
const int l = 1 << 16;
int buffL[l];
LARGE_INTEGER frequency; // ticks per second
LARGE_INTEGER t1, t2; // ticks
// get ticks per second
QueryPerformanceFrequency(&frequency);
// start timer
QueryPerformanceCounter(&t1);
int maxByte = l*4;
__asm
{
push esi
mov esi,0
loopL0:
movlps xmm0, buffL[esi]
add esi,16
cmp esi,maxByte
jb loopL0
pop esi
}
// stop timer
QueryPerformanceCounter(&t2);
// compute elapsed time in millisec
double ms = (t2.QuadPart - t1.QuadPart) * 1000.0/frequency.QuadPart;
bw += (double(4ull*l)/1073741824.0)/(double(ms)*0.001);
}
bw /= double(PASSES);
cout << endl;
cout << " Sequential (SSE) : " << bw << " GB/s " << endl;
cout << "Running : ";
bw = 0;
for(int n = 0; n < PASSES;n++)
{
if(n % 100000 == 0) cout << ".";
const int l = 1 << 16;
int buffL[l];
for(int t = 0;t < l;t++) buffL[t] = (t+1)*4;
LARGE_INTEGER frequency; // ticks per second
LARGE_INTEGER t1, t2; // ticks
// get ticks per second
QueryPerformanceFrequency(&frequency);
// start timer
QueryPerformanceCounter(&t1);
int maxByte = l*4;
__asm
{
push esi
mov esi,0
loopL1:
mov esi, buffL[esi]
cmp esi,maxByte
jb loopL1
pop esi
}
// stop timer
QueryPerformanceCounter(&t2);
// compute elapsed time in millisec
double ms = (t2.QuadPart - t1.QuadPart) * 1000.0/frequency.QuadPart;
bw += (double(4ull*l)/1073741824.0)/(double(ms)*0.001);
}
bw /= double(PASSES);
cout << endl;
cout << " Sequential : " << bw << " GB/s " << endl;
cout << "Running : ";
bw = 0;
for(int n = 0; n < PASSES;n++)
{
if(n % 100000 == 0) cout << ".";
const int l = 1 << 14;
int buffL[l];
int maxByte = l*4;
int roffset[l];
for(int t = 0;t < l;t++) roffset[t] = (rand()*4) % maxByte;
LARGE_INTEGER frequency; // ticks per second
LARGE_INTEGER t1, t2; // ticks
// get ticks per second
QueryPerformanceFrequency(&frequency);
// start timer
QueryPerformanceCounter(&t1);
__asm
{
push esi
push edi
mov esi,0
loopL2:
mov edi, roffset[esi]
mov edi, buffL[edi]
add esi,4
cmp esi,maxByte
jb loopL2
pop edi
pop esi
}
// stop timer
QueryPerformanceCounter(&t2);
// compute elapsed time in millisec
double ms = (t2.QuadPart - t1.QuadPart) * 1000.0/frequency.QuadPart;
bw += (double(2*4ull*l)/1073741824.0)/(double(ms)*0.001);
}
bw /= double(PASSES);
cout << endl;
cout << " Random : " << bw << " GB/s " << endl;
return 0;
}
Pour éviter la possibilité d'un essai influer sur l'issue d'une autre en raison de l'une optimisation du compilateur ou le cache, séparer chacun de vos trois tests boucles dans leur propre fichier source. (Pour que chacun soit compilé séparément). Puis un autre fichier source qui implémente "main" et prend un argument de la ligne de commande dont test à exécuter. Exécutez les tests séparément et exécutez plusieurs fois. – selbie
Déclarez maxByte comme const. 'const int maxByte = l * 4;' – selbie