0

Actuellement, je fais une comparaison des performances sur deux microcontrôleurs 32 bits. J'ai utilisé le benchmark Dhrystone pour fonctionner sur les deux microcontrôleurs. Un microcontrôleur possède 4 Ko de cache I tandis que le second co-contrôleur possède 8 Ko de cache I. Les deux microcontrôleurs utilisent la même chaîne d'outils. Autant que possible, j'ai gardé les mêmes paramètres statiques et d'exécution sur les deux microcontrôleurs. Mais le microcontrôleur avec un cache de 4 Ko est plus rapide qu'un microcontrôleur de cache de 8 Ko. Les deux microcontrôleurs sont du même fournisseur et basés sur le même CPU.Point de référence Drhystone sur microcontrôleur 32 bits

Quelqu'un peut-il fournir des informations sur la raison pour laquelle le microcontrôleur avec 4 Ko de cache est plus rapide que les autres?

Répondre

0

Les repères sont en général inutiles. dhrystone étant l'un des plus anciens et il peut avoir eu un peu de valeur à l'époque, avant les pipelines et trop d'optimisation du compilateur. Je pense que j'ai renoncé à dhrystone il y a 15 ans à peu près au moment où j'ai commencé à l'utiliser.

Il est trivial de démontrer que ce code

.globl ASMDELAY 
ASMDELAY: 
    sub r0,r0,#1 
    bne ASMDELAY 
    bx lr 

Ce qui est principalement deux instructions, peut varier considérablement dans le temps d'exécution sur la même puce si vous comprenez comment fonctionnent les processeurs modernes. L'astuce simple pour voir ceci est d'éteindre les caches et prefetchers et autres, et de placer ce code à offset 0x0000, appelez-le avec une certaine valeur. placez-le à 0x0004 répétez, puis à 0x0008, répétez. continue à faire ça. Vous pouvez mettre un, deux, etc nops entre la soustraction et la branche. Essayez-le à divers décalages. PUIS, allumez et des caches pour chacun de ces alignements, si vous avez une préextraction à l'extérieur du processeur pour le flash, allumez-le et éteignez-le. PUIS, faites varier vos horloges, en particulier pour les MCU où vous devez ajuster les états d'attente en fonction de la fréquence d'horloge.

Sur un MCU SIMPLE, vous verrez que ces deux instructions ont une très grande variation en termes de temps d'exécution. Disons juste 20 fois plus longtemps dans certains cas que d'autres.

Prenez maintenant un petit programme ou une petite fraction du programme dhrystone. Compilez cela pour votre UCM, combien d'instructions voyez-vous? Effectuez des optimisations mineures à majeures et d'autres variations sur la ligne de commande de compilation, à quel point le code change. Si deux instructions peuvent varier, appelons-le 20 fois en temps d'exécution, à quel point peut-il obtenir 200 instructions ou 2000 instructions? Cela peut être plutôt mauvais.

Si vous prenez les programmes dhrystone que vous avez en ce moment avec les options du compilateur que vous avez en ce moment, allez dans votre bootstrap, ajoutez un nop (entraînant le décalage complet du binaire par une instruction flash). Ajoutez deux, trois, quatre. Vous n'êtes toujours pas en train de comparer des mcus différents en train d'exécuter votre benchmark sur un seul système.

Exécuter avec et sans cache, avec et sans cache si vous en possédez. allumer et éteindre le prefetch flash si vous en avez un et si vous avez un tampon d'écriture, vous pouvez allumer et d'essayer cela. Reste toujours sur le même compilateur même options mêmes mcu. Prenez les différentes fonctions dans le code source de dhrystone et réorganisez-les dans le code source. au lieu de Proc_1, Proc_2, Proc_3 faites-en Proc_1, Proc_3, Proc_2. Faites tout ce qui précède à nouveau. Réarranger à nouveau, répétez.

