J'essaye d'accélérer un seul programme en utilisant prefetches. Le but de mon programme est juste pour le test. Voici ce qu'il fait:Accélérer l'accès mémoire aléatoire en utilisant prefetch
- Il utilise deux tampons int de la même taille
- Il lit un par un toutes les valeurs du premier tampon
- Il lit la valeur à l'index dans le second tampon
- Il résume toutes les valeurs prises à partir du second tampon
- Il fait toutes les étapes précédentes pour de plus en plus
- A la fin, j'imprimer le nombre de CP volontaire et involontaire U
Dans le premier temps, les valeurs dans les premières mémoires tampons contenant les valeurs de l'indice (cf. fonction createIndexBuffer
dans le code ci-dessous).
Il sera plus clair dans le code de mon programme:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/time.h>
#define BUFFER_SIZE ((unsigned long) 4096 * 100000)
unsigned int randomUint()
{
int value = rand() % UINT_MAX;
return value;
}
unsigned int * createValueBuffer()
{
unsigned int * valueBuffer = (unsigned int *) malloc(BUFFER_SIZE * sizeof(unsigned int));
for (unsigned long i = 0 ; i < BUFFER_SIZE ; i++)
{
valueBuffer[i] = randomUint();
}
return (valueBuffer);
}
unsigned int * createIndexBuffer()
{
unsigned int * indexBuffer = (unsigned int *) malloc(BUFFER_SIZE * sizeof(unsigned int));
for (unsigned long i = 0 ; i < BUFFER_SIZE ; i++)
{
indexBuffer[i] = i;
}
return (indexBuffer);
}
unsigned long long computeSum(unsigned int * indexBuffer, unsigned int * valueBuffer)
{
unsigned long long sum = 0;
for (unsigned int i = 0 ; i < BUFFER_SIZE ; i++)
{
unsigned int index = indexBuffer[i];
sum += valueBuffer[index];
}
return (sum);
}
unsigned int computeTimeInMicroSeconds()
{
unsigned int * valueBuffer = createValueBuffer();
unsigned int * indexBuffer = createIndexBuffer();
struct timeval startTime, endTime;
gettimeofday(&startTime, NULL);
unsigned long long sum = computeSum(indexBuffer, valueBuffer);
gettimeofday(&endTime, NULL);
printf("Sum = %llu\n", sum);
free(indexBuffer);
free(valueBuffer);
return ((endTime.tv_sec - startTime.tv_sec) * 1000 * 1000) + (endTime.tv_usec - startTime.tv_usec);
}
int main()
{
printf("sizeof buffers = %ldMb\n", BUFFER_SIZE * sizeof(unsigned int)/(1024 * 1024));
unsigned int timeInMicroSeconds = computeTimeInMicroSeconds();
printf("Time: %u micro-seconds = %.3f seconds\n", timeInMicroSeconds, (double) timeInMicroSeconds/(1000 * 1000));
}
Si je lance, je reçois la sortie suivante:
$ gcc TestPrefetch.c -O3 -o TestPrefetch && ./TestPrefetch
sizeof buffers = 1562Mb
Sum = 439813150288855829
Time: 201172 micro-seconds = 0.201 seconds
rapide et rapide !!! Selon mes connaissances (je peux me tromper), l'une des raisons d'avoir un programme aussi rapide est que, lorsque j'accède séquentiellement à mes deux tampons, les données peuvent être préextraites dans le cache du CPU.
Nous pouvons le rendre plus complexe afin que les données soient (presque) préfixées dans le cache CPU. Par exemple, nous pouvons simplement changer la fonction createIndexBuffer
dans:
unsigned int * createIndexBuffer()
{
unsigned int * indexBuffer = (unsigned int *) malloc(BUFFER_SIZE * sizeof(unsigned int));
for (unsigned long i = 0 ; i < BUFFER_SIZE ; i++)
{
indexBuffer[i] = rand() % BUFFER_SIZE;
}
return (indexBuffer);
}
Essayons le programme une fois encore:
$ gcc TestPrefetch.c -O3 -o TestPrefetch && ./TestPrefetch
sizeof buffers = 1562Mb
Sum = 439835307963131237
Time: 3730387 micro-seconds = 3.730 seconds
Plus de 18 fois plus lent !!!
Nous arrivons maintenant à mon problème. Compte tenu de la nouvelle fonction createIndexBuffer
, je voudrais accélérer la fonction computeSum
utilisant prélecture
unsigned long long computeSum(unsigned int * indexBuffer, unsigned int * valueBuffer)
{
unsigned long long sum = 0;
for (unsigned int i = 0 ; i < BUFFER_SIZE ; i++)
{
__builtin_prefetch((char *) &indexBuffer[i + 1], 0, 0);
unsigned int index = indexBuffer[i];
sum += valueBuffer[index];
}
return (sum);
}
bien sûr, je dois aussi changer ma createIndexBuffer
pour qu'il alloue un tampon ayant un élément supplémentaire
Je RELANCE mon programme: pas mieux! Comme prélecture peut être plus lent d'un « pour » itération de la boucle, je ne précharger un élément avant, mais deux éléments avant
__builtin_prefetch((char *) &indexBuffer[i + 2], 0, 0);
pas mieux! deux boucles d'itérations? pas mieux? Trois? ** Je l'ai essayé jusqu'à 50 (!!!) mais je ne peux pas améliorer les performances de ma fonction computeSum
.
Puis-je voudrais aider à comprendre pourquoi Je vous remercie beaucoup pour votre aide
Ma réponse pour votre suggestion de «péché» est au-dessus de votre réponse, pas ci-dessous (j'ai certainement fait une erreur ...) –