kann diese funktion noch optimiert werden?



  • Hi,

    ich habe eine funktion die äquivalent zu (int)floor(value) ist in assembler. die ist auch deutlich schneller als die normale mit dem cast. Problem ist nur das ich floor mehrere tausend male aufrufe und diese funktion jetzt nur noch der eigentliche bottleneck ist.

    inline int Floor2Int( const float value )
    {
       static int CtrlwdHolder;
       static int CtrlwdSetter;
       static int RetVal;
    
       __asm 
       {
          fld    value			// push 'a' onto the FP stack
          fnstcw CtrlwdHolder		// store FPU control word
          movzx  eax, CtrlwdHolder	// move and zero extend word into eax
          and    eax, 0xFFFFF3FF	// set all bits except rounding bits to 1
          or     eax, 0x00000400	// set rounding mode bits to round down
          mov    CtrlwdSetter, eax	// Prepare to set the rounding mode -- prepare to enter plaid!
          fldcw  CtrlwdSetter		// Entering plaid!
          fistp  RetVal				// Store floored and converted (to int) result
          fldcw  CtrlwdHolder		// Restore control word
       }
    	return RetVal;
    }
    

    kann man da nochwas rausholen? Gibts da evtl. was aus SSE oder geht das nur per FPU?



  • Saug dir bei Intel das Optimization Manual, da ist so eine Funktion drin.

    Mit SSE geht's aber auch, soweit ich weiß.



  • vor fistp sollte man frndint aufrufen, damit auch was gerundet wird! 😉


  • Mod

    Power Off schrieb:

    vor fistp sollte man frndint aufrufen, damit auch was gerundet wird! 😉

    nein.

    inline unsigned short defaulCtrlW()
    {
        __asm
        {
            fnstcw    word ptr [ esp - 4 ]
            movzx     eax, word ptr [ esp - 4 ]
        }
    }
    inline int Floor2Int( const float value )
    {
        static const unsigned short defaultCtrl = defaulCtrlW();
        static const unsigned short floorCtrl = ( defaulCtrlW() & 0xf3ff ) | 0x0400;
        __asm
        {
            fld    value
            fldcw  floorCtrl
            fistp  dword ptr [ esp - 4 ]
            fldcw  defaultCtrl
            mov    eax, [ esp - 4 ]
        }
    }
    

    oder auch

    inline void initMXCSR()
    {
        __asm
        {
            stmxcsr [ esp - 4 ]
            and     [ esp - 4 ], 0xffff9ffff
            or      [ esp - 4 ], 0xffff2ffff
            ldmxcsr [ esp - 4 ]
        }
    }
    inline int Floor2IntSSE(const float value)
    {
        __asm
        {
            cvtss2si eax, value
        }
    }
    

    und am besten

    #include "xmmintrin.h"
    inline void initMXCSR()
    {
        _MM_SET_ROUNDING_MODE( _MM_ROUND_DOWN );
    }
    inline int Floor2IntSSE(const float value)
    {
        return _mm_cvtss_si32( _mm_load_ss( &value ) );
    }
    


  • camper schrieb:

    nein.

    Echt jetzt? Davon steht aber nix in der Doku, jedenfalls wird's nicht ausdruecklich erwaehnt, nur in der Wertetabelle zum Befehl fistp steht, dass der Wert je nach Rundungsmodus unterschiedlich ausfallen kann. Komisch!

    Wozu gibt's dann den frndint-Befehl ueberhaupt? Um Zwischenergebnisse zu runden?


  • Mod

    na wenn das so in der dekumentation steht ist es doch eindeutig genug. frndint brauchst du eben, wenn du runden willst, aber es trotzdem ein gleitkommaformat bleiben soll.



  • Hi,

    hab eine frage: was bewirkt das hier?

    inline void initMXCSR() 
    { 
        __asm 
        { 
            stmxcsr [ esp - 4 ] 
            and     [ esp - 4 ], 0xffff9ffff 
            or      [ esp - 4 ], 0xffff2ffff 
            ldmxcsr [ esp - 4 ] 
        } 
    }
    

    ?


  • Mod

    dasselbe wie die entsprechende funktion mit intrinsics (du kannst sie ohne weiteres gegeneinanderaustauschen). das mxcsr register ist im grunde analog zum control register der fpu, nur etwas anders aufgebaut und die rc bits sind an anderer stelle. anders als die fpu register wird es allerdings nicht ständig durch den compiler geändert (was der grund ist, warum die fpu variante so langsam ist, der p4 z.b. ist darauf optimiert, zwischen zwei rundungsmodi (relativ = 14takte) schnell umzuschalten, und diese rundungsmodi sind normalerweise round to nearest (beim rechnen) und chop (beim cast zu int). du benutzt aber einen dritten modus, und das kostet (153 takte beim P4!!), man könnte also versucht sein, stattdessen round to nearest zu nehmen (default) und per bedingten sprung positive und negative werte getrennt zu behandeln, das müsste dann schneller sein.

    weil mxcsr nicht ständig geändert wird, müsste es genügen diese funktion einmal aufzurufen und dann munter drauf los zu runden (was nur noch ein einzelner befehl ist).



  • nur mal so am rande: deine inline void initMXCSR() funktion veranlasst einen runtimeerror


Anmelden zum Antworten