Parameter per Pointer übergeben?



  • Es liegt schon irgendwie an der Funktion UND an den Parametern. Früher hab ich mehr Parameter übergeben, das war noch langsamer. Im Funktionscode selber weiß ich aber echt gar nichts mehr zum optimieren, ich habe durch das inline nochmal einiges rausgeholt, aber davon hat man nichts im Debug-Build.

    EDIT: Ist denn bei VS.Net ein Profiler dabei?



  • EDIT: Ist denn bei VS.Net ein Profiler dabei?

    RTFM!

    Ich ruf in meinem Game eine Funktion 150 Mio mal pro Sekunde auf, sie soll einen bool-Wert zurückliefern.

    Hoffentlich nicht 150 Mio mal den selben 🙂

    Wenn ich ne Funktion inline hab, werden dann die Parameter immer noch ganz normal übergeben

    Wenn sie tatsächlich geinlined wird, nein.

    In dem Fall ist es doch sicher besser ne globale Variable zu verwenden, oder?

    Nö.

    Sind eigentlich public static Klassenmember genauso schnell wie globale Variablen

    Genauso schnell müde? Genauso schnell besoffen? Genauso schnell beleidigt? Was ist das eigentlich für eine Frage?
    Willst du wissen, ob der Zugriff auf eine gloable Variable genauso schnell ist wie der auf eine statische Klassenvariable?
    Sicher. Bedenke: Klassen gibt es nur auf Quellcodeebene.

    Mit Pointer deutlich zu machen, das es eine Änderung geben wird? Sehr merkwürdig...

    Alte C-Schule. Angst vor Information hiding 🙂

    aber davon hat man nichts im Debug-Build.

    Im Debug-Build versucht man in der Regel auch nicht auf dieser low-level-Ebene zu optimieren. Erstmal sollte das Programm fehlerfrei laufen.



  • Willst du wissen, ob der Zugriff auf eine gloable Variable genauso schnell ist wie der auf eine statische Klassenvariable?

    Was denn bitte sonst?!

    Hoffentlich nicht 150 Mio mal den selben 🙂

    Nein ich bin noch nicht ganz bescheuert 🙂

    Ohne Profiler kannst du sowieso nichts sagen.

    Klar kann ich was ohne Profiler sagen. Ich baue an mehreren Punkten in meinem Programm Zeitmessungen ein und deshalb weiß ich, dass die Funktion der Flaschenhals ist. Und ich weiß sogar ganz genau, welche Stelle in der Funktion der Flaschenhals ist. Das kleine Problem ist, dass es inzwischen kaum noch möglich sein sollte diese Zeilen zu optimieren (ich hab sogar schon mal den Quellcode hier gepostet). Deshalb wollte ich wissen, ob man vielleicht noch am Funktionsaufruf selber etwas optimieren kann.



  • [quote=cd9000]
    p.s.:
    Ich weiß, es gibt bei VC++ __fastcall; da werden einzelne Parameter in Register gesteckt. Ich glaube aber nicht, dass das bei so einem Parameter gut funktioniert. Wenn die Funktion sehr kurz ist, kommt es im besten Fall aufs selbe wie return (bool) raus.[/quote]

    es gibt auch so ein Keyword im C++ Standard AFAIK register heisst das.

    Aber das sollte man nicht benutzen, da der Compiler eh besser wissen sollte, was er wohin steckt IMHO



  • register ist für Variablen, __fastcall für Parameter und Rückgabewerte. Kommt aber so oder so nicht gegen inline an.



  • Also, falls es noch jemanden interressiert, ich habe jetzt die Probe auf's Exempel gemacht:

    const DWORD start1 = GetTickCount();
    	for (int i = 0; i < 2000000; i++)
    		CanGo2(GoPos);
    	const DWORD time1 = GetTickCount() - start1;
    
    	const DWORD start2 = GetTickCount();
    	for (int i = 0; i < 2000000; i++)
    		CanGo(&GoPos);
    	const DWORD time2 = GetTickCount() - start2;
    

    Ergebnis: Wie von kingruedi vorhergesagt, sind Referenzen scheinbar genauso schnell wie Pointer. Der Rumpf der beiden Funktionen ist gleich, außer dass bei der Variante mit Pointer natürlich immer GoPos->x statt GoPos.x steht.

    Bleibt noch anzumerken, dass ich den Test mit dem Debug-Build gemacht habe, die Funktionen sind also nicht inline.



  • Moment mal, wie kann das sein, ich hab jetzt zum Spaß mal das Objekt by value übergeben und das braucht nur 3/4 der Zeit ??

    const DWORD start1 = GetTickCount();
    	for (int i = 0; i < 2000000; i++)
    		CanGo(GoPos);
    	const DWORD time1 = GetTickCount() - start1;
    
    	const DWORD start2 = GetTickCount();
    	for (int i = 0; i < 2000000; i++)
    		CanGo2(GoPos);
    	const DWORD time2 = GetTickCount() - start2;
    
    __forceinline bool CanGo(const PointFloat &posToGo);
    	__forceinline bool CanGo2(const PointFloat posToGo);
    

    Ich übergebe immerhin ein 40 Byte großes Objekt!
    Während time1 meist einen Wert um 12000 hat, liegt time2 bei 8900.

    Die einzige Erklärung die ich dafür hab, ist, dass der Compiler doch den Wert als Referenz übergibt (kann er ja machen wegen dem const) und noch irgendwas anderes optimiert. Die Funktionsrümpfe sind absolut identisch.



  • Zeig doch mal den relevanten Assemblercode der beiden Funktionen.



  • Werd ich mal machen. Aber ich muss die Funktion erst noch in kleinere Funktionen unterteilen (dürft ja bei inline keine Nachteile haben). Sonst kriegst du 20 Seiten Assembler-Code 🙂

    EDIT: Irgendwie war das jetzt auch eine besondere Situation. Inzwischen hab ich mit by value nur noch 1 Sekunde Vorteil auf 11 Sekunden.

    EDIT 2: Ok, Fehlalarm. Im Release-Build hat alles seine Richtigkeit. Dort ist die Funktion mit Referenz ein bisschen schneller.



  • Knuddlbaer schrieb:

    Hm, viele verwenden einen Pointer auch um deutlich zu machen das die Daten geändert werden.

    Das finde ich auch sinnvoll. const Referenz zur übergabe für nicht veränderliche Objekte und Zeiger für veränderliche. Hat keinen für mich erkennbaren Nachteil aber ermöglicht es, ohne in die Funktionsdeklaration von funktion f(bla) zu schauen, die Wirkung auf Parameter param zu erkennen:

    bla param;
    f(param); // param bleibt unverändert
    f(&param); // param wird verändert
    

    / Mibo


Anmelden zum Antworten