Go Down

Topic: [CDG] tout peut s'optimiser! (Read 2947 times) previous topic - next topic

Super_Cinci

Oui, encore une fois, je râle sur la façon dont nous utilisons nos pauvres arduinos...

Pour rigoler, j'ai fait ce sketch :

Code: [Select]

void setup() {
  // put your setup code here, to run once:
  DDRF = 0xAA;
}

void loop() {
  // put your main code here, to run repeatedly:
  DDRF = !DDRF;
}

Il ne fait rien du tout, mais l'idée était de voir comment l'IDE allait me traiter tout ça. alors je suis allé chercher le fichier Hex qu'il m'a pondu, et je l'ai décortiqué à l'aide de ReAVR, un petit soft qui transforme les .hex en assembleur. Je ne vous donne pas tout le coe asm, mais j'ai fini par retrouver mon setup() et loop() dedans.

J'y ai surtout vu ce que le core arduino rajoutait, comme l'interruption du timer0 pour le comptage de milliseconds(), et je peux vous dire que cette interruption, elle prend beaucoup de place, juste pour incrémenter une variable de type long (4 octets) en SRAM...

Puis j'ai aussi vu la façon dont le compilateur compilait, ben c'est bien loin d'être optimsé! Si on fait deux opérations à suivre sur un même registre, il va aller copier ce registre, faire l'opération, le remettre à sa place, puis le reprendre et faire la seconde opération et enfin le remettre à sa place. ce n'est qu'une des nombreuses bourdes que j'ai relevées... si j'ai le temps, je ferai la même chose avec un digitalWrite() pour voir...  :smiley-mr-green:

Je me suis amusé à réécrire le code asm sur une petite partie, et surprise : entre ce que le core arduino dit en C et l'assembleur que je ponds, il y a un rapport 2 (mon code est deux fois plus court, donc deux fois plus rapide). :smiley-roll-blue:

Bref, CDG = Coup De Gueule ]:D : d'une, le core est très mal écrit, et de deux, le compilateur n'optimise pas si bien que ça...

Ce qui me pousse de plus en plus à revoir entièrement les choses en créant mon propre core... et ça ne va pas tarder...

skywodd

Salut,


Il ne fait rien du tout, mais l'idée était de voir comment l'IDE allait me traiter tout ça. alors je suis allé chercher le fichier Hex qu'il m'a pondu, et je l'ai décortiqué à l'aide de ReAVR, un petit soft qui transforme les .hex en assembleur. Je ne vous donne pas tout le code asm, mais j'ai fini par retrouver mon setup() et loop() dedans.

Il ne fait pas "rien du tout".
Il places les broches n°1, 3, 5, 7 du port F en sorties et les autres en entrées, puis fait passer la broche n°0 du port F d'entrée à sortie indéfiniment.
Même si ce n'est pas grand chose ça reste quelque chose ;)


J'y ai surtout vu ce que le core arduino rajoutait, comme l'interruption du timer0 pour le comptage de milliseconds(), et je peux vous dire que cette interruption, elle prend beaucoup de place, juste pour incrémenter une variable de type long (4 octets) en SRAM...

Ce qui est tout à fait normal ...
Le code source de l'interruption du timer0 est conçu pour maintenir à jour une variable de temps en millisecondes ... mais pas que.
Cette interruption a aussi pour but de maintenir à jour un compteur de temps très précis en fraction de millisecondes pour la fonction micros().
C'est pour cela qu'elle peut te paraitre assez volumineuse, mais en réalité elle fait pas mal de chose.
(voir dans le fichier wiring.c)


Puis j'ai aussi vu la façon dont le compilateur compilait, ben c'est bien loin d'être optimisé! Si on fait deux opérations à suivre sur un même registre, il va aller copier ce registre, faire l'opération, le remettre à sa place, puis le reprendre et faire la seconde opération et enfin le remettre à sa place. ce n'est qu'une des nombreuses bourdes que j'ai relevées... si j'ai le temps, je ferai la même chose avec un digitalWrite() pour voir...  :smiley-mr-green:

Tu mélanges tout ;)
Il faut bien différencier l'optimisation du code source (par le dév) et l'optimisation du compilateur (par le compilateur et le linker).
L'ide Arduino est paramétré pour ne demander quasiment aucune optimisation au compilateur par défaut.
De même l'ide Arduino ne peut pas corriger les décisions d'analyses et de conceptions de la team arduino.

