[C++] Float to Int : optimisation

Bonjour la zone,

je cherche une macro/fonction ASM qui fait de la conversion float -> int avec une efficacité optimale. (temps minimum) Pour des machines contemporaines.

un truc du genre: http://www.codeproject.com/useritems/ftoi…;select=1136949

Mais peut-être existe t’il mieux ? Quelqu’un s’est déjà penché sur la question ?

Comme ça a l’arrache, avec la FPU c’est l’instruction FIST ou FISTP suivant ce que tu veux faire. Avec le SSE c’est CVTPS2DQ (pour convertir 4 float à la fois. Après j’ai filé une instruction pour le SSE, mais y’en a un paquet si tu veux saturer tes valeurs ou pas, je te renvoi à la doc d’intel/amd pour plus d’info.

Mais plus sérieusement, ton compilateur sait faire ça très bien de lui même quand tu castes, alors évite comme la peste l’éNOOOOOOrme fonction que le mec a fait dans le lien. Elle est lourde (t’as vu le nombre d’instruction?), des branchements conditionnels (qui vont surement vider ton pipeline pour rien), met à 0 ses registres de manière “lente” (mov edx, 00000000h; muhargh), bref réinventage de roue inutile. Alors par pitié, laisse ton compilateur faire.

Merci pour la réponse,
je suis pour laissez cela au compilateur également.

Mais suite à une discussion avec un collègue, on voulait expérimenter certaine de ces optimisations et faire quelques bench, histoire de voir si cela pouvait nous apporter un gain notable sur notre projet.
(C’est du traitement d’image temps réel assez lourd.)

Dans tous les cas, on s’est rendu compte que faire une fonction floatToInt semble idiot, vu que la tendance est au parallélisme. B)

Et, en ce qui concerne la fonction en question, c’était à titre d’exemple. :smiley:

Tu as regardé ca?

http://www.flipcode.com/cgi-bin/fcarticles.cgi?show=64008

et surtout ca qui a l’air bien a jour:

http://www.stereopsis.com/sree/fpu2006.html

Kaboom !
Excellent lien B)
Exactement ce que je cherchais, merci beaucoup !

Déterrage de thread, mais je fais mumuse avec SSE2 et j’ai écrit ça, qui convertit des float en int par blocs de 4. D’un point de vue pratique, ça vaut quoi par rapport à un cast bête et méchant ? Je vais essayer un petit bench pour voir, mais pas ce soir il est tard. Au fait, ça passe sur x64 ça hein ? C’est juste si on utilise les instructions SSE qui utilisent des __m64 que ça pose problème ?

[code] __declspec(align(16)) float fvec[] = { 1.5f, 2.5f, 3.5f, 4.5f};
__declspec(align(16)) int ivec[4];

__m128 mf = _mm_load_ps(fvec);
__m128i mi = _mm_cvttps_epi32(mf);
_mm_store_si128((__m128i *)(ivec), mi);[/code]

4 par 4 et a la chaine ca va surement assez vite. Si jamais tu es oblige de faire un par un, ou potentiellement meme 4 par 4 au milieu d’autre chose, ca sera surement plus lent non? C’est pas le changement de mode qu’est super couteux? Enfin faut se mefier de comment ca se bench ces choses… c’est pas si evident je pense. J’ai pas d’experience directe mais de ce qu’on m’en a dit, c’est compliqué et faut y faire gaffe B)

Niveau changement de mode, d’après ce que j’ai compris, c’est un truc qui était assez embêtant avec le MMX. Car les registres du MMX utilisaient la stack de la FPU, et pour passer de l’un à l’autre fallait réinitialiser le bidule. Cependant, depuis le SSE, ce sont deux choses indépendantes et y’a normalement plus ce coût.

Mais je tiens à souligner que mes connaissances à ce niveau datent de cette nuit que j’ai passée à potasser la MSDN sur les intrinsics SSE de MSVC, et que donc ma compréhension du sujet est encore très vague. Par contre ça m’a donné envie d’en apprendre plus. En passant, voici deux liens intéressants que j’ai trouvés hier, et qui traitent du sujet. C’est un bon complément à la MSDN qui se contente d’énumérer les opcodes et les intrinsics sans trop aller dans les détails.

http://www.tommesani.com/Docs.html
http://www.agner.org/optimize/#manuals

Comme je disais j’ai pas d’experience directe si ce n’est de l’avoir vu faire de pres avec ceux du CPU de la Xbox (qui est ptet pas pareil que SSE, m’enfin on doit pas etre loin) et on m’a bien explique qu’il faut s’en mefier a mort et que c’est vraiment special les cas ou c’est interessant (streaming et process vraiment repetitif, sur des blocs a coup de 128 bits uniquement). Par exemple faire une lib de math generique pour des vecteurs/matrice en 3d qui l’utilise aurait aucun interet, ca va plus lentement. Maintenant, y a des cas ou ca dechire, faut voir pour son application et tester B)

Je suis d’accord pour le coup des 128 bits, c’est un peu l’idée de base du SSE B)

