J'écris un programme pour fonctionner sur un ATmega 328 qui fonctionne à 16 MHz (c'est un Arduino Duemilanove si vous les connaissez, c'est une puce AVR).
J'ai un processus d'interruption qui s'exécute toutes les 100 microsecondes. Il est impossible, je dirais, de déterminer la quantité de "code" que vous pouvez exécuter dans une boucle de 100 microsecondes (j'écris en C qui est probablement converti en assemblage puis en une image binaire?).
Cela dépendrait également de la complexité du code (un liner géant pourrait fonctionner plus lentement que plusieurs lignes courtes par exemple).
Ma compréhension est-elle correcte, en ce sens que mon processeur avec une fréquence d'horloge ou 16 MHz effectue 16 millions de cycles par seconde (cela signifie 16 cycles par microseconde 16 000 000/1 000/1 000); Et donc, si je veux faire plus dans ma boucle de 100 microsecondes, acheter un modèle plus rapide comme une version 72Mhz me donnerait 72 cycles par microseconde (72,000,000 / 1,000 / 1,000)?
Actuellement, il fonctionne un peu trop lentement, c'est-à-dire qu'il faut un peu plus de 100 microsecondes pour faire la boucle (combien de temps exactement est trop difficile à dire, mais il prend progressivement du retard) et j'aimerais qu'il fasse un peu plus, est est-ce une approche sensée obtenir une puce plus rapide ou suis-je devenu fou?
la source
Réponses:
En général, le nombre d'instructions d'assemblage que le dispositif peut exécuter par seconde dépend du mélange d'instructions et du nombre de cycles que chaque type d'instruction prend (CPI) pour exécuter. En théorie, vous pourriez compter votre code en cycle en consultant le fichier asm désassemblé et en regardant la fonction qui vous intéresse, en comptant tous les différents types d'instructions qu'il contient et en recherchant le nombre de cycles à partir de la fiche technique de votre processeur cible.
Le problème de la détermination du nombre effectif d'instructions par seconde est exacerbé dans les processeurs plus complexes par le fait qu'ils sont pipelinés et ont des caches et autres. Ce n'est pas le cas pour un appareil simple comme un ATMega328 qui est une instruction unique dans le processeur de vol.
Quant aux questions pratiques, pour un appareil simple comme un AVR, ma réponse serait plus ou moins "oui". Le doublement de votre vitesse d'horloge devrait réduire de moitié le temps d'exécution d'une fonction donnée. Pour un AVR, cependant, ils ne fonctionneront pas à une vitesse supérieure à 20 MHz, vous ne pourrez donc "overclocker" votre Arduino que de 4 MHz supplémentaires.
Ce conseil ne se généralise pas à un processeur qui a des fonctionnalités plus avancées. Le fait de doubler la vitesse d'horloge de votre processeur Intel ne doublera pas en pratique le nombre d'instructions qu'il exécute par seconde (en raison de fausses prédictions de branche, de ratés de cache, etc.).
la source
La réponse de @ vicatcu est assez complète. Une autre chose à noter est que le processeur peut se retrouver dans des états d'attente (cycles de processeur bloqués) lors de l'accès aux E / S, y compris la mémoire de programme et de données.
Par exemple, nous utilisons un TI F28335 DSP; certaines zones de la mémoire RAM sont à l'état d'attente 0 pour le programme et la mémoire de données, donc lorsque vous exécutez du code dans la mémoire RAM, il s'exécute à 1 cycle par instruction (à l'exception des instructions qui prennent plus d'un cycle). Lorsque vous exécutez du code à partir de la mémoire FLASH (EEPROM intégrée, plus ou moins), cependant, il ne peut pas fonctionner à 150 MHz et il est plusieurs fois plus lent.
En ce qui concerne le code d'interruption à grande vitesse, vous devez apprendre un certain nombre de choses.
Tout d'abord, familiarisez-vous avec votre compilateur. Si le compilateur fait du bon travail, il ne devrait pas être beaucoup plus lent que l'assemblage codé à la main pour la plupart des choses. (où "beaucoup plus lent": un facteur 2 me conviendrait; un facteur 10 serait inacceptable) Vous devez apprendre comment (et quand) utiliser les indicateurs d'optimisation du compilateur, et de temps en temps, vous devriez regarder à la sortie du compilateur pour voir comment il fonctionne.
D'autres choses que le compilateur peut faire pour accélérer le code:
utiliser des fonctions en ligne (je ne me souviens pas si C le supporte ou si ce n'est qu'un isme C ++), à la fois pour les petites fonctions et pour les fonctions qui ne seront exécutées qu'une ou deux fois. L'inconvénient est que les fonctions en ligne sont difficiles à déboguer, surtout si l'optimisation du compilateur est activée. Mais ils vous épargnent des séquences d'appel / retour inutiles, surtout si l'abstraction "fonction" est à des fins de conception plutôt que d'implémentation de code.
Regardez le manuel de votre compilateur pour voir s'il a des fonctions intrinsèques - ce sont des fonctions intégrées dépendantes du compilateur qui correspondent directement aux instructions d'assemblage du processeur; certains processeurs ont des instructions d'assemblage qui font des choses utiles comme inverser min / max / bit et vous pouvez gagner du temps en le faisant.
Si vous effectuez un calcul numérique, assurez-vous que vous n'appelez pas les fonctions de bibliothèque de mathématiques inutilement. Nous avons eu un cas où le code ressemblait
y = (y+1) % 4
à un compteur qui avait une période de 4, s'attendant à ce que le compilateur implémente le modulo 4 en tant que AND au niveau du bit. Au lieu de cela, il a appelé la bibliothèque mathématique. Nous avons donc remplacé pary = (y+1) & 3
faire ce que nous voulions.Familiarisez-vous avec la page de piratage de bits . Je vous garantis que vous en utiliserez au moins un souvent.
Vous devez également utiliser les périphériques de temporisation de votre CPU pour mesurer le temps d'exécution du code - la plupart d'entre eux ont un timer / compteur qui peut être réglé pour s'exécuter à la fréquence d'horloge du CPU. Capturez une copie du compteur au début et à la fin de votre code critique, et vous pouvez voir combien de temps cela prend. Si vous ne pouvez pas faire cela, une autre alternative consiste à abaisser une broche de sortie au début de votre code, à la relever à la fin et à regarder cette sortie sur un oscilloscope pour chronométrer l'exécution. Il y a des compromis à chaque approche: le temporisateur / compteur interne est plus flexible (vous pouvez chronométrer plusieurs choses) mais plus difficile à obtenir les informations, tandis que définir / effacer une broche de sortie est immédiatement visible sur une étendue et vous pouvez capturer des statistiques, mais il est difficile de distinguer plusieurs événements.
Enfin, il y a une compétence très importante qui vient avec l'expérience - à la fois générale et avec des combinaisons processeur / compilateur spécifiques: savoir quand et quand ne pas optimiser . En général, la réponse est ne pas optimiser. La citation de Donald Knuth est publiée fréquemment sur StackOverflow (généralement juste la dernière partie):
Mais vous êtes dans une situation où vous savez que vous devez faire une sorte d'optimisation, il est donc temps de mordre la balle et d'optimiser (ou d'obtenir un processeur plus rapide, ou les deux). N'écrivez PAS l'intégralité de votre ISR en assemblage. C'est presque un désastre garanti - si vous le faites, dans les mois ou même les semaines, vous oublierez des parties de ce que vous avez fait et pourquoi, et le code est susceptible d'être très fragile et difficile à changer. Il est probable que certaines parties de votre code soient de bons candidats pour l'assemblage.
Signifie que certaines parties de votre code sont bien adaptées au codage d'assemblage:
Apprenez les conventions d'appel de fonction de votre compilateur (par exemple, où il place les arguments dans les registres et quels registres il enregistre / restaure) afin de pouvoir écrire des routines d'assemblage appelables C.
Dans mon projet actuel, nous avons une base de code assez grande avec du code critique qui doit s'exécuter dans une interruption de 10 kHz (100usec - son familier?) Et il n'y a pas beaucoup de fonctions écrites en assembleur. Ceux qui le sont, sont des choses comme le calcul CRC, les files d'attente logicielles, la compensation de gain / décalage ADC.
Bonne chance!
la source
Une autre chose à noter - il y a probablement des optimisations que vous pouvez effectuer pour rendre votre code plus efficace.
Par exemple - j'ai une routine qui s'exécute à partir d'une interruption de minuterie. La routine doit se terminer en 52 µS, et doit parcourir une grande quantité de mémoire pendant qu'elle le fait.
J'ai réussi une grande augmentation de vitesse en verrouillant la variable de compteur principale dans un registre avec (sur mon µC et compilateur - différent pour le vôtre):
Je ne connais pas le format de votre compilateur - RTFM, mais vous pourrez faire quelque chose pour accélérer votre routine sans avoir à passer en assembleur.
Cela dit, vous pouvez probablement faire un bien meilleur travail pour optimiser votre routine que le compilateur, donc passer à l'assemblage peut bien vous donner des augmentations de vitesse massives.
la source