IPB

Bienvenue invité ( Connexion | Inscription )

 
Reply to this topicStart new topic
> Optimiser les calculs en C
Options
Anard
posté 10 Mar 2018, 15:06
Message #1


Macbidouilleur de bronze !
**

Groupe : Membres
Messages : 377
Inscrit : 7 May 2015
Membre no 195 224



Bonjour,

Je travaille sur un µC qui doit lire du MIDI en temps réel.
Il est programmé en C et je débute un peu dans ce language. Lors de changements de tempo, j'ai besoin de faire des calculs mathématiques qui prennent beaucoup de temps au processeur (je pense que je m'y prend mal, j'ai l'impression que certaines instructions seraient à éviter).
Le fichier est écrit ainsi :
  • L'en-tête du fichier contient une valeur en nombre de "ticks" par noire
  • Au début et quand c'est nécessaire, il est indiqué un nouveau tempo en µs par noire (j'en déduis la durée d'un tick)
  • Avant chaque évènement Midi est indiqué un nombre de "ticks" à attendre


Mon programme actuel fonctionne comme ça :
Le microcontrôleur dispose d'un timer interne. Il s'incrément automatiquement tous les 64 coups d'horloge et il déclenche une action quand il atteint une limite configurable entre 1 et 255.
J'essaie donc de le calculer de telle manière à ce qu'il corresponde au plus près de la durée d'un "tick" et quand je recois un nombre de ticks à attendre, j'attends qu'il se déclenche autant de fois avant de lire la suite.
Mon calcul fonctionne, mais si le tempo change par exemple de manière progressive dans un morceau (en gros, il y a un changement de tempo avant chaque note), la lecture s'en trouve très ralentie. C'est embêtant.

Voici ce que j'utilise en cas de changement de tempo :
Code
// variable globale
    unsigned int baseDelay;
        float baseFreq;
// variables locales
    long Finstruction;
    float base, limite, calcul;

// A l'ouverture du fichier, je déduis du nombre de "ticks" par noire (une seule fois) la fréquence du timer dont j'ai besoin
    Finstruction = _XTAL_FREQ / 4000000; //MHz
    baseFreq = 256 * (long)DivisionTps; // 256 = limite max d'explosion du timer
    baseFreq = Finstruction / baseFreq; // = FmaxTimer / DivisionTps
    baseFreq /= 16;    // multiplicateur interne du timer

// Configuration lors d'un changement de Tempo

        // souvent la limite de 256 du timer ne suffira pas, donc j'utilise un multiplicateur supplémentaire
        base = ceil(Tempo * baseFreq);

        // calcul de la valeur d'Overflow (PR2)
        calcul = baseFreq * 256 / base;
        limite = round (Tempo * calcul);
        
        // config
        baseDelay = (int)base;
        PR2 = (int)limite - 1; // le timer déclenche un évènement au moment où il passe la limite PR2, pas quand il l'atteint

        // je dois aussi récupérer le Tempo en BPM :
        TempoBPM = 60000000/Tempo;

// Lorsque je reçois un délai à attendre, il est simplement calculé comme ceci :
        return (DelaiLu * baseDelay);
// puis le timer est démarré si le résultat n'est pas nul.


Pourriez-vous m'expliquer quelles sont les opérations les plus lourdes là-dedans pour essayer de faire en sorte de les supprimer ?
Merci beaucoup.

Ce message a été modifié par Anard - 10 Mar 2018, 15:38.


--------------------
"iMack" : GA-B85-D3H, Intel i5 4460, 8Go DDR3, Intel HD4600, SSD 128+60Go, HDD 500Go+1To / Clover - macOS Sierra / Ubuntu Bionic Beaver / Windows 10
"Portable" : Samsung P200, Intel Core2Duo T8100, 3Go DDR2, Radeon X1250, HDD 160Go / Grub2 - SliTaz 5.0 rolling / Windows 10
Go to the top of the page
 
+Quote Post
ntx
posté 10 Mar 2018, 22:23
Message #2


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 459
Inscrit : 19 Aug 2004
Lieu : 92
Membre no 22 254



