Crunchez vos adresses URL
|
Rejoignez notre discord
|
Hébergez vos photos
Affichage des résultats 1 à 6 sur 6
  1. #1
    Bonjour,

    Je me demandais un peu comment fonctionnaient les caches CPU, et comment le CPU pouvait déterminer si le cache doit être mis à jour ou non. Notamment je me pose la question lorsque du matos va écrire en RAM, via du DMA et que le CPU accède à la même portion de mémoire.

    Je comprends sans problème que les caches CPU ne sont pas tout le temps à jour par rapport à la mémoire, ou même entre deux caches non partagés de deux cores. Je vois aussi bien comment il est possible, via des instructions de demander explicitement un flush des caches pour les synchroniser avec la mémoire. Je ne suis pas certain ceci dit de la signification et de l'opération exacte faite par chaque instruction, donc peut être que quelqu'un pourrait m'expliquer plus clairement les opérations de chacune.

    En gros, de ce que je connais, on peut utiliser mfence, sfence, lfence ou clflush pour synchroniser les cores et contrôler le cache. Mais plus précisément, qu'est-ce que fait chacune ? sfence et lfence n'ont pas d'impact sur le cache, il s'agit juste de points de synchro pour les instructions executées sur un même core, non ?

    Autre question, comment un core va-t-il décider ou non de rafraichir son cache ? Si l'on a appelé clflush, la ligne de cache va être explicitement marquée comme à rafraichir, et au prochain accès à cette ligne, un accès mémoire aura lieu, c'est ça ? Si l'on ne fait pas clflush, à quel moment le CPU va-t-il décider de faire tout de même cet accès mémoire ?

    Si une carte utilisant du DMA pour fournir des données écrit directement en mémoire, est-il nécessaire d'executer des clflush pour que les CPU voient les modifications en mémoire plus rapidement ? Ne perd-t-on pas du temps CPU à faire des accès mémoire même s'il n'y en a pas besoin (si la carte n'a pas modifié la mémoire, le clflush s'avère inutile) ? Si aucun clflush n'est executé, quand le CPU va-t-il se rendre compte que la mémoire a été modifiée par la carte ?

    Je suppose que c'est lié au fonctionnement du contrôleur mémoire et de son intégration ou non au CPU ? Une idée de lecture possible sur le sujet ou de ou je pourrais trouver plus d'infos là dessus ?

    PS : Je suis un peu noob sur le sujet, donc soyez indulgents si je raconte de la merde
    "Dieu est mort" · "Si le téléchargement c’est du vol, Linux c’est de la prostitution."

  2. #2
    Je ne suis pas un spécialiste du x86 mais puisque sfence et ses potes font partie de l'ISA je vais supposer que tu parles des caches sur le PC de monsieur tout le monde.

    Citation Envoyé par rOut Voir le message
    Je comprends sans problème que les caches CPU ne sont pas tout le temps à jour par rapport à la mémoire, ou même entre deux caches non partagés de deux cores.
    En général, les caches non partagés d'une même puce son cohérents (Et sur les systèmes multisockets aussi). C'est le matériel qui s'occupe d'assurer la cohérence via les protocoles qui vont bien. Cela évite notamment d'avoir deux versions différentes d'une même ligne au même instant. L'unicité de version vient du fait qu'une ligne ne peut être écrite par un coeur que si il est le seul à posséder la ligne (En gros, si il veut écrire dessus, il signale à tout les autres coeurs d'invalider la ligne dans leur caches respectifs). A cela s'ajoute le snooping, qui fait que chaque coeur voit les requêtes mémoires de tous les autres et fournit la ligne si il la possède et qu'elle est valide (sachant que si elle est valide, c'est la version la plus récente).

    Pour plus d'infos, jette un oeil ici. Oui, c'est wikipédia, mais si tu veux quelque chose qui illustre bien le principe, ce n'est pas si mal.

    Si l'on ne fait pas clflush, à quel moment le CPU va-t-il décider de faire tout de même cet accès mémoire ?
    Quand un évènement extérieur aura invalidé la ligne (Une invalidation venue d'un autre coeur, par exemple). Sachant que les caches sont cohérents, tu es sur que ta ligne reste valide tant que tu n'as pas reçu d'invalidation venant d'un autre coeur (ou d'ailleurs pour le DMA). Si au contraire tu fais clfush ça accèdera à la mémoire au prochain load/store qui tape dans la ligne, oui.

    Si une carte utilisant du DMA pour fournir des données écrit directement en mémoire, est-il nécessaire d'éxecuter des clflush pour que les CPU voient les modifications en mémoire plus rapidement ?
    Ça dépend, le contrôleur de cache peut le gérer comme un grand dès lors qu'il a l'information qu'une écriture/lecture a été faite par la carte, mais ça peut aussi être géré à la main par l'OS. Sur x86 je ne sais pas comment c'est fait mais c'est un des deux (de rien).

    Si j'ai répondu à côté, n'hésite pas (de toute façon quelqu'un passera bien pour me corriger).

    EDIT : mfence, lfence, sfence, clflush
    Dernière modification par Thamior ; 17/11/2011 à 20h41.

  3. #3
    Ok merci,

    Je pense que je vais avoir besoin d'un expert X86, parce que je lis des choses assez contradictoires sur le sujet. D'un coté, je comprends qu'il existe des protocoles de cohérence de cache et des mécanismes de communication inter-caches pour fournir aux autres coeurs des valeurs modifiées par un coeur, et d'un autre coté, je lis que l'on peut parfois obtenir r2 == 0 et r4 == 0 à la fin de l'exemple suivant:

    Code:
    x = 0, y = 0
    
    Processor 0   Processor 1
    mov [_x], 1   mov [_y], 1
    mov r1, [_x]  mov r3, [_y]
    mov r2, [_y]  mov r4, [_x]
    Hors, autant j'ai plus ou moins compris que le CPU avait le droit de faire des load/store dans le sens qu'il a envie tant que ça touche des endroits différents, autant là ça me contrarie (d'autant plus qu'en ajoutant un load sur la même addresse, après le store initial, on oblige le CPU à executer le tout dans l'ordre):

    Supposons que r2 == 0 à la fin, ça signifie que du point de vue de proc 0, le proc 1 n'a encore rien executé. Quand il va executer son store/load y, puis load x, le load x devrait être intercepté par le mécanisme de snoop du protocole MESI et proc 0 devrait fournir la valeur modifiée de x, donc r4 == 1, non ?

    ---------- Post added at 00h24 ---------- Previous post was at 23h47 ----------

    Je viens de découvrir l'existence des write buffers en lisant la doc AMD64, je pense que c'est ça qui pose problème dans l'exemple que je citais.

    Les opérations en write buffer ne sont pas reflétés dans le cache tant que le buffer n'est pas flushé, mais un load va vérifier dans le write buffer local si une valeur sera été modifiée () plus tard avant de vérifier dans le cache (c'est là que le bât blesse, on ne vérifie que le write buffer du CPU ou est executé le load?). Si tout se passe dans le write buffer, le cache ne voit rien et le résultat est bien r2 == 0 et r4 == 0. C'est un peu retour vers le futur...
    "Dieu est mort" · "Si le téléchargement c’est du vol, Linux c’est de la prostitution."

  4. #4
    x = 0, y = 0

    Processor 0 Processor 1
    mov [_x], 1 mov [_y], 1
    mov r2, [_y] mov r4, [_x]
    mov r1, [_x] mov r3, [_y]
    Ce cas-là peut rendre r2 = r4 = 0 si tu as bien deux cores, puisque les loads peuvent passer devant les stores si l'adresse est différente.
    J'imagine que tu as déjà lu ceci?

    Mais ton exemple est valide aussi, comme l'indique le whitepaper Intel (Vol 3. Section 8.2.3.5).
    En effet, même si en théorie le thread 0 recharge _x juste après l'avoir écrit force l'ordre (dans le thread 0), et que dans le core 0, on a bien r1 = 1 avant d'éxécuter le load de _y, tu peux quand même obtenir r4 = 0. Cela vient du fait que la store queue n'est pas visible par le protocole de cohérence. Comme le load _x du core 0 est servie par la store queue (ou la nouvelle valeur de _x est en attente d'être écrite dans le cache), on a bien r1 = 1 avant la dernière instruction du thread 0, mais du point de vue du thread 2, le thread 0 n'a pas encore fait son store sur _x.

    Hope it helps. Ah et quand je parlais de MESI, c'était un exemple, je ne sais pas exactement à quelle sauce sont cuisinés les caches chez Intel et AMD.

  5. #5
    Ouaip, j'ai pigé maintenant. Je pensais que le cache était mis à jour directement, et que du coup le protocole de cohérence empêchait le résultat r2 == 0 et r4 == 0.

    Mais comme je le disais, j'ai appris il y a quelques minutes l'existence des store queues, et que les loads allaient chercher dedans les valeurs avant même leur sortie dans le cache (bien entendu, un load ne va chercher que dans la store queue du CPU ou il est exécuté, sinon ça ne poserait pas de problème). Et c'est avant même qu'il n'y ait quoi que ce soit dans le cache, donc le protocole de cohérence ne s'applique même pas.
    "Dieu est mort" · "Si le téléchargement c’est du vol, Linux c’est de la prostitution."

  6. #6
    Citation Envoyé par rOut Voir le message
    Et c'est avant même qu'il n'y ait quoi que ce soit dans le cache, donc le protocole de cohérence ne s'applique même pas.
    Oui. Les puristes distinguent la cohérence de la consistence (consistency). En gros la cohérence définit la façon dont les écritures sont propagées d'un processeur à l'autre. La consistence s'occupe de l'ordre dans lequel les lectures et écriture ont lieu du point de vue d'un processeur.

    La référence est le chapitre "Thread-level parallelism" du Hennessy-Patterson.

    Le problème n'est pas tellement la présence de mécanismes genre caches et store queue. Les modèles de cohérence / consistence des processeurs sont (plus ou moins) bien définis dans l'architecture indépendamment des détails micro-architecturaux. La définition est juste dure à trouver, compliquée et pas intuitive du tout.

    En théorie tu peux toujours te débrouiller pour assurer un modèle de cohérence/consistence forte même avec des buffers et caches, ne serait-ce qu'en spéculant puis en revenant en arrière si tu te plantes. Les difficultés sont que ça doit rester raisonnablement efficace en pratique, et être raisonnablement possible à implémenter et à vérifier...

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •