Operatoren langsam, wie so...?
-
Warum sind eigentlich operatoren langsamer als "normale" funktionen...?
ich möchte eine eine 3D Vectorklasse schreiben, lohnt es sich mit SSE oder mit 3DNow! zu implementieren? Welche operationen sollte ich als inline assembler implementieren?( Echtzeit grafik )
-
Wer sagt das sie langsamer sind? Kommt ganz auf deine Methode an, nicht?
Und bevor du groß optimierst solltest du selbst mal feststellen ob eine Optimierung überhaupt notwendig ist.
-
wie komst du darauf das operatoren langsamer sind als normale funktionen ?
MMX und konsorten sind fuer solche dinge ausgelegt. wuerde also schon sinn machen.
Meep Meep
-
Operatoren dienen einzig aund allein einer lesbareren Darstellungsweise des quelltextes, sind aber nach dem Kompilieren genau das gleiche wie Funktionen, wäre schwachsinn, wenn es anders wäre.
-
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