Inline Ersetzung funzt nicht 100%



  • Hallo,

    Folgende Problemstellung:

    class Integer
    {
    public:
    	Integer(void); 
    	Integer(const int value);
    	Integer(const Integer &var);
    	~Integer(void);
    
            int operator + (Integer var) const;
    
    	const Float sepp() const;
    // cast operatoren
    	operator Float() const; // kein schreibfehler!!! Float pendant zu float wie Integer zu int
    
    private:
    	int value;
    };
    
    inline const Float Integer::sepp() const{
    	return value;
    }
    
    inline int Integer::operator + (Integer var) const
    {
    	return (this->value + var.value);
    }
    
    //V 1
    inline Integer::operator Float() const
    {	
    	const Float puff(value);
    	return puff;
    }
    //V 2 (liefern beide das gleiche problem)
    inline Integer::operator Float() const
    {
    	return value;
    }
    

    Diese Klasse ist natuerlich noch groesser, was aber fuer die Frage belanglos ist.
    Main vollstaendig:

    int main(void)
    {
    	Integer i(5);
    	Integer j(6);
    	Float f(3.7f);
    	Char *c = new Char[100];
    	Double d(7.3849);
    	Double dd(2.4233);
    	utils::StopWatch *sw = new utils::StopWatch();
    	volatile int k=0;
    	double time;
    	ofstream file("inlineRTTI.csv", ios::out|ios::binary|ios::beg);
    	int l=0;
    	while (l < 100)
    	{
    		sw->reset();
    		sw->start();
    		while(k < 4000000000)
    		{
    			i += 1;
    			i += j+2;
    			i -= 3;
    			i -= j+3;
    			i *= 4;
    			--i;
    			i *= j+4;
    			i /= 6;
    			i /= j+5;
    			++i; 
    
    			f +=   (Float) i; // <------ !!!!!!!!!!! operator Float() const 
    			f = f + 0.3f;
    			f += 2.1f;
    			f -= 1.2f;
    			f /= 0.234f;
    
    			c[0] = i+1;
    			c[1] = i+2;
    
    			if (i == j)
    				f  = 9.34f;
    			else
    				i = 345;
    
    			d /= dd;
    			d *= dd;
    			d += dd;
    			d -= dd; //*/
    
    			++k;
    		}
    
    		time = sw->getTime();
    		file << time << ";" << endl;
    		k=0;
    		++l;
    	}
    	file.close();
    	cout << i << j << c << f << d << dd;
    /*	cout << "fertig" << endl;
    	char fake[100];
    	cin >> fake;*/
    	return 0;
    }
    

    Bei der makierten Zeile wird entsprechend der cast operator Aufgerufen. Dieser ist allerdings Inline definiert und sollte bei den entsprechenden optimierungseinstellungen ersetzt werden.

    Ich benutze den VC++ 7, mit den einstellungen:
    Full Optimization (/Ox)
    Global Optimizations yes (/Og)
    Inline Function Expansion only _inline ODER any siutable
    Favor Fast Code

    Die Inline Ersetzung sollte also an sein. Bei funktionen die eine Referenz auf sich selbst zurueckgeben und ansonsten nicht viel machen (siehe operator +) passiert dies auch, nur bei dem Cast operator bzw. bei Methoden die Beispielsweise in der Methodendefinition Objekte erstellen (siehe operator Float() const) wird immer noch ein call (sowohl Variante V1 als auch V2 und bei Integer::sepp()) ausgefuehrt:

    ; 50   : 			f +=   (Float) i;
    
    	lea	ecx, DWORD PTR $T109043[esp+216]
    	lea	esi, DWORD PTR [edx+eax+1]
    	push	ecx
    	lea	ecx, DWORD PTR _i$[esp+220]
    	mov	DWORD PTR _i$[esp+220], esi
    	call	??BInteger@@QBE?AVFloat@@XZ		; Integer::operator Float <-- das ist schlecht / langsam
    
    ; 50   : 			f +=   i.sepp();
    	lea	ecx, DWORD PTR $T109036[esp+224]
    	lea	esi, DWORD PTR [edx+eax+1]
    	push	ecx
    	lea	ecx, DWORD PTR _i$[esp+228]
    	mov	DWORD PTR _i$[esp+228], esi
    	call	?sepp@Integer@@QBE?BVFloat@@XZ		; Integer::sepp <-- analog zu oberen
    

    gibt es eine Moeglichkeit die Methoden anders zu formulieren so dass entsprechend eine ersetzung anstatt eines sprunges vorgenommen wird / bzw gibt es eine Kompilereinstellung die dies bezweckt? (die Klasse soll in Float castbar sein (nicht float))

    (der call macht die ganze sache ziemlich langsam)

    thx for help[code]



  • Nunja, inline ist ja nur eine Empfehlung an den Compiler. Ob er wirklich inlined, ist letztendlich seine Sache. Den einzigen Tipp, den ich dir im Moment geben kann, ist, probier es mal mit Compilerflag /O2 statt /Ox. Ansonsten wäre da noch __forceinline, ist allerdings compilerspezifisch und der MSC wird das vermutlich auch nicht grossartig anders handeln als inline.



  • beide Optimierungsstufen wie auch __forceinline und __inline machen genau das gleiche



  • inline ist nur eine Empfehlung - wenn der Compiler meint, daß dein Programm ohne inline schneller ist, wird er die Funktion in jedem Fall normal erstellen.

    Und der operator Float scheint so ein Kandidat zu sein (könnte mit der impliziten Typ-Umwandlung zusammenhängen - oder hast du einen Float::Float(int) Ctor?)



  • ne hat ich nicht aber natuerlich ein Float(float) und da es auch einen Integer::operator int() gibt macht er bei
    Integer i(5);
    Float f = i;
    auch den weg ueber die kette
    Integer->int->float->Float
    was aber nicht sinn und zweck der sache ist da ja von int und float abstrahiert werden soll. deswegen sollte ein Integer->Float moeglich sein
    mit

    inline Integer::operator const Float &() const
    {
    const Float puff(value);
    const Float & boing = puff;
    return boing;
    }

    macht ers jetzt richtig 🙂
    problem geloest



  • ADOOM schrieb:

    auch den weg ueber die kette
    Integer->int->float->Float

    Solange du keine direkte Umwandlung definierst, gehst du auf jeden Fall über diese Kette.

    inline Integer::operator const Float &() const
    {	
    	const Float puff(value);
    	const Float & boing = puff;
    	return boing;
    }
    

    Auch wenn du dir die zusätzliche Referenz dort sparen könntest - das ist auch eine Möglichkeit.

    PS: Ist es dir wirklich so wichtig, was da im Untergrund passiert? Wenn es dir so auf Geschwindigkeit ankommt, verzichte lieber auf die Wrapper-Klassen.

    PPS: Schonmal Optimierung auf Größe (/Os) versucht?



  • 1. jop die Wrapper sind absicht
    2. die wrapper waren bisher genauso schnell wie die entsprechenden primitiven datentypen
    3. wenns nicht langsamer waere (faktor 10) waer der thread auch nicht hier entstanden (die kompilersettings auf speed etc. habe ich natuerlich auch vorher probiert)

    wenns so ist wie bisher sollten diese wrapper klassen vom speed her identisch sein mit den primitiven typen (alles deutet im mom darauf hin)

    thx





  • es wurde MsVC 7.1 (2003 Net) verwendet - Professional Edition


  • Mod

    ADOOM schrieb:

    beide Optimierungsstufen wie auch __forceinline und __inline machen genau das gleiche

    fast. ich bin ein einziges mal bewusst über einen fall gestolpert, bei dem __forceinline tatsächlich etwas genutzt hat.

    der grund, warum vc++7.1 hier den operator nicht inlined, hat mit exceptions zu tun. eine function, die ein objekt mit nicht-trivialem destruktor zurück gibt, wird niemals inline-expandiert (selbst wenn die funtion und alle member funktionen des objekts mit leerer exception-spezifikation definiert wird). in diesem falle ist ein selbst definierter destruktor allerdings auch völlig überflüssig...


  • Mod

    inline Integer::operator const Float &() const
    {	
    	const Float puff(value);
    	const Float & boing = puff;
    	return boing;
    }
    

    eine referenz auf eine locale variable zurückgeben? wohl kaum...
    man könnte eine statische variable verwenden:

    inline Integer::operator const Float &() const
    {	
    	static Float puff;
            puff = value;
    	return puff;
    }
    

    aber die funktion ist dann nicht mehr reentrant - und das ist bei konvertierungsoperatoren so gut wie immer inakzeptabel. eine referenz zurückzugeben, wenn es ein objekt sein muss ist immer ein fehler.


Anmelden zum Antworten