Question

J'ai la tâche suivante pour démontrer le partage faux et écrit un programme simple:

#include <sys/times.h>
#include <time.h>
#include <stdio.h> 
#include <pthread.h> 

long long int tmsBegin1,tmsEnd1,tmsBegin2,tmsEnd2,tmsBegin3,tmsEnd3;

int array[100];

void *heavy_loop(void *param) { 
  int   index = *((int*)param);
  int   i;
  for (i = 0; i < 100000000; i++)
    array[index]+=3;
} 

int main(int argc, char *argv[]) { 
  int       first_elem  = 0;
  int       bad_elem    = 1;
  int       good_elem   = 32;
  long long time1;
  long long time2;
  long long time3;
  pthread_t     thread_1;
  pthread_t     thread_2;

  tmsBegin3 = clock();
  heavy_loop((void*)&first_elem);
  heavy_loop((void*)&bad_elem);
  tmsEnd3 = clock();

  tmsBegin1 = clock();
  pthread_create(&thread_1, NULL, heavy_loop, (void*)&first_elem);
  pthread_create(&thread_2, NULL, heavy_loop, (void*)&bad_elem);
  pthread_join(thread_1, NULL);
  pthread_join(thread_2, NULL);
  tmsEnd1 = clock(); 

  tmsBegin2 = clock();
  pthread_create(&thread_1, NULL, heavy_loop, (void*)&first_elem);
  pthread_create(&thread_2, NULL, heavy_loop, (void*)&good_elem);
  pthread_join(thread_1, NULL);
  pthread_join(thread_2, NULL);
  tmsEnd2 = clock();

  printf("%d %d %d\n", array[first_elem],array[bad_elem],array[good_elem]);
  time1 = (tmsEnd1-tmsBegin1)*1000/CLOCKS_PER_SEC;
  time2 = (tmsEnd2-tmsBegin2)*1000/CLOCKS_PER_SEC;
  time3 = (tmsEnd3-tmsBegin3)*1000/CLOCKS_PER_SEC;
  printf("%lld ms\n", time1);
  printf("%lld ms\n", time2);
  printf("%lld ms\n", time3);

  return 0; 
} 

J'ai été très surpris quand j'ai vu les résultats (je cours sur mon processeur i5-430M).

  • Avec le partage de faux, il était 1020 ms.
  • Sans faux partage, il était de 710 ms, seulement 30% plus rapide au lieu de 300% (il a été écrit sur certains sites que ce serait plus rapide que 300-400%).
  • Sans utiliser pthreads, il était de 580 ms.

S'il vous plaît me montrer mon erreur ou expliquer pourquoi il arrive.

Était-ce utile?

La solution

Fonction Mémoire sur l'horloge () en C - Il vous donne le nombre d'horloges CPU écoulées depuis le début jusqu'à la fin. Donc, lorsque vous exécutez deux fils parallèles, le nombre de cycles CPU sera cycles d'horloge de cycles d'horloge CPU1 + de UC2. Je pense que ce que vous voulez est une véritable horloge de minuterie. Pour cette utilisation clock_gettime () et vous devriez obtenir le résultat attendu.

J'ai couru votre code avec le clock_gettime () Je suis arrivé ceci:.

faux partage 874.587381 ms

sans faux partage 331.844278 ms

calcul séquentiel 604.160276 ms

Autres conseils

Faux partage est le résultat de plusieurs cœurs avec des caches séparés accédant à la même région de mémoire physique (mais pas la même adresse - qui serait vrai partage).

Pour comprendre le partage faux, vous devez comprendre les caches. Dans la plupart des processeurs, chaque noyau aura son propre cache L1, qui contient des données récemment accédé. Les caches sont organisés en « lignes », qui sont alignées blocs de données, habituellement 32 ou 64 octets de longueur (selon le processeur). Lorsque vous lisez une adresse qui est pas dans le cache, la ligne entière est lue dans la mémoire principale (ou un cache L2) en L1. Lorsque vous écrivez à une adresse dans le cache, la ligne contenant cette adresse est marquée « sale ».

Voici où l'aspect de partage entre en jeu. Si plusieurs noyaux sont en train de lire à partir de la même ligne, ils peuvent chacun avoir une copie de la ligne en L1. Toutefois, si une copie est sale marque, il annule la ligne dans les autres caches. Si cela ne se produit pas, puis écrit sur un noyau fait peut-être pas visible aux noyaux des autres jusqu'à ce que beaucoup plus tard. La prochaine fois que l'autre noyau va lire de cette ligne, les défauts de cache, et il doit chercher à nouveau la ligne.

false partage se produit lorsque les noyaux sont la lecture et l'écriture à des adresses différentes sur la même ligne. Même si elles ne partagent pas les données, les caches agissent comme ils sont, car ils sont si proches.

Cet effet dépend fortement de l'architecture de votre processeur. Si vous aviez un processeur simple core, vous ne verrez pas l'effet du tout, car il n'y aurait pas de partage. Si vos lignes de cache sont plus, vous verriez l'effet dans les deux cas, les « mauvais » et « bon », car ils sont toujours proches. Si vos cœurs ne partagent pas un cache L2 (que je devine qu'ils font), vous pouvez voir la différence 300-400% comme vous le dites, car ils devraient aller tout le chemin à la mémoire principale sur un défaut de cache.

Vous aimerez aussi savoir qu'il est important que chaque fil est à la fois la lecture et l'écriture (+ = au lieu de =). Certains processeurs ont write-through caches qui signifie que si un noyau de écriture à une adresse pas dans le cache, il ne vous perdez pas et vont chercher la ligne de la mémoire. Cela contraste avec write-back caches, qui ne manque sur les écritures.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top