7
votes

Est-il possible de verrouiller certaines données dans le cache CPU?

J'ai un problème .... J'écris des données dans la matrice dans la boucle tandis que. Et le point est que je le fais vraiment souvent. Il semble que cette écriture est maintenant une bouteille dans le code. Donc, comme je présume que c'est causé par l'écriture à la mémoire. Ce tableau n'est pas vraiment grand (smth comme 300 éléments). La question est qu'il est possible de le faire de cette façon: pour le stocker dans le cache et la mise à jour de la mémoire qu'après la fin de la boucle tandis que la boucle est terminée?

[Modifier - Copié d'une réponse ajoutée par Alex] P>

double* array1  = new double[1000000]; // this array has elements  
unsigned long* array2  = unsigned long[300];
double varX,t,sum=0;
int iter=0,i=0;
while(i<=max_steps)
{
   varX+=difX;
   nm0 =  int(varX);
   if(nm1!=nm0)
   {
        array2[iter] = nm0;  // if you comment this string application works more then 2 times faster :)
        nm1=nm0;
        t = array1[nm0]; // if you comment this string , there is almost no change in time 
        ++iter;
   }
   sum+=t;
   ++i;
}


2 commentaires

"Si vous commencez cette chaîne [...]" Eh bien, la demande exécutée deux fois plus rapidement peut également être causée par le compilateur optimisant le bloc de condition (selon le compilateur et le code qui suit) car il ne fait rien de significatif. plus.


9 ans après cette question, il apparaît que cela sera bientôt possible, au moins sur certains CPU d'Intel exécutant Linux Kernel 4.19: kernelnewbies.org/linux_4.19#intel_cache_pseudo-locking . Plus d'informations sur événements.Linuxfoundation.org/wp-content/uploads/2017/11/...


12 Réponses :


2
votes

Je doute que cela soit possible, au moins sur un système d'exploitation multitâche de haut niveau. Vous ne pouvez pas garantir que votre processus ne sera pas préempté et perdez la CPU. Si votre processus possède alors le cache, d'autres processus ne peuvent pas l'utiliser, ce qui rendrait leur exeucution très lente et compliquerait beaucoup les choses. Vous ne voulez vraiment pas courir un processeur de plusieurs ghz moderne sans cache, juste parce qu'une application a enfermé tous les autres.


0 commentaires

12
votes

Non intentionnellement, non. Entre autres choses, vous n'avez aucune idée de la taille du cache, vous n'avez donc aucune idée de ce qui va s'adapter. En outre, si l'application était autorisée à verrouiller une partie du cache, les effets sur le système d'exploitation pourraient être dévastateurs de la performance globale du système. Cela tombe carrément sur ma liste de "Vous ne pouvez pas le faire parce que tu ne devrais pas le faire. Jamais."

Ce que vous pouvez faire est d'améliorer votre localité de référence - essayez d'organiser la boucle de telle sorte que vous n'accumulez pas les éléments plus d'une fois et essayez d'y accéder dans la mémoire.

Sans plus d'indices sur votre application, je ne pense pas que des conseils plus spécifiques puissent être donnés.


1 commentaires

Ce n'est pas strictement correct. Évidemment, les détails seront spécifiques à une architecture (rendant ainsi «C ++» entièrement la mauvaise étiquette de cette question), mais les processeurs modernes offrent certainement un certain contrôle sur ce qui est stocké dans le cache et la mémoire principale. ARM9 Les CPU ont en effet une API "verrouillée" réelle qui correspond à ce que le questionneur semble demander. Les boîtes Intel sont plus limitées, où vous émettez une instruction pour préciser une ligne avant d'en avoir besoin et utilisez une instruction MFence pour contrôler l'ordre dans lequel les lignes de cache sale sont écrites.



3
votes

Sauf si votre code ne fait quelque chose de complètement différent entre l'écriture à la matrice, la majeure partie du tableau restera probablement dans le cache.

Malheureusement, il n'y a pas de quoi que vous puissiez faire pour affecter ce qui se trouve dans la cache, à part la réécriture de votre algorithme avec la cache à l'esprit. Essayez d'utiliser aussi peu de mémoire que possible entre écrire dans la mémoire: N'utilisez pas de variables de lot, n'appelez pas de nombreuses autres fonctions et essayez d'écrire dans la même région du tableau consécutif.


0 commentaires

1
votes

même si vous le pouviez, c'est une mauvaise idée.

Les ordinateurs de bureau modernes utilisent des processeurs multiples. Les puces d'Intel sont les copeaux les plus courantes dans les machines de bureau ... mais les processeurs Core et Core 2 ne partagent pas de cache sur matrice.

C'est-à-dire que cela n'a pas partagé de cache avant que les jetons Core 2 I7 ont été libérés, ce qui partage un cache de 8 Mo de 8 Mo de 8 Mo.

Donc, si vous pouviez verrouiller des données dans le cache de l'ordinateur, je sais que cela à partir de ce processus, vous ne pouvez même pas garantir que ce processus sera programmé sur le même noyau, de sorte que le verrouillage de cache soit totalement inutile.


0 commentaires

1
votes

Si vos écritures sont lentes, assurez-vous qu'aucun autre noyau de la CPU ne écrit dans la même zone de mémoire en même temps.


0 commentaires

1
votes

Il serait peut-être possible d'utiliser un code de montage, ou comme onebyone pointé, d'assemblage intrinsèque, de préférer des lignes de mémoire dans le cache, mais cela coûterait beaucoup de temps pour bricoler avec elle.

Juste pour l'essai, essayez de lire toutes les données (de manière à ce que le compilateur ne soit pas optimiser), puis faire l'écriture. Voir si cela aide.


2 commentaires

Vous n'avez pas nécessairement d'utiliser l'assemblage. Par exemple, GCC a __ intégré_prefetch pour donner des alloneurs de cache.


@onebyone bon point, mais cela se résume toujours à l'instruction Prefetch



8
votes

La CPU n'offre généralement pas de contrôle de cache à grain fin, vous n'êtes pas autorisé à choisir ce qui est expulsé ou d'épingler les choses dans le cache. Vous avez quelques opérations de cache sur certains processeurs. Tout comme un peu d'informations sur ce que vous pouvez faire: Voici quelques instructions intéressantes sur le cache sur les cpus plus récents x86 {-64} (faire des choses comme ça fait de la portabilité de l'enfer, mais je pensais que vous pourriez être curieux)

Données logicielles Préfectuh

L'instruction non temporelle est Prefetchnta, qui récupère les données dans le cache de deuxième niveau, minimiser la pollution cache. P>

Les instructions temporelles sont aussi suit: p>

* prefetcht1 – Identical to prefetcht0

* prefetcht2 – Identical to prefetcht0


0 commentaires

1
votes

Lorsque vous avez un problème de performance, ne présumez rien, mesurez-la en premier. Par exemple, commencez les écritures et voyez si la performance est différente.

Si vous écrivez à une gamme de structures, utilisez un pointeur de structure pour mettre en cache l'adresse de la structure afin que vous ne effectuez pas la matrice multiplie chaque fois que vous effectuez un accès. Assurez-vous d'utiliser la longueur de mot native pour la variable d'indexateur de matrice pour une optimisation maximale.


0 commentaires

1
votes

Comme d'autres personnes ont dit, vous ne pouvez pas contrôler cela directement cela, mais la modification de votre code peut permettre indirectement une meilleure mise en cache. Si vous exécutez sur Linux et que vous souhaitez obtenir plus d'informations sur ce qui se passe avec le cache de la CPU lorsque votre programme est exécuté, vous pouvez utiliser l'outil Cachegrind, une partie de la Valgrind Suite. C'est une simulation d'un processeur, donc ce n'est pas totalement réaliste, mais cela vous donne des informations difficiles à obtenir une autre manière.


0 commentaires

4
votes

J'ai un problème ... J'écris des données dans la matrice dans la boucle tandis que. Et le point est que je le fais vraiment souvent. Il semble que cette écriture est maintenant une bouteille dans le code. Donc, comme je présume que c'est causé par l'écriture à la mémoire. Ce tableau n'est pas vraiment grand (smth comme 300 éléments). La question est qu'il est possible de le faire de cette façon: pour le stocker dans le cache et la mise à jour de la mémoire qu'après que la boucle tandis que la boucle est terminée?

Vous n'avez pas besoin de. La seule raison pour laquelle il pourrait être poussé hors le cache est si d'autres données sont jugées plus urgentes à mettre dans le cache.

En dehors de cela, un tableau de 300 éléments doit s'intégrer dans le cache sans problème (en supposant que la taille de l'élément n'est pas trop folle), très probablement, vos données sont déjà en cach.

Dans tous les cas, la solution la plus efficace est probablement pour modifier votre code. Utilisez beaucoup de temporaires (pour indiquer au compilateur que l'adresse de la mémoire n'est pas importante), plutôt que d'écrire / lire dans le tableau constamment. Réorganisez votre code afin que les charges sont effectuées une fois, au début de la boucle et rompent autant que possible les chaînes de dépendance.

déroulant manuellement la boucle vous donne plus de flexibilité pour atteindre ces choses.

Et enfin, deux outils évidents que vous devriez utiliser plutôt que de deviner sur le comportement du cache:

  • Un profileur et une cachegrind si disponible. Un bon profileur peut vous dire beaucoup de statistiques sur les missions de cache et la cachegrind vous donner beaucoup d'informations aussi.
  • nous ici à Stackoverflow. Si vous publiez votre code de boucle et demandez comment sa performance peut être améliorée, je suis sûr que beaucoup d'entre nous le trouveront un défi amusant.

    Mais comme d'autres personnes ont mentionné, lorsque vous travaillez avec performance, ne devinez pas. Vous avez besoin de données et de mesures difficiles, pas de hésions et de sentiments intestinaux.


0 commentaires

2
votes

Dans ce cas, Array2 sera assez "chaud" et restera dans le cache pour cette raison seule. L'astuce consiste à garder array1 hors du cache (!). Vous ne le lisez qu'une seule fois, il n'ya donc aucun point de la mettre en cache. L'instruction SSE pour celui-ci est MOVNTPD , intrinsèque void_mm_stream_pd (double * destination, source __m128i)


0 commentaires

1
votes

Dans les premières phases de démarrage de Coreboot (anciennement Linuxbios), car ils n'ont pas encore accès à la RAM (nous parlons du code du BIOS, et le RAM n'a donc pas encore été initialisé), ils ont mis en place quelque chose qu'ils appellent le cache-comme -Ram (voiture), c'est-à-dire qu'ils utilisent le cache de processeur comme RAM, même s'il n'est pas soutenu par la RAM réelle.


0 commentaires