Il faut aussi prendre en compte un point TRÈS important : le framework Arduino N'EST PAS conçu pour la vitesse / optimisation / etc.
Il est conçu pour être simple d'utilisation par des novices de la programmation, l'optique Arduino c'est "je tapote, ça marche, fini".
C'est dure à dire mais c'est comme ça.
En aucun cas l'optimisation n'as été une fonctionnalité du core arduino ;)

digitalWrite() en interne c'est 6 appels de fonction, 3 tables de lookup en flash et 440 octets de code machine (environ).
Ça semble énorme comparé à un pauvre PORTx |= _BV(PINx); qui demande 8 octets de code machine mais c'est comme ça.
L'optimisation a été volontairement sacrifié au profit de la simplicité.

Après il existe des initiatives comme "DigitalWriteFast" qui se basent sur des #define et de l'optimisation en pré-compilation mais le résultat reste le même : dés qu'on retombe sur un digitalWriteFast(valeur_dynamique) on revient aux 6 appels de fonctions, 3 tables, etc

Abstraction matériel haut niveau et optimisation intensive bas niveau ne peuvent malheureusement pas cohabiter.
Il faut faire un choix à un moment donné.


Je me suis amusé à réécrire le code asm sur une petite partie, et surprise : entre ce que le core arduino dit en C et l'assembleur que je ponds, il y a un rapport 2 (mon code est deux fois plus court, donc deux fois plus rapide). :smiley-roll-blue:

Fait un test, compile ceci avec l'ide Arduino :
Code: [Select]
int main() {
  DDRF = 0xAA;
  for(;;)
    DDRF = !DDRF;
}


L'ide Arduino est conçu pour passer en mode "éditeur de texte" dés qu'une fonction main() existe.
Le code ci dessus est donc un code Arduino tout à fait valable, mais regarde la taille du programme générait.
Le facteur de taille doit être d'environ /3 ;)


Bref, CDG = Coup De Gueule ]:D : d'une, le core est très mal écrit, et de deux, le compilateur n'optimise pas si bien que ça...

Le core Arduino est assez mal écrit, c'est un fait mais :
- n'oublions pas que la team Arduino à l'origine est composée de designer. C'est déjà pas mal qu'ils aient pu apprendre la programmation Java et AVR-C.
(même si c'est vrai qu'ils auraient pu laisser la prog à des développeurs compétent, bref)
- le compilateur optimise très bien ... quand on lui demande ;)
GCC est un compilateur dont le taux d'optimisation est très élevé (si bien utilisé). GCC en mesure de générer du code machine avec seulement 10% d'instructions en plus par rapport à un code assembleur fait main par un "pro".
(PS: depuis les nouvelles formes d'optimisation "LTO" ce % à du diminuer drastiquement)
- le compilateur AVR-GCC fourni avec l'ide à plus de 4 ans de retard (et même si beaucoup de monde râle la team Arduino s'en fout royalement)
- l'ide arduino est un gouffre sans fond en terme de truc foireux mais ça tout le monde le sait :smiley-mr-green:

Donc oui je te comprend mais il faut relativiser.
Si tu veut du code optimiser il ne faut pas espérer des miracles ;)
Moi je code désormais exclusivement en AVR-C, mes programmes ont perdu un sacré poids sans pour autant être plus compliqué à lire.
Mais bien sûr pour coder en AVR-C il faut lire la doc constructeur en anglais, du coup les débutants prennent peur.
Même si le core arduino est une catastrophe en terme d'optimisation cela reste un excellent moyen de commencer dans la programmation embarqué.
Après il faut savoir évoluer et passer à quelque chose de mieux une fois les bases acquises.


Ce qui me pousse de plus en plus à revoir entièrement les choses en créant mon propre core... et ça ne va pas tarder...

Beaucoup ont essayé, et crois moi c'est pas aussi simple que ça n'y parait ;)
Faire quelque choses de simple, optimisé et portable demande beaucoup de réflexion et une analyse en béton armé.

Ps: je sait pas si c'est la crève ou quoi mais j'étais inspiré dis donc, désolé pour le roman :smiley-mr-green:
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

Super_Cinci

Nous sommes d'accord, Sky.

Un coup de gueule, c'est une râlerie qui a pour but d'extérioriser un peu. Oui je tenterai d'écrire un core, mais il ne faudra pas y chercher de digitalWrite ou analogRead... il n'y aura rien dedans, que de la définition de registres. il y aura une fonction delay(), mais je l'imagine déjà comme étant un simple timer qui au bout d'un certain temps mettra un boolean à true

