2010-11-01 6 views
3

Cela fait partie de la sortie de cachegrind. Cette partie du code a été exécutée 1224 fois. elmg1 est un tableau de longueur non signée de 16 x 20. La taille de ma mémoire cache de la machine L1 est de 32 Ko, la taille de la ligne de cache de 64 Mo et l'ensemble associatif à 8 voies.Interprétation de la sortie de cachegrind

  1. for (i = 0; i < 20; i ++) 78336 2448 50184 2 0 0 0 0 1224
  2. {
  3. telm01 = elmg1 [i]; 146,880 0 0 73,440 0 0 24,480 0 0
  4. telm31 = (telm01 < < 3)^val1; 97,920 0 0 48,960 0 0 24,480 0 0
  5. telm21 = (telm01 < < 2)^(val1 >> 1); 146,880 1,224 1 48,960 0 0 24,480 0 0
  6. telm11 = (telm01 < < 1)^(val1 >> 2); 146.880 0 0 48.960 0 0 24.480 0 0
  7. }

A. La raison pour laquelle je l'ai mis ici, est que, dans la 3ème ligne à l'intérieur de la boucle, je vois un certain nombre de I1 manque (une L2 manque aussi bien). C'est un peu confus et je ne pouvais pas deviner la raison pour laquelle?

B. J'essaie d'optimiser (temps) une partie du code. Ce qui précède est juste un petit extrait. Je pense que dans mon programme d'accès à la mémoire m'a coûté beaucoup. Comme dans l'exemple ci-dessus, elmg1 est un tableau de taille 16 x 20 de longs non signés. Quand j'essaie de l'utiliser dans le code, il y a toujours des échecs, et dans mon programme ces variables se produisent beaucoup. Aucune suggestion?

C. Je dois allouer et (parfois initialiser) ces longs non signés. Pouvez-vous suggérer lequel devrais-je préférer, déclaration de calloc ou de tableau et puis initialisation explicite. Par ailleurs, y aura-t-il une différence dans la façon dont le cache les gère?

Merci.

Répondre

3

Avez-vous essayé de dérouler la boucle?

  1. Je ne m'inquiéterais pas des échecs L1 pour le moment. De plus, un L2 manqué de 1224 fois est correct, le CPU doit charger les valeurs dans le cache à un moment donné.
  2. Quel pourcentage de L2 rate ce code par rapport au reste du programme?
  3. Utilisez calloc(), si la taille du tableau est toujours la même et que vous utilisez des constantes pour la taille, le compilateur peut optimiser le zéro du tableau. En outre, la seule chose qui affecterait les utilisations des lignes de cache est l'alignement, pas la façon dont il a été initié.

edit: Le nombre était difficile à lire de cette façon et les lisait mal la première fois.

permet de vous assurer que je suis en train de lire les bons chiffres pour la ligne 5:

Ir 146,880 
I1mr 1,224 
ILmr 1 
Dr 48,960 
D1mr 0 
DLmr 0 
Dw 24,480 
D1mw 0 
DLmw 0 

Le cache L1 est divisé en deux caches 32Kbyte un pour le code I1 et l'une des données D1. IL & DL sont le cache L2 ou L3 partagé par les données et les instructions.

Le grand nombre d'instructions I1mr manque et ne rate pas les données, ce qui signifie que le code de boucle est éjecté du cache d'instructions I1.I1 manque à la ligne 1 & 5 total 3672 soit 3 fois 1224, de sorte que chaque fois que la boucle est exécutée, vous obtenez 3 I1 cache manquants avec des lignes de cache 64Byte qui signifie que la taille du code de boucle est comprise entre 128-192 octets pour couvrir 3 lignes de cache. Donc, ceux qui manquent à la ligne 5, c'est parce que c'est là que le code de la boucle traverse la dernière ligne de cache.

I would recommend using KCachegrind for viewing the results from cachegrind

Edit: En savoir plus sur les lignes de cache. Ce code de boucle n'a pas l'air d'appeler 1224 fois par lui-même, ce qui signifie qu'il y a plus de code qui pousse ce code hors du cache I1. Le cache I1 de 32 Ko est divisé en 512 lignes de cache (64 octets chacune). La partie "association de 8 ensembles associatifs" signifie que chaque adresse de mémoire est mappée à seulement 8 des 512 lignes de cache. Si l'ensemble du programme que vous êtes en profil était un bloc continu de 32 Ko de mémoire, alors tout rentrerait dans le cache I1 et aucun ne serait éjecté. Ce n'est probablement pas le cas et il y aura plus de 8 blocs de 64 octets de code pour les mêmes 8 lignes de cache. Disons que votre programme entier a 1 Mo de code (cela inclut les bibliothèques), alors chaque groupe de 8 lignes de cache aura environ 32 morceaux de code (1 Mo/32 Ko) pour ces mêmes 8 lignes de cache.

Read this lwn.net article for all the gory details about CPU caches

Le compilateur ne peut pas toujours détecter les fonctions du programme seront les points chauds (appelé beaucoup de fois) et qui sera codespots (à savoir le code de gestionnaire d'erreurs, qui fonctionne presque jamais). GCC a des attributs de fonction hot/cold qui vous permettront de marquer les fonctions comme chaud/froid, ce qui permettra au compilateur de regrouper les fonctions chaudes dans un bloc de mémoire pour obtenir une meilleure utilisation du cache (ie le code froid ne poussera pas le hotcode caches).

De toute façon ceux qui me manquent ne valent vraiment pas le temps de s'inquiéter.

+0

A. C'est ok, mais pourquoi il y a des échecs de cache à la ligne 5, alors qu'il y en a moins à la ligne 3, 4. Dois-je spécifier la chose d'alignement moi-même? . – anup

+0

Oui, malloc devrait fournir au moins 8 octets d'alignement, mais ce n'est pas la même chose que l'alignement du cache de 64 octets. L'alignement du cache est important uniquement lorsque vous disposez d'un tableau d'objets de 64 octets chacun. Si le cache n'est pas aligné, l'accès à un élément du tableau peut provoquer deux échecs de cache au lieu d'un. Mais l'alignement du cache n'est pas un problème dans ce cas. – Neopallium

+0

Merci pour votre réponse. Mais, une chose que je n'ai pas compris ce que cela a à voir avec 3 lignes de cache? Il devrait y avoir plus de lignes de cache. – anup

Questions connexes