Pourquoi la vitesse de ce solveur SOR dépend-elle de l’entrée?

En lien avec mon autre question , j’ai maintenant modifié le solveur masortingciel crépu pour utiliser la méthode SOR (successive over-relaxation). Le code est maintenant comme suit:

void SORSolver::step() { float const omega = 1.0f; float const *b = &d_b(1, 1), *w = &d_w(1, 1), *e = &d_e(1, 1), *s = &d_s(1, 1), *n = &d_n(1, 1), *xw = &d_x(0, 1), *xe = &d_x(2, 1), *xs = &d_x(1, 0), *xn = &d_x(1, 2); float *xc = &d_x(1, 1); for (size_t y = 1; y < d_ny - 1; ++y) { for (size_t x = 1; x < d_nx - 1; ++x) { float diff = *b - *xc - *e * *xe - *s * *xs - *n * *xn - *w * *xw; *xc += omega * diff; ++b; ++w; ++e; ++s; ++n; ++xw; ++xe; ++xs; ++xn; ++xc; } b += 2; w += 2; e += 2; s += 2; n += 2; xw += 2; xe += 2; xs += 2; xn += 2; xc += 2; } } 

Ce qui est étrange, c’est que si j’augmente omega (le facteur de relaxation), la vitesse d’exécution commence à dépendre de façon spectaculaire des valeurs contenues dans les différents tableaux!

Pour omega = 1.0f , le temps d’exécution est plus ou moins constant. Pour omega = 1.8 , la première fois, il faudra généralement 5 millisecondes pour exécuter cette step() 10 fois, mais ce nombre passera progressivement à près de 100 ms au cours de la simulation. Si je mets omega = 1.0001f , le temps d’exécution augmente légèrement; plus l’ omega est élevé, plus le temps d’exécution sera rapide pendant la simulation.

Puisque tout cela est intégré au solveur de fluide, il est difficile de trouver un exemple autonome. Mais j’ai sauvegardé l’état initial et réexécuté le résolveur sur cet état à chaque pas temporel, ainsi que la résolution du pas temporel réel. Pour l’état initial, il était rapide, pour les pas de temps suivants, de plus en plus lent. Puisque tout le rest est égal, cela prouve que la vitesse d’exécution de ce code dépend des valeurs de ces six tableaux.

Ceci est reproductible sur Ubuntu avec g ++, ainsi que sur Windows 7 64 bits lors de la compilation 32 bits avec VS2008.

J’ai entendu dire que les valeurs NaN et Inf peuvent être plus lentes pour les calculs en virgule flottante, mais qu’aucun NaN ni Inf n’est présent. Est-il possible que la vitesse des calculs de float dépende autrement des valeurs des nombres entrés?

La réponse courte à votre dernière question est “oui” – les nombres dénormalisés (très proches de zéro) nécessitent un traitement spécial et peuvent être beaucoup plus lents. J’imagine qu’ils s’insinueront dans la simulation avec le temps. Voir cet article SO relatif: Temps d’exécution des calculs en virgule flottante

Définir le contrôle à virgule flottante pour effacer les dénormaux à zéro doit permettre de résoudre les problèmes tout en minimisant la qualité de la simulation.

La réponse de Celion s’avère être la bonne. Le message auquel il renvoie dit d’activer la mise à zéro des valeurs dénormalisées:

 #include  _controlfp(_MCW_DN, _DN_FLUSH); 

Cependant, il s’agit uniquement de Windows. En utilisant gcc sous Linux, j’ai fait la même chose avec un souffle d’assemblage en ligne:

 int mxcsr; __asm__("stmxcsr %0" : "=m"(mxcsr) : :); mxcsr |= (1 << 15); // set bit 15: flush-to-zero mode __asm__("ldmxcsr %0" : : "m"(mxcsr) :); 

Ceci est mon premier assemblage x86, donc il peut probablement être amélioré. Mais ça fait l'affaire pour moi.