web-dev-qa-db-fra.com

Comment trouver la taille de la taille de la ligne de cache L1 avec IO mesures de chronométrage?

En tant qu'école, je dois trouver un moyen d'obtenir la taille de ligne du cache de données L1, sans lire les fichiers de configuration ni utiliser les appels api. Censé utiliser des accès mémoire pour lire et écrire des timings pour analyser et obtenir ces informations. Alors, comment pourrais-je faire ça? 

Dans une tentative incomplète pour une autre partie de la mission, pour trouver les niveaux et la taille du cache, j'ai: 

for (i = 0; i < steps; i++) {
    arr[(i * 4) & lengthMod]++;
}

Je pensais que j'avais peut-être simplement besoin de varier la ligne 2, (i * 4) partie? Donc, une fois la taille de la ligne de cache dépassée, il peut être nécessaire de la remplacer, ce qui prend parfois? Mais est-ce si simple? Le bloc requis est peut-être déjà en mémoire quelque part? Ou encore, je peux toujours compter sur le fait que si j’ai une steps assez grande, cela fonctionnera quand même assez précisément? 

METTRE &AGRAVE; JOUR

Voici une tentative sur GitHub ... partie principale ci-dessous

// repeatedly access/modify data, varying the STRIDE
for (int s = 4; s <= MAX_STRIDE/sizeof(int); s*=2) {
    start = wall_clock_time();
    for (unsigned int k = 0; k < REPS; k++) {
        data[(k * s) & lengthMod]++;
    }
    end = wall_clock_time();
    timeTaken = ((float)(end - start))/1000000000;
    printf("%d, %1.2f \n", s * sizeof(int), timeTaken);
}

Le problème est qu'il ne semble pas y avoir beaucoup de différences entre le timing. FYI. depuis sa pour cache L1. J'ai TAILLE = 32 K (taille du tableau)

36
Jiew Meng

