Operatoren langsam, wie so...?



  • orkun schrieb:

    Warum sind eigentlich operatoren langsamer als "normale" funktionen...?...

    Da Operatoren normale Funktionen sind, sind sie auch nicht langsamer. 😃

    Gruß,

    Simon2.



  • Okay, dann muss ich wohl meine Frage anders formulieren...

    Warum wird in Real Time Rendering oder Physik Engines auf operatoren verzichtet...?

    Beispielsweise Havok Vectorklasse sieht so aus:

    00001 #ifndef HAK_MATH_VECTOR3_H
    00002 #define HAK_MATH_VECTOR3_H
    00003 
    00004 #ifndef HK_MATH_VECMATH_H
    00005 #error Include <hk_math/vecmath.h> Do not include this file directly.
    00006 #endif // HK_MATH_VECMATH_H
    00007 
    00008 namespace Havok { class Vector3; }
    00009 
    00010 struct hkVector3ExpressionPlus;
    00011 struct hkVector3ExpressionMinus;
    00012 
    00013 #define HK_REF &
    00014 #define Const //const
    00015 #define ConsT const
    00016 
    00017 class hk_Vector3
    00018 {
    00019         public:
    00020 
    00021                 HK_DECLARE_NONVIRTUAL_CLASS_ALLOCATOR(HK_MEMORY_CLASS_CONSTRAINT, hk_Vector3)
    00022 
    00023                 inline hk_Vector3();
    00024                 inline hk_Vector3(hk_real a, hk_real b, hk_real c);
    00025                 inline hk_Vector3(const double*);
    00026                 inline hk_Vector3(const float*);
    00027 
    00028                 inline hk_Vector3( const hk_Vector3& v);
    00029                 inline void operator=  (const hk_Vector3& v);
    00030 
    00031                 /* expression operators */
    00032                 inline hk_Vector3(ConsT hkVector3ExpressionPlus HK_REF v);
    00033                 inline void operator= (ConsT hkVector3ExpressionPlus HK_REF v);
    00034                 inline hk_Vector3(ConsT hkVector3ExpressionMinus HK_REF v);
    00035                 inline void operator= (ConsT hkVector3ExpressionMinus HK_REF v);
    00036 
    00037                 /* accumulation operators */
    00038                 inline void operator=  (const Havok::Vector3&); //<todo> remove me
    00039                 inline void operator+= (const hk_Vector3& a);
    00040                 inline void operator-= (const hk_Vector3& a);
    00041                 inline void operator*= (hk_real a);
    00042 
    00043                 inline void set(hk_real a, hk_real b, hk_real c);
    00044                 inline void set_zero();
    00045 
    00046                 /* arithmetic operations - fast! */
    00047                 inline void set_add(const hk_Vector3& a, const hk_Vector3& b);
    00048                 inline void set_sub(const hk_Vector3& a, const hk_Vector3& b);
    00049                 inline void set_cross(const hk_Vector3& a, const hk_Vector3& b);
    00050 
    00051                 inline void set_mul(hk_real r, const hk_Vector3& a);
    00052                 inline void set_mul3(const hk_Diagonal_Matrix& a, const hk_Vector3& b);
    00053                 inline void set_mul3( const hk_Matrix3& a, const hk_Vector3& b ); 
    00054                 inline void add_mul(hk_real r, const hk_Vector3& a);
    00055                 inline void set_interpolate( const hk_Vector3& a, const hk_Vector3& b, hk_real t);
    00056 
    00057                 /* transform */
    00058                 void set_rotated_dir    (const hk_Rotation& a, const hk_Vector3& b);
    00059                 void set_rotated_inv_dir(const hk_Rotation& a, const hk_Vector3& b);
    00060 
    00061                 void set_transformed_pos    (const hk_Transform& a, const hk_Vector3& b);
    00062                 void set_transformed_inv_pos(const hk_Transform& a, const hk_Vector3& b);
    00063     
    00064                 /* inline versions of above */
    00065                 inline void _set_rotated_dir    (const hk_Rotation& a, const hk_Vector3& b);
    00066                 inline void _set_rotated_inv_dir(const hk_Rotation& a, const hk_Vector3& b);
    00067 
    00068                 inline void _set_transformed_pos    (const hk_Transform& a, const hk_Vector3& b);
    00069                 inline void _set_transformed_inv_pos(const hk_Transform& a, const hk_Vector3& b);
    00070 
    00071                 /* length and distance */
    00072                 inline hk_real dot(const hk_Vector3& a) const;
    00073                 inline hk_real length() const;
    00074                 inline hk_real length_inv() const;
    00075                 inline hk_real length_squared() const;
    00076 
    00077                 inline hk_real distance_squared_to( const hk_Vector3 &) const;
    00078                 inline hk_real distance_to( const hk_Vector3 &) const;
    00079 
    00080                 inline void normalize();
    00081                 inline hk_real normalize_with_length();
    00082                 //void fast_normalize_e10(); // 10 bits valid
    00083 
    00084         /* element access */
    00085             inline hk_real& operator() (int a);
    00086                 inline const hk_real& operator() (int a) const;
    00087 
    00088                 inline       hk_real* get_real_pointer() { return &x; }
    00089                 inline const hk_real* get_real_pointer() const { return &x; }
    00090 
    00091         public:
    00092 
    00093                 hk_real HK_ALIGNED_VARIABLE(x,16);
    00094                 hk_real y;
    00095                 hk_real z;
    00096                 hk_real w;
    00097 };
    00098 
    00099 inline Const hkVector3ExpressionPlus operator+ (const hk_Vector3& a, const hk_Vector3& b);
    00100 inline Const hkVector3ExpressionMinus operator- (const hk_Vector3& a, const hk_Vector3& b);
    00101 
    00102 #endif // HAK_MATH_VECTOR3_H
    


  • was willst du ? hier werden doch genauso operatoren verwendet

    Meep Meep



  • orkun schrieb:

    ...
    Warum wird in Real Time Rendering oder Physik Engines auf operatoren verzichtet...?

    Beispielsweise Havok Vectorklasse sieht so aus:

    Also ich sehe da sehr viele Operatoren...
    (operator=, operator+=, operator-=, operator*=, operator(), operator+, operator-...)

    cu André



  • Okay, also ihr denkt der Author hatte langeweile beim implementieren und kommentieren der Methoden:

    00046                 /* arithmetic operations - fast! */
    00047                 inline void set_add(const hk_Vector3& a, const hk_Vector3& b);
    00048                 inline void set_sub(const hk_Vector3& a, const hk_Vector3& b);
    00049                 inline void set_cross(const hk_Vector3& a, const hk_Vector3& b);
    00050 
    00051                 inline void set_mul(hk_real r, const hk_Vector3& a);
    00052                 inline void set_mul3(const hk_Diagonal_Matrix& a, const hk_Vector3& b);
    00053                 inline void set_mul3( const hk_Matrix3& a, const hk_Vector3& b ); 
    00054                 inline void add_mul(hk_real r, const hk_Vector3& a);
    00055                 inline void set_interpolate( const hk_Vector3& a, const hk_Vector3& b, hk_real t);
    

    die sind wohl nur zufällig da... alles klar...



  • Vielleicht solltest du mal die Implementierung der Operatoren und Methoden miteinander vergleichen (da die als 'inline' definiert sind, solltest du sie auch vorliegen haben).

    (PS: Vielleicht ist set_add() auch nur schneller, weil es zwei Vektoren auf einen Schlag aufaddieren kann - oder der Autor hatte tatsächlich Langeweile (oder keine Ahnung))



  • Dir ist schon klar, dass diese Funktionen durchwegs 3 Parameter haben während die Operatoren nur 2 Parameter haben?

    Ich weiß nicht was ein set_add macht, aber es verlangt 3 hk_Vector3 Objekte. Das geht mit einem + schwer. Dass ein

    add(a,b,c)
    uU schneller sein kann als ein
    add(a, add(b,c))
    sollte der Verstand von alleine erklären können.

    PS:
    ein operator ist eine stinknormale funktion die für uns programmierer einfach nur etwas anders aussieht.

    wir können zwar a+b schreiben, aber der compiler sieht hier ein a.operator+(b) oder ein operator+(a,b) - je nachdem. ersetzen wir den namen "operator+" nun durch "foo":
    foo(a,b)
    sieht es doch fast wie eine normale funktion aus, oder?



  • orkun schrieb:

    Okay, also ihr denkt der Author hatte langeweile beim implementieren und kommentieren der Methoden:

    00046                 /* arithmetic operations - fast! */...
    

    die sind wohl nur zufällig da... alles klar...

    Vorab: Meinst DU wirklich, mit einem genervten Grundton läuft die Diskussion besser ?

    @Topic: Ich wette, dass dieser Kommentar gar nichts mit Sprachfeatures/Eigenschaften zu tun hat, sondern der Autor (höchstens) eine optimierte Implementierung mit diesen Namen belegt hat.
    Genauso könnte da auch stehen:

    00046                 /* arithmetic operations - slow! */...
    

    Gruß,

    Simon2.



  • orkun schrieb:

    Okay, also ihr denkt der Author hatte langeweile beim implementieren und kommentieren der Methoden:

    00046                 /* arithmetic operations - fast! */
    00047                 inline void set_add(const hk_Vector3& a, const hk_Vector3& b);
    00048                 inline void set_sub(const hk_Vector3& a, const hk_Vector3& b);
    00049                 inline void set_cross(const hk_Vector3& a, const hk_Vector3& b);
    00050 
    00051                 inline void set_mul(hk_real r, const hk_Vector3& a);
    00052                 inline void set_mul3(const hk_Diagonal_Matrix& a, const hk_Vector3& b);
    00053                 inline void set_mul3( const hk_Matrix3& a, const hk_Vector3& b ); 
    00054                 inline void add_mul(hk_real r, const hk_Vector3& a);
    00055                 inline void set_interpolate( const hk_Vector3& a, const hk_Vector3& b, hk_real t);
    

    die sind wohl nur zufällig da... alles klar...

    Ich glaube du bist ein bisschen doof. Welche dieser Funktionen würdest du denn durch einen überladenen Operator ersetzen? Und welchen? Und wie?
    Willst du statt set_add einen operator + (std::pair<hk_Vector3 const&, hk_Vector3 const&>) machen oder wie stellst du dir das vor?



  • hustbaer schrieb:

    Ich glaube du bist ein bisschen doof. Welche dieser Funktionen würdest du denn durch einen überladenen Operator ersetzen? Und welchen? Und wie?
    Willst du statt set_add einen operator + (std::pair<hk_Vector3 const&, hk_Vector3 const&>) machen oder wie stellst du dir das vor?

    ich denkmal das 'set_add' den operator+ und den operator= ersetzen soll.
    ich glaub der programmierer hat den aufwand mit den funktionen deshalb betrieben, um temporaere objecte zu vermeiden.

    bin mir fast sicher das das ungefaehr so aussieht:

    class hk_Vector3;
    
    class hkVector3ExpressionPlus
    {
       public:
          hkVector3ExpressionPlus(const hk_Vector3 &v1, const hk_Vector3 &v2) : vec1(v1), vec2(v2) { }
    
       const hk_Vector3 &vec1, &vec2;
    };
    
    inline const hkVector3ExpressionPlus operator+ (const hk_Vector3& a, const hk_Vector3& b)
    {
       return hkVector3ExpressionPlus(a,b);
    } 
    
    class hk_Vector3
    {
       public:
          ...
          /* expression operators */
          inline void operator= (ConsT hkVector3ExpressionPlus HK_REF v)
          {
             /* hier kommt der teil den ich mir denke */
             set_add(v.vec1, v.vec2);
          } 
          ...
          /* arithmetic operations - fast */
          ...
          inline void set_add(const hk_Vector3& a, const hk_Vector3& b)
          {
             /* hier wird er wahrscheinlich die addition und die zuweisung machen */
          }
          ...
    };
    
    /* damit kann man nu folgendes schreiben: */
    hk_Vector3 a,b,c;
    
    a = b + c; /* <- schlussendlich wird dann hier vom kompiler implizit die 'set_add'-memberfunktion eingesetzt. 
    somit wird das temporaere object, welches von 'b + c' erzeugt werden wuerde, vermieden. deshalb wahrscheinlich der kommentar mit 'fast'*/
    

    und nachdem ich grad so schoen am traeumen bin, geh ich jetz schlafen.

    gute nacht

    Meep Meep



  • @Meep Meep
    jep, denke ich auch, die dinger werden ja auch "expression operators" genannt. imho eine sehr geile idee, komplexe operationen auf diese Weise effizient und lesbar zu machen.



  • Hah, hab ich wieder mal das offensichtliche übersehen 🙂
    Trotzdem würde ich das nicht so machen wenn ich will dass es unbedingt und auf jeden Fall schnell geht... ich persönlich finde da die "set_add" Funktion besser.



  • orkun schrieb:

    Warum sind eigentlich operatoren langsamer als "normale" funktionen...?

    In der Theorie nicht, in der Praxis leider schon. Das hat vor allem mit den von Meep Meep bereits angesprochenen temporären Objekten zu tun, die Compiler nicht vollständig eliminieren können. Dort gab es immer mal wieder diverse Lösungsansätze. Alexandrescu hat auch mal etwas dazu verfasst, Stichwort Mojo. Ein bekannte Lösung für binäre Operatoren sind Expression Templates. Allerdings ist sowas weder elegant zu implementieren, noch einfach zu warten. Jedenfalls kann das ziemlich komplexe Ausmasze annehmen.

    Sry wenn dich einige hier anmachen, aber deine Frage ist durchaus berechtigt.

    orkun schrieb:

    ich möchte eine eine 3D Vectorklasse schreiben, lohnt es sich mit SSE oder mit 3DNow! zu implementieren?

    SSE bzw. 3DNow lohnt sich immer. Ob man das selber implementiert, hängt von den Fähigkeiten deines Compilers ab.

    orkun schrieb:

    Welche operationen sollte ich als inline assembler implementieren?

    Gar keine. Aktuelle Compiler sollten entsprechende Intrinsics kennen.



  • groovemaster schrieb:

    orkun schrieb:

    Warum sind eigentlich operatoren langsamer als "normale" funktionen...?

    In der Theorie nicht, in der Praxis leider schon. Das hat vor allem mit den von Meep Meep bereits angesprochenen temporären Objekten zu tun, die Compiler nicht vollständig eliminieren können. Dort gab es immer mal wieder diverse Lösungsansätze. Alexandrescu hat auch mal etwas dazu verfasst, Stichwort Mojo. Ein bekannte Lösung für binäre Operatoren sind Expression Templates. Allerdings ist sowas weder elegant zu implementieren, noch einfach zu warten. Jedenfalls kann das ziemlich komplexe Ausmasze annehmen.

    Sry wenn dich einige hier anmachen, aber deine Frage ist durchaus berechtigt.

    Ist sie finde ich nicht. (Ich vor allem habe mich auch am Ton des OP mehr gestossen als an seiner Frage. Etwas nicht zu wissen und zu fragen ist OK, auf richtige Antworten dann aber patzig zu werden ... vertrage ich nicht ganz.)

    Ein überladener Operator ++ ist nicht langsamer als eine "increment" Memberfunktion.
    Ein überladener Operator += ist auch nicht langsamer als eine "add" Memberfunktion.
    Beides sind üblicherweise Memberfunktionen und werden ganz genau gleich aufgerufen.

    D.h. solange man nicht anfängt Äpfel mit Birnen zu vergleichen...

    Ein Aufruf von Operator + der ein Temporary zurückliefert + ein Aufruf von Operator = mit diesem Temporary als Argument, dann vielleicht noch darauf besteht dass Operator = eine Referenz auf *this zurückliefert ... wenn du das mit dem Aufruf einer einzigen Funktion die void zurückliefert vergleichen willst ... ich finde den Vergleich auf jeden Fall unsinnig.

    ----

    Wo ich dir natürlich zustimme: mit überladenen Operatoren kann man schwerer optimieren als mit Memberfunktionen. Was aber einfach daran liegt dass Operatoren eine vorgegebene Anzahl an Parametern haben, und Memberfunktionen nicht. Wo wir dann auch wieder bei den Äpfeln und Birnen wären, man soll eben keinen Apfel den Job einer Birne machen lassen. 😃



  • Es geht in diesem Thread um Optimierungstechniken von Funktionen und Operatoren (auch mit SSE, MMX etc.) Ich habe behauptet, dass man Operatoren nur schwer optimieren kann und dass sie deshalb langsam sind.
    Der Code war nur ein Beispiel für eine Optimierungstechnik. (meine Meinung nach eine schöne UND aufwendige Technik)
    Ich habe genervt beantwortet, weil die Optimierungstechnik, die da benutzt wird, ignoriert wurde. Man muss ja nicht unbediengt die ganze Implementierung sehen, um zu wissen was die Klasse macht.

    Jetzt habe ich noch eine Frage an die jenigen die Sachlich diskutieren können und mir bei meinem Problem helfen wollen:

    Was genau ist der Unterschied zwischen Inline-Assembler-Code und Verwendung von Intrinsics.
    Inline-Assembler, wird ja immer noch benutzt, obwohl es mit Intrinsics einfacher geht.

    PS: Ich werde jetzt dafür kein Beispielcode verwerden, ihr wisst schon warum...



  • wenn du inline assembler verwendest hast du die komplette kontrolle ueber den generierten code, aber auch die komplette verantwortung dafuer.
    meines wissens kann der kompiler jedoch selbst keine optimierungen mehr an dem code vornehmen.

    intrinsics erscheinen wie normale funktionen, werden jedch direkt in maschinencode umgesetzt.

    ob der kompiler damit noch optimieren kann entzieht sich meinem wissen.
    hab auch irgendwo im internet mal gelesen, das mit VC auf nem 64-bit windows kein inline assembler mehr moeglich sein soll. kann jetzt aber die quelle dazu nicht angeben. schon zu lange her. also mit vorsicht zu geniesen.

    Meep Meep



  • orkun schrieb:

    Es geht in diesem Thread um Optimierungstechniken von Funktionen und Operatoren (auch mit SSE, MMX etc.) Ich habe behauptet, dass man Operatoren nur schwer optimieren kann und dass sie deshalb langsam sind.

    sah fuer mich nicht so aus

    orkun schrieb:

    Warum sind eigentlich operatoren langsamer als "normale" funktionen...?

    orkun schrieb:

    Man muss ja nicht unbediengt die ganze Implementierung sehen, um zu wissen was die Klasse macht.

    haette die sache aber unter umstaenden vereinfacht

    Meep Meep



  • orkun schrieb:

    ...Ich habe behauptet, dass man Operatoren nur schwer optimieren kann und dass sie deshalb langsam sind....

    Ist trotzdem Quatsch !
    Was Du vielleicht meinst, ist, dass bestimmte Aufrufsemantiken weniger Optimierungstechniken zulassen als andere. Ob diese in f() oder in operator_() umgesetzt wird, spielt keine Rolle.

    Gruß,

    Simon2.



  • orkun schrieb:

    Es geht in diesem Thread um Optimierungstechniken von Funktionen und Operatoren (auch mit SSE, MMX etc.) Ich habe behauptet, dass man Operatoren nur schwer optimieren kann und dass sie deshalb langsam sind.

    Nein, hast du nicht.

    du hast neben dem von Meep meep zitiertem teil auch folgendes geschrieben:

    Warum wird in Real Time Rendering oder Physik Engines auf operatoren verzichtet...?

    Beispielsweise Havok Vectorklasse sieht so aus:

    und pastest danach einen code, der ganz offensichtlich auf operatoren aufbaut, nur dass er sie intelligent nutzt, und nachdem wir den code mühevoll aufdröseln, wirst du patzig und behauptest "Das hab ich doch alles schon gewusst".

    <°(((><



  • Oh man, ohne deine Hilfe hätte ich eine Woche lang auf die Implementierung der Methoden gestart und nicht gewusst was die Klasse macht, danke dass du mir alles erklärt hast...

    Jetzt mal im Ernst:
    Okay, ich bin Student und lebe seit einpaar Jahren in Deutschland. Ich habe meine Frage sehr schlecht formulieren(auch überschrift schlecht formuliert). Ich wollte eigentlich mehr über Optimierungstechniken wissen ...und worum geht's denn jetzt in diesem Thread...???
    Naja egal... Nachdem mehrmals geschrieben wurde, dass ein Operator auch eine Funktion ist, habe ich geschrieben, dass in 3D engines auf operatoren verzichtet wird, deshalb die Behauptung, dass Operatoren langsam sind. Ich habe versucht, auf die schwerige(!) Optimierung von Operatoren aufmerksam zu machen. Ich dachte Headerdatei reicht, weil da auch die expression structs und die arithmetic operationen deklariert sind. Es war ein Beispiel...

    ...und ich behaupte nicht, dass ich Ahnung habe... im Gegenteil, ich habe Frage gestellt, weil ich mehr wissen möchte. Mit Sachliche Diskusion meine ich, dass man über das Thema diskutiert und nicht über meine genervte Ton, über meine Sprachkenntnisse etc...

    Kurz:
    Es ging in diesem Thread um Optimierungstechniken, um eine Vectorklasse mit optimierte Operationen, wie man am besten arithmetic operationen optimieren kann... Sollte man vielleicht doch operatoren benutzten. Oder lieber so was machen:

    http://www.cortstratton.org/articles/OptimizingForSSE.php

    So missverständlich war der Anfangspost nun wieder auch nicht...


Anmelden zum Antworten