Par contre je suis perplexe quant au manque d’intérêt d’une lib générique vec/mat 3D (ou 4D pour ceux qui préfèrent avoir leurs translations dans la matrice, et puis ça rentre mieux dans 128 bits), parce que je pense que tu as suivi la discussion sur sweng y’a quelques mois, et tout le monde avait l’air plutôt convaincu de l’intérêt du SIMD dans ce cas précis.

Si jamais t’arrives à coincer un des gourous du CPU XBox dont tu parles entre la photocopieuse et la machine à café, demande-lui si il a une piste pour de bonnes références (didactiques) à lire sur le sujet. Parce que pour trouver de la doc correcte sur le site de Intel, il me faudrait un chien d’avalanches (et le tonnelet de gin qui va avec).

Ha bah non j’ai pas suivit la discussion sur sweng, mais on a des resident experts gourous CPU en local et on a verifie, et il me semble que le gars qui fait la lib math chez nous en a conclu que y a pas moyen de faire une lib generique (de base hein, pas un truc complexe) qui soit plus rapide. Justement on etait etonne apres verification que ca aille pas plus vite, parceque tout le monde semblait effectivement persuade de l’interet de la chose. C’est d’ailleurs la seule raison pour laquelle j’en ai entendu parler et j’y croyais pas donc on m’a montre sur un exemple de multiplication de matrices et a la Saint Thomas, je l’avais sous les yeux (me rapelle plus le scenario exact, c’etait ptet un cas particulier). Apres je pense que tout depend de ce que tu fais et comment, en particulier si t’implemente toute la BLAS doit y avoir plein de cas ou ca peut servir. Avec l’architecture PC c’est ptet pas pareil aussi. M’enfin donc : mefiance c’est tout ce que je voulais dire a la base.

Je demanderais pour le references.

Ah bah tiens, finalement j’ai trouvé un truc sur le site de Intel : http://www.intel.com/cd/ids/developer/asmo…/code/20460.htm

Mais comme d’habitude, niveau documentation, y’a quasiment rien. B)

Un truc qui est sure, c’est que quelque soit la machine et le compilo, tu a 73% de chances que le compilo fasse un truc trops complique…

sur PC, j’ai longtemps utilise le fistp facons : (code gaulle sur gamedev).

inline int __stdcall _ftoi(float x)
{
int r;
__asm fld x
__asm fistp dword ptr r;
return r;
}

et equivalent sur les autres platformes.

le seul problem c’est que ca passe par la memoire : il n’y a quasiment jamais de moyen facile de bouger d’un registre FPU vers un registre CPU sans passe par la memoire.
Apres il y a aussi d’autre bidouilles utilisant la representation IEEE dont je ne retrouve plus la trace…

Exact, à cause de la façon dont le comportement de _ftol est spécifié par le standard ANSI C.
Cependant, pas besoin de se donner du mal, y’a un switch du compilo qui fait juste ça, c’est “/QIfist” : http://msdn2.microsoft.com/en-us/library/6…1d2(VS.80).aspx

edit : euh oui en fait juste sur MSVC hein… tu bosses sur cell toi non ?

entre autre, sur PPC en general on va dire B)

(mais une chose est sure : mon MIPS me manque… haaaa le MIPS… c’etait bien ca…)

Pour les opérations de bases les CPU sont ultra optimisés pas la peine de faire des trucs à la mort moi le noeud. Par exemple tu ne batteras pas un rep movsb sur de petites copies de mémoire, pas la peine de faire des movntq [edi], mm0 blah.

Je ne peux pas m’empecher mais : si, meme sur de petite operations memoire, tu peux faire mieux qu’un rep movsb…
la vrais question est : est-ce que ca vaux le coup de se faire chier, mais ca, c’est un debat pour un autre jour B)

Donne moi le code et le benchmark.

rep movsd
pour le benchmark : j’ai pas le temps, et j’ai passe l’age des concours de bites en plus B)

rep movsd n’est pas plus performant que rep movsb sur les machines actuelles, d’ailleurs tu regarderas la sortie des compilateurs recents pour les tailles de quelques octets en optimisation a fond les manettes ils ne font plus de rep movsd rep movsb. Je pense que c’est du au fait que le rep movsd implique un stall sur le coup d’apres pour le reliquat de quelques octets, stall ou tu pourrais faire d’autres choses… Pis, a modulo 4, sur mes benches court le rep movsd ne changeait rien. Optimisation en catimini du compilateur qui attend d’en avoir assez pour faire la copie ideale? Possible cher ami.

Je me souviens qu’a l’epoque j’avais teste et reteste dans tous les sens parce que j’avais du mal a digerer que le rep movsb faisait mieux que ma copie non temporelle cache-through avec utilisation de la localite de la page. Un grand moment de debug cette routine, mais comment que je frimais sur la Riviera. La vie est dure et depuis je suis devenu vendeur dans un magasin de tuning auto dans la region lilloise et je me remets doucement de cette epreuve.