Code: [Select]

  instruction1();  // on fait un truc,
  cinciDelay(100);  // il faut attendre 100 ms avant de faire l'instruction2,
  mais_là_on_a_d_autres_trucs_à_faire();  // en attendant, peut-être que?
  while(delay);  // on attend que le timer de cinciDelay mette la variable delay à 1 si ce n'est déjà fait...
  instruction2();


je vois déjà le même principe pour un analogWrite() etc etc. Mais je le fais pour ma gueule, pas pour les autres, je n'ai pas envie de passer ma vie à répondre à des emails de gugusses qui n'arriveraient pas à s'en servir... (encore merci pour l'info sur boards.txt dans le topic du 644...)

Il faudra que j'essaie ton int main(), ça m'intrigue... C'est fait. 316 octets contre 682 avant. Reste que sur les 316, il doit y en avoir encore de trop, non? et s'il a reconnu mon DDRF, c'est donc qu'il y a des #include cachés qui trainent encore.

En effet, l'arduino est fait pour les gros débutants (le prenez pas mal les gars, hein!), et quand on voit que même la team utilise des int 16bits signés pour de simples variables sur un proc 8bits, ça me fait vraiment peur...

skywodd


Un coup de gueule, c'est une râlerie qui a pour but d'extérioriser un peu.

Je comprend ;)


Mais je le fais pour ma gueule, pas pour les autres, je n'ai pas envie de passer ma vie à répondre à des emails de gugusses qui n'arriveraient pas à s'en servir... (encore merci pour l'info sur boards.txt dans le topic du 644...)

Ben moi je passe ma vie à répondre à mes mails donc je peut comprendre que ça te tente pas trop :smiley-mr-green:


Il faudra que j'essaie ton int main(), ça m'intrigue... C'est fait. 316 octets contre 682 avant. Reste que sur les 316, il doit y en avoir encore de trop, non? et s'il a reconnu mon DDRF, c'est donc qu'il y a des #include cachés qui trainent encore.

Ha ba tient, voila un exemple parfait de mon commentaire sur les optimisations LTO.
Avec un AVR-GCC à jour j'obtiens 458 octets de base et 148 octets en mode éditeur de texte.
Comme quoi il serait bon que la team arduino se bouge un peu pour ça.

Pour la petite histoire : avec 3 autres dév ont a fait un mail sur le google-code du projet Arduino pour passer du package WinAVR (tout pourri et plus maintenu) à MHV Avr Tool (maintenu activement).
Rien à faire la team Arduino veut rien entendre, il n'ont même pas dénié nous répondre ...


En effet, l'arduino est fait pour les gros débutants (le prenez pas mal les gars, hein!), et quand on voit que même la team utilise des int 16bits signés pour de simples variables sur un proc 8bits, ça me fait vraiment peur...

Et oui on peut pas tout avoir.
Avec une connaissance on a dans l'idée de créer un framework suivant l'optique des bibliothèques CMSIS pour processeurs ARM.
(CMSIS est une librairie qui uniformise l'api logicielle pour les processeurs ARM)
Mais c'est une projet très conséquent donc pour le moment on laisse l'idée de côté.
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

68tjs

Quote
si j'ai le temps, je ferai la même chose avec un digitalWrite() pour voir...

C'est fait. Fréquence max à laquelle on peut basculer une  sortie:
Core Arduino :
Sorties PWM : fmax = 68,6 kHz.
Sorties non PWM Fmax = 87,4 kHz
Écriture directe dans les registres :
Quelque soit la sortie (PWM ou pas c'est pareil) : Fmax = 1MHz avec un rapport cyclique  RC=12/88
En rectifiant le RC (ajout de NOP() bien placés) Fmax = 570 kHz et RC = 50/50
En utilisant directement les timers:
F max = Fsysteme/2 = 8 MHz.
Quote
le compilateur AVR-GCC fourni avec l'ide à plus de 4 ans de retard (et même si beaucoup de monde râle la team Arduino s'en fout royalement)

Sous Debian, et donc Ubuntu, Mint, etc, c'est la dernière version qui est utilisé puisque ce qui est téléchargeable sur le site Arduino a été coupé en deux paquets par le mainteneur Debian. D'un coté le "core"  et de l'autre l'interface graphique proprement dite.
En vertu de quoi les chiffres de fréquences max ont été obtenus avec la dernière version du compilateur.

Quote
1) (même si c'est vrai qu'ils auraient pu laisser la prog à des développeurs compétents, bref)
2) Beaucoup ont essayé, et crois moi c'est pas aussi simple que ça n'y parait smiley-wink
3) Mais bien sûr pour coder en AVR-C il faut lire la doc constructeur en anglais, du coup les débutants prennent peur