Es-tu obligé de travailler avec des float ? Les calculs sur les entiers sont plus rapides. 1/10 de Hz sera-t-il entendu à l'oreille ?
Avec des entiers, les "*256" et "/16" seront fait avec des décalages de bits et cela sera bien plus rapide qu'une multiplication ou une division sur des flottants.

Sinon pour des calculs sur des flottants, utilise un DSP qui est fait pour cela.
Go to the top of the page
 
+Quote Post
Jaypee
posté 11 Mar 2018, 07:16
Message #3


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 344
Inscrit : 29 Aug 2002
Membre no 3 340



Une autre option serait des configs/patterns pré-définis :
- le calcul permet de proposer tous les cas possibles, mais tous les cas ne sont pas utiles

Donc si les cas les plus probables ou utiles sont prévisibles, on peut pré-calculer les valeurs et les stocker, et les relire sans calculs au moment de les utiliser
- Il faut alors pouvoir trouver le "pattern pré-calculé" qui va bien en fonction du fichier à transformer
- il faut relire les valeurs pré-calculées.

Mais l'idée est là : séparer la fabrication des paramètres de leur utilisation pour transformer un fichier

J-P
Go to the top of the page
 
+Quote Post
Anard
posté 13 Mar 2018, 10:07
Message #4


Macbidouilleur de bronze !
**

Groupe : Membres
Messages : 377
Inscrit : 7 May 2015
Membre no 195 224



Bonjour et merci pour vos réponses.
J'ai réussi à revoir mes calculs pour n'utiliser que des entiers. J'arrive en fonction de la situation à une erreur finale de 0 à -5‰ au lieu de ±2,2‰ avec des float. Ce n'est en effet pas si dramatique et ça tourne beaucoup plus vite.
J'ai également essayé d'écrire les données en dur en créant d'énormes tableaux, pour 7 valeurs de "ticks"/noire (120, 192, 240, 384, 480, 768, 960) souvent rencontrées et pour des tempos allant de 45 à 299 :
Code
const unsigned int limites[7][255] =  {{252,252,252,253,254,249,..},\
                                    {...},{...},{...},{...},{...},{...}};

const unsigned int bases[7][255] =    {{ 44, 43, 42, 41, 40, 40, ..},\
                                      {...},{...},{...},{...},{...},{...}};


C'est bourrin et ça prend pas mal de place en mémoire, mais en effet, ça fonctionne et va encore bien plus vite. Ca m'a surtout permis de constater que certains ralentissements venaient d'ailleurs dans le programme. Par exemple au moment d'afficher la modification à l'écran, en SPI, ce qui ralenti considérablement le temps de traitement s'il y a beaucoup de modifications à suivre (par exemple comme je le disais lors d'un changement de tempo progressif).

Un DSP ? Je ne connais pas. C'est un composant externe qui s'occupe uniquement du calcul ?

En tout cas, c'est déjà un peu mieux, merci beaucoup pour vos conseils, c'est exactement ce dont j'avais besoin pour avancer.

Ce message a été modifié par Anard - 13 Mar 2018, 20:32.


--------------------
"iMack" : GA-B85-D3H, Intel i5 4460, 8Go DDR3, Intel HD4600, SSD 128+60Go, HDD 500Go+1To / Clover - macOS Sierra / Ubuntu Bionic Beaver / Windows 10
"Portable" : Samsung P200, Intel Core2Duo T8100, 3Go DDR2, Radeon X1250, HDD 160Go / Grub2 - SliTaz 5.0 rolling / Windows 10
Go to the top of the page
 
+Quote Post
ntx
posté 13 Mar 2018, 18:14
Message #5


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 459
Inscrit : 19 Aug 2004
Lieu : 92
Membre no 22 254



Un petit peu de culture.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 utilisateur(s) sur ce sujet (1 invité(s) et 0 utilisateur(s) anonyme(s))
0 membre(s) :

 



Nous sommes le : 21st July 2018 - 17:57