



Next: Les accès mémoire Up: Optimisation de fluide Previous: Optimisation de fluide Contents
Conversions int-float
Sur une grande partie des processeurs modernes, la conversion entre les données flottantes et les données entières est très lente. Par exemple, sur un processeur d'Intel or AMD de type x86, une conversion d'un float à un int nécessite de vider le pipeline du processeur, ce qui perturbe fortement les opérations du processeur. [16] Sur un PowerPC G4 de Motorola à 800MHz, une conversion d'un int de 16 bits prend plus de 43 nanosecondes, ce qui fait 35 cycles d'exécution [17]. Pour comparaison, la plupart des instructions dans l'unité flottant de ce même processeur s'exécutent sur un cycle dans le meilleur des cas, ou sur 5 cycles pour le pire cas. [18]
Souvent dans le code de la simulation il y a des variables de type int
qui ne changent pas, ou qui changent d'une façon évidente, mais qui sont souvent utilisées dans les calculs avec des valeurs de type float
. Ceci demande une conversion à chaque fois que la variable est utilisée, et cette conversion est redondante.
Par exemple, la variable N
dans la fonction advect()
est souvent utilisée dans les expressions avec des valeurs flottantes. En ajoutant une variable Nfloat
et en faisant la conversion une seule fois avant la boucle, on économise beaucoup de conversions. Au lieu de convertir la valeur de N
plusieurs fois pendant chaque exécution de la boucle, la valeur est convertie une fois au début.
Dans la même fonction, la variable i
est dans le même cas, mais sa valeur change souvent. Mais ce changement est simple, alors il est possible de créer une variable ifloat
. Au début de la boucle, ifloat
commence avec la même valeur que i
, et à chaque étape elle est incrémentée en même temps que i
. Alors avec ce changement, il n'y a plus de conversion de la variable i
.
Dans le même ordre d'idées, on préfère les multiplications que les divisions. Encore sur le PowerPC G4, une multiplication est dans la catégorie des instructions qui prennent entre 1 et 5 cycles, mais la division peut prendre plus que 14 cycles.
La fonction lin_solve()
fait une division par la variable c
à chaque itération de sa boucle. Comme c
ne change jamais pendant cette boucle, on peut alors calculer sa réciproque, et multiplier par cette réciproque dans la boucle. Alors, on met au début de la fonction :
float cRecip = 1.0 / c;
Et puis dans la boucle, on remplace ... / c
par ... * cRecip
.




Next: Les accès mémoire Up: Optimisation de fluide Previous: Optimisation de fluide Contents Michael Ash 2005-09-21