1) Bien sûr c'est comme cela qu'il aurait fallu faire mais pas question de partager les $$$$.
2) Tout à fait d'accord, par contre ils auraient pu établir des règles simples pour les bibliothèques. Le problème récurant des librairies ISP qui utilisent toutes le même pin pour le chip select est honteux : édicter que le numéro du pin de chip select doit être indiqué à l'instantiation c'est quand même pas insurmontable, c'est tout simplement du je m'en foutisme : l'important est de vendre des cartes et d'empocher des $$$$$.
3) C'est bien réel et bien triste. Pourtant pour maîtriser ce que l'on fait et pour progresser il n'y a pas d'autre solution.
Quote
n'oublions pas que la team Arduino à l'origine est composée de designer. C'est déjà pas mal qu'ils aient pu apprendre la programmation Java et AVR-C.

On ne peut être qu'admiratif de la réussite, ce n'était pas gagné d'avance, dont acte.
Réussir à fédérer une communauté aussi compétente, et en plusieurs langues, autour de ce projet est réussite exceptionnelle. J'aimerais bien retrouver la même communauté dans le domaine des FPGA
.
Mais à partir du moment où on transforme un projet universitaire (de maîtrise ou de doctorat, je ne connais pas trop la réalité des faits), en projet mercantile on se doit d'être rigoureux et de faire face a ses obligations.
On est loin de la rigueur anglo-saxone.

skywodd

Gros +1 pour 68tjs.

Ce que je trouve dommage et ce qui ce confirme un peu plus de jour en jour :
- la team Arduino se contre fout de sa communauté (pourtant c'est cette même communauté qui fait vivre le projet ...).
- argent, argent, argent, toujours plus d'argent (+120€ le "robot arduino" avec trois fois rien dedans, si ça c'est pas du foutage de gueule)
(Je suis tout à fait d'accord que la team Arduino veuillent s'assurer un salaire correct mais quand même)
- support sur le long terme ? Pas rentable ça ma p'tite dame ...
(J'attends toujours le portage des librairies "de bases" sur l'arduino Due :smiley-roll:)
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

Super_Cinci

On est bien d'accord, la team a du mérite d'avoir su monter la mayo arduino, mais avec tous les développeurs qu'ils ont maintenant sous la main, ils pourraient gagner à faire bosser les gens qui savent. Tout est une affaire de $$$$.



Il faudra que j'essaie ton int main(), ça m'intrigue... C'est fait. 316 octets contre 682 avant. Reste que sur les 316, il doit y en avoir encore de trop, non? et s'il a reconnu mon DDRF, c'est donc qu'il y a des #include cachés qui trainent encore.

Ha ba tient, voila un exemple parfait de mon commentaire sur les optimisations LTO.
Avec un AVR-GCC à jour j'obtiens 458 octets de base et 148 octets en mode éditeur de texte.
Comme quoi il serait bon que la team arduino se bouge un peu pour ça.

J'ai créé mon cinciduino. J'ai copié le UNO dans boards.txt en changeant le répertoire build.core avec un nouveau dans lequel j'ai mis main.cpp, arduino.h, io.h, sfr_defs.h, iom328p.h, inttypes.h et stdint.h, tous repris en virant un max de trucs (surtout les #include). Normalement, il ne me reste que les defs des types, registres et interruptions, soit que des #define.

compilation du même code avec la carte UNO habituelle : 476 octets en 5 secondes
avec la carte cinciduino UNO : 194 octets en... ben ça a été tellement rapide, j'ai pas eu le temps de compter...

Je suis en bonne voie... C'est donc depuis le main.cpp que tout se joue, et j'ai réussi (enfin je crois)...

LamiRene

Bonjour à tous,

Merci pour les détails, c'est très instructif !

Et si vous avez d'autres détails, ne vous gênez pas de nous les communiquer !

L'ami René
Tous pour un et un pour tous !

Super_Cinci

Je suis tombé sur une vieille discussion...