Allouez un tableau BIG char (assurez-vous qu'il est trop grand pour tenir dans le cache L1 ou L2). Remplissez-le avec des données aléatoires.

Commencez à parcourir le tableau en étapes de n octets. Faites quelque chose avec les octets récupérés, comme les sommer.

Analysez et calculez le nombre d'octets/seconde que vous pouvez traiter avec différentes valeurs de n, en commençant à 1 et en comptant jusqu'à 1 000 ou plus. Assurez-vous que votre benchmark imprime la somme calculée, afin que le compilateur ne puisse pas optimiser le code référencé.

Lorsque n == la taille de votre ligne de cache, chaque accès nécessitera la lecture d’une nouvelle ligne dans le cache N1. Les résultats de l’indice de référence devraient donc ralentir assez fortement à ce stade.

Si le tableau est assez grand, au moment où vous atteignez la fin, les données au début du tableau seront déjà à nouveau en mémoire cache, comme vous le souhaitez. Ainsi, après avoir incrémenté n et recommencé, les résultats ne seront pas affectés si les données nécessaires sont déjà dans le cache.

27
Alex D

Regardez Calibrator , tout le travail est protégé par copyright, mais le code source est disponible gratuitement. De son idée de document de calculer la taille des lignes de cache semble beaucoup plus instruit que ce qui est déjà dit ici.

L’idée sous-jacente à notre outil de calibrage est de disposer d’un micro-benchmark dont les performances ne dépendent que sur la fréquence des erreurs de cache qui se produisent. Notre calibrateur est un simple programme en C, principalement une petite boucle qui exécute un million de lectures en mémoire. En modifiant la foulée (c'est-à-dire le décalage entre deux accès mémoire ultérieurs ) Et la taille de la zone mémoire, nous forçons des taux de perte de mémoire cache variables.

En principe, la fréquence des erreurs de cache est déterminée par la taille de la matrice. Tailles de tableau qui correspondent à le cache L1 ne génère aucun cache manquant une fois les données chargées dans le cache. De manière analogue, Les tableaux qui dépassent la taille du cache L1 mais qui tiennent toujours dans L2 provoquent des échecs de L1, mais aucun échec de L2. Finalement, les matrices plus grandes que L2 sont à l'origine des échecs de L1 et de L2.

La fréquence des erreurs de cache dépend de la foulée d'accès et de la taille de la ligne de cache. À grands pas égal ou supérieur à la taille de la ligne de cache, un échec de cache se produit à chaque itération. À grands pas plus petite que la taille de la ligne de cache, un échec de cache se produit uniquement toutes les n itérations (en moyenne), où n est le ratio cache ligne taille/foulée.

Ainsi, nous pouvons calculer le temps de latence d’un cache cache en comparant le temps d’exécution sans manque le temps d'exécution avec exactement un manque par itération. Cette approche ne fonctionne que si Les accès mémoire sont exécutés purement séquentiels, c’est-à-dire qu’il faut s’assurer que ni deux ni plus ne chargent Les instructions, l’accès à la mémoire et le travail pur du processeur peuvent se chevaucher. Nous utilisons un simple pointeur chassant mécanisme pour y parvenir: la zone de mémoire à laquelle on accède est initialisée de telle sorte que chaque chargement renvoie le adresse pour la charge suivante dans la prochaine itération. Ainsi, les processeurs super-scalaires ne peuvent pas bénéficier de leur capacité à masquer la latence des accès mémoire par une exécution spéculative.

Pour mesurer les caractéristiques du cache, nous avons effectué notre expérience plusieurs fois, en faisant varier la foulée et la taille du tableau. Nous nous assurons que la foulée varie au moins entre 4 octets et deux fois le maximum la taille de ligne de cache attendue et que la taille de la matrice varie de la moitié de la taille de cache minimale attendue à au moins dix fois la taille de cache maximale attendue.

J'ai dû commenter #include "math.h" pour le compiler, après quoi il a trouvé les valeurs de cache de mon ordinateur portable correctement. Je ne pouvais pas non plus voir les fichiers postscript générés.

5
auselen

Vous pouvez utiliser la fonction CPUID dans l'assembleur, bien que non portable, elle vous donnera ce que vous voulez.

Pour les microprocesseurs Intel, la taille de la ligne de cache peut être calculée en multipliant bh par 8 après l'appel de la fonction cpuid 0x1.

Pour les microprocesseurs AMD, la taille de ligne de cache de données est en clé et l'instruction Taille de ligne de cache est en dl après l'appel de la fonction cpuid 0x80000005.

J'ai pris ceci de cet article ici .

3
Tony The Lion

Je pense que vous devriez écrire un programme, qui parcourra tableau dans un ordre aléatoire plutôt que tout droit, car les processus modernes effectuent la lecture anticipée par le matériel . programme il y a 1 an http://Pastebin.com/9mFScs9Z Désolé pour mon anglais, je ne suis pas locuteur natif.

2
Alexey Matveev

Voyez comment memtest86 est implémenté. Ils mesurent et analysent le taux de transfert de données d'une manière ou d'une autre. Les points de changement de débit correspondent à la taille de L1, L2 et à la taille possible du cache L3.

1
vitaly.v.ch

Si vous êtes coincé dans la boue et que vous ne pouvez pas sortir, regardez ici .

Des manuels et des codes expliquent comment faire ce que vous demandez. Le code est également de haute qualité. Regardez "Bibliothèque de sous-routines".

Le code et les manuels sont basés sur les processeurs X86.

1
JimR

Je pense que cela devrait être suffisant pour chronométrer une opération utilisant une certaine quantité de mémoire. Augmentez ensuite progressivement la mémoire (opérandes, par exemple) utilisée par l'opération . Lorsque la performance de l'opération diminue considérablement, vous avez trouvé la limite.

J'allais simplement lire quelques octets sans les imprimer (l'impression aurait un impact négatif sur la performance, qui deviendrait un goulot d'étranglement). Lors de la lecture, le minutage doit être directement proportionnel au nombre d'octets lus jusqu'à ce que les données ne puissent plus correspondre à la N1. Vous obtiendrez ainsi l'impact sur les performances.

Vous devez également allouer la mémoire une fois au début du programme et avant de commencer à compter le temps.

0
enTropy

Juste une note.

La taille de la ligne de cache est variable sur quelques familles de cortex ARM et peut changer pendant l'exécution sans notification à un programme en cours.

0
vitaly.v.ch