Structure d'un programme d'émulation
Je cherche à ce que ça exécute viiiiite !
Une bonne technique pour accélérer l'exécution d'un code écrit en C, pourrait résider dans les faits :
- d’éviter d'utiliser les switchs. En fait, je ne sais pas comment est implémenté un switch, mais je ne vois pas comment faire sans une (+ ou - longue) série de "if else if"
- d'éviter le passage de paramètre aux fonctions.
Ceci oblige a utiliser des viables globales, ou une structure pointée par une globale.
J'ai écrit un émulateur. Il reçoit en entrée des codes compris en 0 et 256. Le logiciel actuel comporte près de 300 fonctions. Pour régler le problème des switchs, j'ai utilisé intensivement les tableaux de pointeurs sur fonctions, et c'est la variable qui est entre parenthèse dans :
Code:
switch (variable) { ... }
qui sert d'index dans ce tableau. Chaque fois qu'on déclare une variable locale à une fonction (dite automatique), il faut réserver de la place dans la pile, ce qui est probablement ridicule en terme de temps d'exécution. J'ai réglé le problème de la façon suivante :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| // inclusion de headers, déclaration des types de structures,
// fonction etc : équivalent à un ".h"
// Le code C de l'émulateur ne comporte qu'une fonction visible :
void make_a_step (void) {
register MyStruct_t *GlobStruct; // Notez le modificateur "register"
int local1, local2, etc...
static void (*functTable[4])(); // "static" modificateur obligatoire
void funct1 (void) { ... }
void funct2 (void) { ... }
void funct3 (void) { ... }
void funct4 (void) { ... }
void init (void) {
functTable[0] = funct1; // Ce n'est pas écrit ainsi,
functTable[1] = funct2; // ça revient au même.
functTable[2] = funct3;
functTable[3] = funct4;
}
// le corps de la fonction "make_a_step" commence ici...
if (GlobStruct->_flagInited) {
init();
GlobStruct->_flagInited = 1;
}
...
...
} // Fin de make_a_step() |
La liste de ce bout de code est extrêmement simplifié, puisque le code actuel comporte plus de 3000 lignes.
Pour pouvoir mettre au point cet émulateur, il m'aura fallu écrire un moniteur (environs mille lignes). Je peut ainsi "programmer l'émulation en saisissant des codes que je fait exécuter en pas à pas, tout ceci grâce au moniteur. Ce moniteur est supposé permettre l'éxécution de code en pas à pas, ainsi que l'exécution d'une liste de codes en continu. Évidemment, la mise au point du code c'est fait en mode "pas à pas". Mais fait étrange, le programme se plante quand je passe de "pas à pas" en "run", OU quand je passe de "run" en "pas à pas". Nemiver (la "belle et vielle promesse non tenue") ou gdb n'y ont rien fait : je ne vois qu'une perte de contexte mais sans pouvoir corriger en gardant la structuration actuelle décrite plus haut.
J'ai essayé sans succès :
Code:
1 2 3 4 5
| void make_a_step (register MyStruct_t *GlobStruct) {
int local1, local2, etc...
static void (*functTable[4])(); // Static obligatoire
...
} |
La mémoire affectée à la variable pointée par GlobStruct l'a été par.le monitor, avec malloc. Il est peut probable (impossible) qu'elle soit déplacée dans la mémoire par le système.
Finalement, ça fonctionne,ainsi, avec un minimum de modif de la source, mais c'est philosophiquement insatisfaisant :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| MyStruct_t *GlobStruct; // Notez le modificateur "register"
int local1, local2, etc... // Elles ne sont plus locales (mal nommées!
void (*functTable[4])(); // Static PLUS obligatoire, puisque globale !
void funct1 (void) { ... }
...
functTable[3] = funct4;
}
void make_a_step (void) {
if (GlobStruct->_flagInited) {
init();
GlobStruct->_flagInited = 1;
}
...
...
} // Fin de make_a_step() |
Quelqu'un pourrait-il me dire pourquoi Linux perd les pédales ? Je pense que les programmeurs réguliers de threads pourraient sentir l'origine du problème et ainsi pouvoir m'indiquer comment le résoudre...
J'aurais préféré la première forme de structure décrire plus haut. J'ai bien vu que le logiciel perd vraiment les pédales entre "run" et "faire un pas" sans comprendre pourquoi. Je suppose que le code (la fonction make_a_step() complète) n'est pas "déplacé" par le système, à quelque occasion, auquel cas la fonction init serait à relancer ? J'ai vérifier en écrivant ceci :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| // inclusion de headers, déclaration des types de structures,
// fonction etc : équivalent à un ".h"
// Le code C de l'émulateur ne comporte qu'une function visible :
void *gFuncPosRef = NULL;
void make_a_step (void) {
register MyStruct_t *GlobStruct; // Modificateur "register"
int local1, local2, etc...
static void (*functTable[4])(); // "static" obligatoire
void funct1 (void) { ... }
...
functTable[3] = funct4;
}
// le corps de la fonction "make_a_step" commence ici...
if (!gFuncPosRef || gFuncPosRef!= &make_a_step) {
init();
gFuncPosRef = &make_a_step;
}
...
...
} // Fin de make_a_step() |
Mais ça marche pas.
EDIT :
Mais j'y pense : peut-être qu'écrire cette "fonction" comme étant une librairie résoudrait mon problème ?