Désolé, c'est ce que donne ton code avec le logiciel arduino 1.04!

Normal, la team arduino fourni l'ide avec une version de AVR-GCC datant de 2008 ;)

Pour mettre à jour AVR-GCC :
1) télécharge MHV AVR TOOLS : http://www.makehackvoid.com/node/578/release
2) installe le tout
3) copie le dossier de l'installation (qui doit contenir bin, etc, ...) dans le dossier hardware/tools/avr de ton installation arduino (renomme l'ancien dossier avr en avr-old)
4) copie le fichier avrdude.conf du dossier "bin" dans le dossier "etc"
5) relance l'ide arduino, compile et enjoy ;)

Alors j'ai fait! j'ai trouvé la mise à jour vers AVR GCC 4.7.2, j'ai installé, copié... bref, tout fait comme Skywood a dit.

Mais voilà, il semblerait que le nouvel avr-g++.exe ne réponde pas, j'ai "erreur de compilation" et ceci :
Quote

C:\Program Files\Arduino\hardware\tools\avr\bin\avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=105 -IC:\Program Files\Arduino\hardware\arduino\cores\arduino -IC:\Program Files\Arduino\hardware\arduino\variants\standard C:\DOCUME~1\FREEPO~1\LOCALS~1\Temp\build1091528783843041485.tmp\BareMinimum_test.cpp -o C:\DOCUME~1\FREEPO~1\LOCALS~1\Temp\build1091528783843041485.tmp\BareMinimum_test.cpp.o

mince alors... j'aurais bien voulu tester mon petit code bidon avec un compilateur + à jour (j'ai définit la carte UNO classique).

J'imagine bien que Sky a déjà de quoi s'occuper, mais si un jour il a le courage de nous faire un tuto sur une MAJ du compilateur...

Je vais regarder ce que je peux faire de mon côté...

LamiRene

N'oubliez pas les linuxiens !

L'ami René
Tous pour un et un pour tous !

68tjs

Quote
N'oubliez pas les linuxiens !


Pas de problème avec Linux, du moins avec Debian et dérivées cela fait plusieurs années que l'IDE à été coupée en deux paquets : arduino et arduino-core.  Ce qui permet d'utiliser  les versions de GCC et d'avr-GCC des dépots officiels qui sont à jour eux !

Evidement si tu  télécharger la version Linux concoctée par Arduino tu as tout faux.

Il faut prendre la version officielle des dépots de ta distribution.

LamiRene

Bonjour 68tjs,

Merci pour l'info !

J'ai déjà la version des dépôts d'installée, mais j'ai aussi installé les paquets a décompresser des versions 1.0.5, 1.5.2, 1.5.3 et 1.5.4.

Est-ce que je pourrais convertir mes versions 1.0.5 et 1.5.4 en version potable ?

Je suis sous Kubuntu 12.04, 64 bits.

L'ami René
Tous pour un et un pour tous !

68tjs

La version 1,5 n'est pas dans les dépots debian donc pas non plus chez Ubuntu puisque c'est la debian.
Il n'y a pas suffisamment de demande.

icare

Bonsoir,
J'ai fait la mise à jour du compilateur selon les indications de Skywodd : http://forum.arduino.cc/index.php?topic=182507.msg1363449#msg1363449
Quelques petites différence par rapport  à la description : http://forum.arduino.cc/index.php?topic=182507.msg1364124#msg1364124
A ce jour, j'utilise 4.7.2
@+
2B OR NOT(2B) = FF
Arduino 1.0.5 + Notepad++ (sous Linux Fedora et/ou Windows)

Super_Cinci


Bonsoir,
J'ai fait la mise à jour du compilateur selon les indications de Skywodd : http://forum.arduino.cc/index.php?topic=182507.msg1363449#msg1363449
Quelques petites différence par rapport  à la description : http://forum.arduino.cc/index.php?topic=182507.msg1364124#msg1364124
A ce jour, j'utilise 4.7.2
@+


ok. j'ai bien suivi les étapes 1 et 3 depuis skyduino.wordpress.com (téléchargement / installation de la toolchain (version 4.7.2), copie du fichier avrdude.conf, renommage avr_old, copie de la toolchain dans le avr de arduino). version IDE : 1.0.5

Mais à l'installation, je n'ai pas coché "ajout au path". il y a un .bat qui permet de le faire après (mais à lancer à chaque démarrage de windaube. avec ou sans : aucun résultat...

Go Up