Avant de quitter ce mcu, vous devriez maintenant voir que le temps d'exécution du même code source qui est complètement non modifié (autre que peut-être réorganiser les fonctions) peut et aura des temps d'exécution très différents.Si vous commencez alors à changer les options du compilateur ou à conserver la même source et à changer de compilateur, vous verrez une différence de temps d'exécution encore plus grande.

Comment est-il possible que les benchmarks dhrystone aujourd'hui ou de retour aient un résultat unique pour chaque plate-forme? Simple, ce résultat était l'un d'un large éventail, ne représentant pas vraiment la plate-forme. Donc, si vous essayez de comparer deux plates-formes matérielles différentes, c'est le même noyau de bras dans un autre mcu du même fournisseur ou de différents fournisseurs. le noyau du bras, supposant (ce qui n'est pas une hypothèse sûre) c'est la même source avec les mêmes options de compilation/construction, même en supposant que la même compilation et synthèse de verilog a été utilisée. vous pouvez avoir ce même changement de base basé sur les options fournies par le bras. Quoi qu'il en soit, comment le vendeur sera-t-il le même fournisseur dans deux cas ou deux fournisseurs différents enveloppent ce même noyau, vous verrez des variations. Ensuite, prenez un noyau complètement différent que ce soit un autre bras ou un mips, etc. Comment pourriez-vous gagner de la valeur en comparant ceux qui utilisent un programme comme celui-ci qui varie lui-même largement sur chaque plate-forme?

Vous ne pouvez pas. Ce que vous pouvez faire est d'utiliser des benchmarks pour donner l'illusion qu'une chose est meilleure qu'une autre, un ordinateur est plus rapide qu'un autre, un compilateur est plus rapide qu'un autre. Afin de vendre des ordinateurs ou des compilateurs. La couverture des sprints est de un pour cent de Verizons ... est-ce que cela nous dit quelque chose d'utile? Nan.

Si vous deviez éliminer le compilateur de l'équation, et si ce sont vraiment le même "CPU", le même tour de source d'ARM, construit de la même manière, alors ils devraient aller chercher le même, mais la taille de la le cache fait partie de cela, donc il peut déjà y avoir une implémentation de cpu différente car la largeur ou la profondeur du cache peut affecter les choses. Dans le logiciel, c'est comme avoir besoin d'un pointeur de 32 bits plutôt que d'un pointeur de 16 bits (17 bits au lieu de 16, mais vous ne pouvez pas avoir un 17 bits généralement en logique, vous pouvez). Quoi qu'il en soit, si vous compilez le code sous test une fois pour un espace d'adressage commun aux deux plates-formes, utilisez exactement le même binaire pour cet espace, pouvez attacher un code bootstrap différent, notez les appels de bibliothèque C strcpy, etc doivent également être les mêmes dans le même espace entre les plates-formes pour éliminer le compilateur et l'alignement de vous embêter. Cela peut ou non niveler le terrain de jeu.

Si vous voulez croire que ce sont les mêmes CPU, alors éteignez les caches, éliminez les variations du compilateur en faisant ce qui précède. Voyez s'ils exécutent la même chose. Copiez le programme à ram et courez en RAM, éliminez les problèmes de flash. Je suppose que vous les avez tous les deux synchronisés avec les mêmes états d'attente dans le flash? Si elles sont le même CPU et le fournisseur de puces a avec ces deux puces fait le système de mémoire prendre le même nombre d'horloges disons pour les accès RAM, et c'est vraiment le même CPU, vous devriez être en mesure d'obtenir le même en éliminant les optimisations (mise en cache, pré-lecture flash, alignement). Ce que vous voyez probablement est une certaine forme d'alignement avec la façon dont le code se trouve dans la mémoire du compilateur par rapport aux lignes de cache, ou cela pourrait être beaucoup plus simple que les différences dans les caches, comment les hits et les échecs travail et le 4KB est juste plus chanceux que le 8KB pour ce programme particulier compilé d'une certaine manière, aligné dans la mémoire d'une certaine manière, etc

Avec la simple boucle de deux instructions ci-dessus, il est facile de voir certaines des raisons pour lesquelles la performance varie sur le même système, si votre cpu moderne récupère 8 instructions à la fois et que votre boucle se rapproche trop de la fin de cette recherche, la prefetch peut penser qu'elle doit aller chercher 8 autres que celles qui vous coûtent ces cycles. Bien sûr, comme vous chevauchez exactement deux «fetch lines» comme je les appelle avec ces deux instructions, cela va vous coûter beaucoup plus de cycles par boucle, même avec un cache.Le même problème se produit lorsque ces deux instructions s'approchent d'une ligne de cache (puisque vous changez leur alignement par test). Finalement, il faut deux lectures de ligne de cache au lieu d'une pour récupérer ces deux instructions. Au moins la première fois à travers, une ligne de cache supplémentaire est lue. Les horloges supplémentaires pour cette première fois sont quelque chose que vous pouvez voir en utilisant un simple benchmark comme ça tout en jouant avec l'alignement. Michael Abrash, Zen of Assembly Language. Il y a un epub/etc que vous pouvez construire à partir du github de ce livre. le 8088 était obsolète quand ce livre est sorti si c'est tout ce que vous voyez 8088 choses, alors vous manquez complètement le point. Il s'applique aux processeurs les plus modernes aujourd'hui, comment visualiser le problème, comment tester, comment chronométrer le test, comment interpréter les résultats. Toutes les choses que j'ai mentionnées jusqu'ici, et toutes les choses que je sais à propos de ceci que je n'ai pas mentionnées, tout est venu de ce livre des connaissances appliquées pendant des décennies que j'ai fait ceci.

Donc, encore une fois si vous avez vraiment éliminé le compilateur, l'alignement, le processeur, le système de mémoire liée à ce processeur, etc et il est à la seule taille du cache varie. Ensuite, il est probablement lié à la manière dont la ligne de cache récupère et heurte différemment en fonction de l'alignement du code par rapport aux lignes de cache pour les deux caches. On frappe plus et manque moins et/ou expulse mieux pour ce binaire particulier. Vous pouvez réorganiser les fonctions, ajouter des interruptions ou, si vous ne pouvez pas obtenir le bootstrap, ajouter des fonctions entières ou plus de code (un autre printf, etc.) à une adresse inférieure du binaire, ce qui fait glisser le code sous test vers différentes adresses changeant comment le programme s'aligne avec les lignes de cache. Puisque les fonctions dans le code à tester sont si grandes (plus que quelques instructions à implémenter) vous devrez commencer à modifier le programme afin d'obtenir un ajustement plus fin de binaire par rapport aux lignes de cache.

Vous devriez certainement voir des différences de temps d'exécution sur les deux plates-formes si vous ajustez l'alignement et ou réorganisez en gros le binaire en fonction des fonctions réorganisées.

Les benchmarks de ligne de fond ne vous disent pas vraiment beaucoup, les résultats ont plus d'une puanteur négative à eux qu'une joie positive. Sans réécriture, un benchmark ou une application particulière peut faire mieux sur une seule plate-forme (que ce soit la même chose mais la taille du cache ou deux architectures complètement différentes) même lorsque vous essayez de faire varier les résultats En retirant toutes les astuces que l'on peut trouver, on peut varier de x à y l'autre de n à m et peut-être qu'il y a un certain chevauchement dans les plages. Pour ces deux plates-formes que vous dites similaires, sauf pour la taille du cache, j'espère que vous pourriez trouver une combinaison où A est plus rapide que B et au moins une combinaison où B est plus rapide que A, avec les mêmes fonctionnalités activées et désactivées pour les deux dans cette comparaison. Si/quand vous passez à une autre application/benchmark, tout recommence, il n'y a aucune raison de supposer que les résultats dhrystone prédisent n'importe quel autre code testé. Le seul programme qui compte, en particulier sur un MCU est la version finale de votre application. Rappelez-vous simplement de changer une seule ligne de code, ou même d'ajouter un seul nop dans le bootstrap peut avoir des résultats spectaculaires dans les performances parfois plusieurs fois plus lent ou plus rapide à partir d'un seul nop.