8
votes

Comment écrire un programme en C pour mesurer la vitesse du cache?

Écrivez un programme et essayez de comparer (mesurer, si vous le pouvez) l'heure d'accès à des données de la mémoire principale et du cache.

Si vous pouvez le faire, comment mesurer la vitesse de chaque niveau de cache?


11 commentaires

TNIS est-il même réalisable? Les caches ne sont pas sous votre contrôle, vous n'avez aucun moyen de savoir lorsque des données sont chargées de l'endroit. (D'accord, peut-être que vous pourriez tracer le cache misses, mais je suppose que les frais généraux de traçage confondaient les résultats.)


Peut-être utiliser des registres et du MMAP? Mais cela semble hautement subjectif (il existe d'autres processus fonctionnant sur un ordinateur en plus de cela). Sonne comme quelque chose qui devrait être fait au niveau du matériel; Sinon, d'autres threads / processus / OS-Stuff seront dans la voie


Autant que je sache, si je définis un grand tableau en C, lorsque j'accumule un élément de cette matrice, les données autour de cet élément semblent être stockées dans le cache. Donc, si j'accède à la matrice du début à la fin, il sera plus rapide que l'accès aléatoire (accès à chaque élément une fois) - c'est vrai, mais je ne sais pas que c'est le résultat en mettant en cache ou autre chose.


Prendre une supposition sauvage, peut-être que cet exercice / projet provient d'un très ancien livre où ce type de test était possible en raison d'un matériel ou d'une mise en cache mal optimisé?


@Millimoose: ils ne sont pas sous un contrôle direct, mais il est toujours possible d'utiliser certaines heuristiques. Par exemple, on peut écrire un programme pour provoquer un cache Miss, puis comparer la vitesse d'accès à la mémoire à une seule sans cache Miss. Encore une fois, il existe plusieurs niveaux de cache, etc., ce n'est donc pas une tâche triviale.


Peut-être devriez-vous simplement faire confiance que vous pouvez récupérer un élément du cache réel, véritable rapide ...


Ma meilleure hypothèse serait d'allouer un vaste éventail de plusieurs blocs de mémoire sur la taille du tas (> Taille de cache), puis lisez dans chaque "page" pour vos tests. Cela tirerait la page (


@Sayakiss qui suppose toujours que rien ne optimise cela sous le capot en précisant ou autre chose. (N'oubliez pas que vous voulez probablement plus d'échantillons de hits et de rats, et cela pourrait être suffisamment d'informations pour un peuple suffisamment intelligent.) Honnêtement, je ne sais pas Qu'est-ce que pourrait arriver, les processeurs modernes et les compilateurs sont juste insensés complexe et il semble que cela prendrait une connaissance très étendue pour commencer à le faire correctement.


En outre, rappelez-vous que la prise du temps du système changera probablement probablement le contenu du cache. Donc, cela vous laisse également avec l'hypothèse que rien ne provoque la page que vous pensiez être mis en cache.


Un benchmarking Google pour cache produira un hits de gazillion, y compris des programmes de benchmarking de cache bien respectés.


@HighperformCemark Merci pour le mot clé Nice!


3 Réponses :


5
votes

Vous devez trouver une heuristique qui obligea une cache de cache 100% (ou très proche) (espérons-le que vous avez un code OP d'invalidation de cache?) Et 100% de cache frappé. Hourra, cela fonctionne pour 1 niveau de cache. Maintenant, comment faire la même chose pour les niveaux 2 et 3?

En toute gravité, il n'y a probablement pas un moyen de le faire 100% de manière fiable sans matériel spécial et traces connectées à la CPU et à la mémoire, mais voici ce que je ferais:

Écrivez un "bouquet" de trucs à 1 emplacement en mémoire - Assez que vous pouvez être sûr que cela frappe le cache L1 constamment et enregistrez l'heure (qui affecte votre cache, donc méfiez-vous). Vous devriez faire cet ensemble d'écritures sans branches pour essayer de vous débarrasser des incohérences de prédiction des succursales. C'est le meilleur temps. Maintenant, de tous ces temps, écrivez une ligne de cache de données de la ligne de cache à un emplacement au hasard au hasard en RAM à la fin de votre emplacement connu à droite et enregistrez la nouvelle fois. Espérons que cela prend plus de temps. Continuez à faire cela en enregistrant les différents moments et espérons que vous verrez quelques timings qui ont tendance à se regrouper. Chacun de ces groupes "pourrait" montrer des timings pour les horaires d'accès à L2, L3 et à la mémoire. Le problème est qu'il y a tellement d'autres choses qui entrent dans la voie. Le système d'exploitation pourrait vous contacter et bousillez votre cache. Une interruption pourrait venir et traverser votre timing. Il y aura beaucoup de choses qui pourraient lancer les valeurs. Mais, espérons-le, vous obtenez suffisamment de signal dans vos données pour voir si cela fonctionne.

Ce serait probablement plus facile à faire sur un système de type plus simple et intégré dans lequel le système d'exploitation (le cas échéant) ne se mettra pas dans votre chemin.


3 commentaires

Mais comment mesurer le calendrier de lire une donnée une fois? C'est tellement court et peut être juste quelques ns!


En le faisant assez de fois. Vous devriez être capable de compter sur le royaume milliseconde. Néanmoins, je n'ai pas dit que ce serait facile :)


Mais après l'avoir fait une fois, il peut être chargé dans le cache (supposer ce qui n'est pas auparavant).



2
votes

Jetez un coup d'œil à Cachegrind-Valgrind :

Cachegrind simule la manière dont votre programme interagit avec le cache d'une machine hiérarchie et prédicteur de la branche (éventuellement). Il simule une machine avec des instructions et des caches de données indépendantes de premier niveau (I1 et D1), soutenu par un cache de second niveau unifié (L2). Cela correspond exactement à la Configuration de nombreuses machines modernes.

Voir Tese Belles questions, elles sont en quelque sorte liées:

  1. Comment est-ce que je désactive programmatiquement la préfettration du matériel?
  2. Comment détecteriez-vous génériquement Ligne de cache associativité du code de mode utilisateur?
  3. Comment invalider le cache lors de l'analyse comparative?

1 commentaires

Ah, l'émulation peut être une meilleure option si sa qualité d'émulation est suffisamment bonne. Bonne idée.



3
votes

Cela nécessite généralement une certaine connaissance de la "géométrie" du cache et d'autres aspects de celui-ci. Il est également utile d'avoir un certain contrôle du système au-delà d'un accès simple utilisateur à celui-ci et des éléments dépendants de la mise en œuvre, tels que la minuterie plus fin que pourraient être fournis via le mécanisme Standard C Clock .

Voici une approche initiale:

  • Écrivez une routine qui prend un pointeur à la mémoire, une longueur et un certain nombre de répétitions et lit toute cette mémoire dans une commande consécutive, à plusieurs reprises.
  • Écrivez une routine qui prend un pointeur à la mémoire, une longueur et un certain nombre de répétitions et écrit à la totalité de cette mémoire dans une commande consécutive, à plusieurs reprises.
  • Les routines ci-dessus peuvent devoir convertir leurs pointeurs en volatile pour empêcher le compilateur d'optimiser les accès à l'extérieur qui n'ont aucun effet.
  • allouer une grande quantité de mémoire.
  • Appelez chacune des routines ci-dessus, obtenant l'heure actuelle avant et après chaque appel et appelez avec une variété de longueurs pour voir les temps pour différentes longueurs.

    Lorsque vous faites cela, vous verrez généralement des vitesses rapides (nombre d'octets en lecture / écriture par seconde) pour de petites longueurs et des vitesses plus lentes pour des longueurs plus longues. La baisse de la vitesse se produira lorsque les tailles des différents niveaux de cache sont dépassées. Donc, vous êtes assez susceptible de voir la taille du cache L1 et L2 reflété dans les données collectées à l'aide de la technique ci-dessus.

    Voici quelques raisons que l'approche est inadéquate:

    • Il ne contrôle pas les instructions utilisées pour lire ou écrire le cache. Le compilateur C peut générer des instructions de Word et de magasin de chargement, mais de nombreux processeurs modernes ont des instructions pouvant charger et stocker 16 octets à la fois, la lecture et l'écriture peuvent être plus rapides avec ces instructions qu'avec les instructions de mot de quatre octets.
    • Cache se comportera différemment lorsque vous accédez à séquentiellement que si vous y accédez au hasard. La plupart des caches ont une tentative de suivre lorsque des données sont utilisées, de sorte que les données récemment utilisées sont conservées dans le cache, tandis que d'autres données sont distribuées. Les parties d'accès des programmes réels diffèrent généralement des opérations consécutives décrites ci-dessus.
    • En particulier, les écrites consécutives à la mémoire peuvent être capables de remplir une ligne de cache entière, de sorte que rien ne doit être lu depuis la mémoire, alors qu'un modèle d'utilisation du monde réel qui écrit qu'un seul mot à un emplacement particulier peut avoir à être mis en œuvre en lisant la ligne de cache de la mémoire et la fusion dans les octets modifiés.
    • La concurrence d'autres processus de votre système interférera avec ce qui est en cache et avec la mesure.

0 commentaires