J'essaie d'optimiser une application MPI avec un modèle de communication hautement asynchrone. Chaque rang a une liste de choses à calculer et envoie des messages si nécessaire si les entrées ou les sorties résident sur un rang différent. De plus, chaque rang est fileté (actuellement avec un fil de communication et 5 travailleurs).
J'ai instrumenté le code avec des minuteries autour des différentes parties critiques du code de performance, ce qui me donne une liste de triplets (début, fin, type) pour chaque thread. Tracé de manière évidente, avec le temps comme axe horizontal, le rang et le fil comme la verticale, et la couleur indiquant ce que fait actuellement chaque fil, j'obtiens une image comme celle-ci pour 16 rangs avec 6 fils / rang:
Ma question est: quelles sont les autres façons de visualiser ces données qui pourraient aider à identifier les problèmes de performances? Quelqu'un a-t-il un type de tracé préféré qu'il utilise lors du profilage des applications asynchrones?
Cet ensemble de données est limité en ce qu'il ne connaît pas la structure du flux de données, mais j'aimerais en tirer le maximum d'informations avant d'essayer de collecter quelque chose de plus compliqué.
L'image non compressée est là au cas où quelqu'un voudrait regarder autour (elle n'a pas pu être téléchargée via la route normale). Malheureusement, Firefox ne l'accepte pas même si je pense qu'il est valide, peut-être parce qu'il est tout simplement trop grand.
la source
Réponses:
Je passe beaucoup de temps à écrire et à déboguer du code parallèle, à la fois avec de la mémoire partagée et / ou distribuée, mais sans connaître votre problème spécifique, je ne peux que vous dire ce qui fonctionne le mieux pour moi.
Savoir quelles routines prennent combien de temps est une chose importante si vous regardez l'efficacité du calcul, mais si vous vous inquiétez de l'efficacité parallèle, alors vous devriez être plus inquiet de ce que fait votre code quand il ne fait aucun calcul. Un peu comme s'inquiéter de ce que font les enfants quand c'est trop calme ...
Puisque vous utilisez une approche de mémoire partagée / distribuée hybride, je suppose que votre code attend, dans les blancs, soit un appel MPI, soit une variable mutex / condition. Vous pouvez également encapsuler ces appels dans des minuteries, ce qui vous donnera une meilleure image de ce qui vous ralentit, par exemple si c'est toujours le même conditionnel ou toujours le même sur
MPI_REDUCE
lequel vos threads sont bloqués.L'un des logiciels que j'utilise assez souvent est le Intel Vtune Amplifier XE . Il a une fonctionnalité / option de traçage agréable qui visualise la simultanéité des threads. Le programme dessinera un tracé très similaire au vôtre, mais lorsqu'un thread attend sur un mutex ou une variable de condition, il trace une ligne diagonale du thread en attente, au moment où il a commencé à attendre, vers le thread qui a effectivement libéré le mutex ou signalé l'état qu'il attendait, au moment où il a été libéré / signalé. Cela peut être assez compliqué, mais cela fait immédiatement apparaître des goulots d'étranglement.
Enfin, je collecte également des statistiques en masse, par exemple pour chaque appel mutex / signal / MPI, quels étaient les temps d'attente moyen et maximum? Quel est l'histogramme des temps d'attente collectés? Bien que l'intrigue vous donne un bon aperçu, il peut devenir assez compliqué quand il s'agit des détails les plus fins.
Enfin, une question à ne pas sous-estimer: comment recueillez-vous vos horaires? Votre temporisateur est-il suffisamment non intrusif pour ne pas influencer votre code? J'utilise le nombre d'instructions CPU autant que possible, c'est-
RDTSC
à- dire sur les architectures x86. Cela ajoute généralement une seule instruction à votre code.la source
constant_tsc
indicateur défini (vérifier/proc/cpuinfo
) et si vous utilisez verrouiller chaque thread sur un noyau spécifique, c'est-à-dire que chaque thread lit toujours le même registre à partir du même noyau, par exemple en utilisantpthread_setaffinity_np
. Notez que ce dernier est spécifique à Linux et donc pas portable.MPI_Waitsome
, vous pouvez toujours enregistrer les demandes qui sont réellement arrivées et d'où. Ces informations peuvent ou non être utiles ...Parfois, vous pouvez obtenir une vue alternative sur les problèmes de performances via une analyse de ressources de haut niveau: existe-t-il un goulot d'étranglement pertinent tel que la bande passante mémoire? Chaque thread de travail fait-il la même quantité de travail? Ces données peuvent être facilement collectées avec likwid-perfctr à partir de la suite d'outils LIKWID LIKWID projet de code Google . Si le profil est tel qu'il existe de nombreux points chauds différents, vous devrez peut-être les résoudre un par un. Il peut également y avoir différents problèmes, selon le nombre de threads / processus utilisés.
la source
Lorsque j'ai un problème dans un réseau de processus hautement asynchrones régis par des messages ou des événements, j'utilise une méthode qui n'est pas simple mais efficace. Cela impliquait d'obtenir des journaux horodatés des processus, de les fusionner dans une chronologie commune et de suivre la progression de certains messages lorsqu'ils déclenchent des activités, déclenchant d'autres messages. Ce que je recherche, c'est un délai entre le moment où un message est reçu et le moment où il est appliqué, et comprendre la raison du retard. Lorsqu'un problème est détecté, il est résolu et le processus est répété. De cette façon, vous pouvez obtenir des performances vraiment satisfaisantes.
Il est important de voir en quoi cela diffère des approches où vous mesurez, mesurez, mesurez. La seule chose que mesurer peut vous dire est de savoir où ne pas regarder. Le réglage des performances réelles nécessite une attention particulière aux détails, dans une perspective temporelle. Ce que vous cherchez, ce n'est pas où le temps est passé, mais où il est dépensé inutilement.
Bonne chance.
la source