Schneller Code vs. Übersichtlichkeit/Wartbarkeit
-
slax schrieb:
Ja er sollte aber wie kann ich mir sicher sein, ohne jedesmal das Disassembly zu prüfen?
gar nicht...
-
dot schrieb:
Das kannst du auch so nicht.
Doch, und zwar indem ich ihn über die hässliche Macromethodik ihn dazu zwinge den kompletten Code aufzublähen. Aber das will ich ja nicht.
-
Gut, Makros sind natürlich ein Weg. Aber ich würd einfach eine inline Funktion verwenden.
-
dot schrieb:
slax schrieb:
Wie gesagt, die condition kann sich zur Laufzeit ändern (aber nicht während dem Funktionsaufruf).
Dann helfen templates natürlich nix.
Hm.. warum nicht?
template<bool condition> void calc() { for () { for() { if (condition) } } }
Klar, das ist immer noch nicht erzwungen, aber wenn der Compiler hier immer noch nicht optimiert fress ich nen Donut.
-
Weil condition zur Compiletime bekannt sein muss...
EDIT: Achso, es geht wirklich nur um ein if. Dann sind Templates natürlich die Lösung...
-
dot schrieb:
Weil condition zur Compiletime bekannt sein muss...
Na ja..
cout << "Wanna condition?"; bool wanna; cin >> wanna; if (wanna) calc<true>(); else calc<false>();
-
Ja, das ist die Lösung. Ich dachte bei Condition gings um irgendwelche Werte die erst irgendwo mitten drin zur Laufzeit bestimmt werden müssten und so...
-
Ahja danke, dass hilft mir ungemein.
Hatte templates "sorum" bisher noch nicht benutzt.
-
slax schrieb:
Ahja danke, dass hilft mir ungemein.
Hatte templates "sorum" bisher noch nicht benutzt.ist doch auch humbug...
-
King George schrieb:
humbug...
Bitte bleib doch im NadRW Forum, da schätzen wir alle deine Meinung sehr.
-
Man schreibt fuer Datenforma A eine Funktion, fuer B, fuer C, ... da wuerde ich dann gemeinsame Teile nicht weiter in Funktionen auslagern. Wenns dann mehrmals ist, ist es halt so. Auf dem Top-Level bleibt es aber uebersichtlich. Dazu braucht man nicht zwingend Templates.
-
Grund: Die Verarbeitung an "einem Stück" ist schnell. Kapselt man nun jetzt gemeinsam genutzte Codeteile bricht die Performance teilweise massiv ein, weil der Compiler dann halt Funktionsaufrufe macht, o.g. Konstanten nicht mehr zur Compilezeit berechnet sondern zur Laufzeit.
Und was ist mit inline?
-
Was soll damit sein?
-
knivil schrieb:
Man schreibt fuer Datenforma A eine Funktion, fuer B, fuer C, ... da wuerde ich dann gemeinsame Teile nicht weiter in Funktionen auslagern. Wenns dann mehrmals ist, ist es halt so. Auf dem Top-Level bleibt es aber uebersichtlich. Dazu braucht man nicht zwingend Templates.
Nö aber mit Templates ist das halt drei mal weniger Code..
-
Naja dann habe ich keine Aufrüfe mehr, sondern direkt "geinlineten" code, oder irre ich mich?
Sodass zwar für den Compiler eine Codeduplizierung existiert, aber nicht für den Programmierer. Die Geschwindigkeit bleibt dennoch gleich.
-
cooky451 schrieb:
Nö aber mit Templates ist das halt drei mal weniger Code..
Haha! Es kommt immer drauf an: http://www.youtube.com/watch?v=zh8W4ZglOlw 49:35 . Ich kann dir auch leicht eine Aufgabe geben, an der du dich probieren kannst.
-
inline ist ein Hinweis, aber zwingt den Compiler zu nichts. Moderne Compiler wie MSVC entscheiden von selbst was geinlined wird und was nicht, unabhängig davon ob inline davor steht oder nicht...
-
slax schrieb:
Die if Abfrage in der inneneren Schleife ist völlig ineffizient, weil die Schleifen entsprechend oft durchlaufen werden. Die Bedingung kann sich aber auch während dem Funktionsaufruf nicht ändern.
Du schreibst die Bedingung ändert sich nicht.
Angenommen du hilfst dem Compiler etwas indem du die Bedingung in ein eigenes bool speicherst ala
// ... bool const someCondition = PossiblySomeComputationsOrComparisons; for (...) { // ... if (someCondition) { // ... } else { // ... } // ... }
Dann ist schonmal sichergestellt dass es wirklich nur mehr um einen Conditional-Branch geht, und nicht diverse Berechnungen bei jedem Schleifendurchlauf neu angestellt werden. (Das könnte sonst nämlich passieren, z.B. weil der Compilier auf Grund von möglichem Aliasing nicht sicher weiss, dass die Variablen in der Bedingung in der Schleife garantiert nicht verändert werden können).
Dann hast du also einen Conditional-Branch in der Schleife, der immer immer immer gleich ausgeht.
Genau dafür wurde Branch-Prediction erfunden, und genau das macht sie sensationell gut. Zumindest auf den CPUs wo ich es ausprobiert habe (Pentium 4, Core 2).
D.h. mach erstmal nen Versuch mit "if vs. kein-if", und wenn er so ausgeht wie ich es mir erwarte (=kein relevanter Unterschied messbar), dann schreib es einfach mit nem normalen "if".Falls der Unterschied doch gut spürbar ist (z.B. weil du CPUs unterstützen musst die keine (gute) Branch-Prediction haben), dann würde ich die Template-Variante empfehlen.
Ansonsten gibt es immer noch den Präprozessor:
// foo_variant_impl.hpp // Kein Include-Guard! namespace { void FOO_VARIANT_NAME() { // ... for (...) { // ... DoStuffWith(FOO_VARIANT_SOME_CONSTANT); #if FOO_VARIANT_SOME_CONDITION != 0 { // ... } #else { // ... } #endif // ... } } } // namespace #undef FOO_VARIANT_NAME #undef FOO_VARIANT_SOME_CONDITION #undef FOO_VARIANT_SOME_CONSTANT
// foo.cpp #define FOO_VARIANT_NAME FooA #define FOO_VARIANT_SOME_CONDITION 1 #define FOO_VARIANT_SOME_CONSTANT 12 #include "foo_variant_impl.hpp" #define FOO_VARIANT_NAME FooB #define FOO_VARIANT_SOME_CONDITION 0 #define FOO_VARIANT_SOME_CONSTANT 42 #include "foo_variant_impl.hpp" void Foo(bool someCondition) { if (someCondition) FooA(); else FooB(); }
Bietet sich auf für C-Projekte an, wenn man sich nicht auf das Inlining des Compilers verlassen will.
(Wenn schon, dann kann man ja genau das selbe machen wie mit Templates, nur nen normalen bool Parameter übergeben statt des Template-Arguments. Wenn der Compiler das inlinen tut, sieht er ja dass die Condition Konstant ist, und wird entsprechend den "if" oder den "else" Zweig wegwerfen)
Ist mMn. auf jeden Fall alles besser als den Code mehrfach zu schreiben (Wartbarkeit!). Speziell wenn es mehr als ein paar Zeilen sind, doppelt speziell wenn es Code ist der nicht ganz einfach zu verstehen ist (was bei SSE-Code ja oft der Fall ist).
-
knivil schrieb:
cooky451 schrieb:
Nö aber mit Templates ist das halt drei mal weniger Code..
Haha! Es kommt immer drauf an: http://www.youtube.com/watch?v=zh8W4ZglOlw 49:35 . Ich kann dir auch leicht eine Aufgabe geben, an der du dich probieren kannst.
Wir haben hier doch schon einen ganz konkreten Fall?
-
hustbaer schrieb:
Ist mMn. auf jeden Fall alles besser als den Code mehrfach zu schreiben (Wartbarkeit!). Speziell wenn es mehr als ein paar Zeilen sind, doppelt speziell wenn es Code ist der nicht ganz einfach zu verstehen ist (was bei SSE-Code ja oft der Fall ist).
Ok, das mit dem conditinal branch habe ich nicht bedacht, aber ist logisch.
Ich habe es jetzt die Schleifen in Templatefunktionen gepackt, und über Template Parameter "nach außen gezogen". Funktioniert soweit gut. Das Problem ist nur, den Funktionen muss man jetzt ~10 Parameter übergeben. Das führt dazu das der Compiler das nicht mehr freiwillig inlined. Performanceverschlechterung: +100%.
Wenn man den Compiler mittels Tricks wie "__forceinline" zum inlinen zwingt habe ich Performanceverschlechterung: +0%Das ärgert mich das man wohl einen Tod sterben muss.
Entweder man verwendet schick templates, riskiert dann aber, dass der Compiler nicht mehr so toll optimiert.Oder man bastelt es sich über Präprozessor Makros zusammen, was auch nicht so wirklich toll ist.
Die Codeduplizierung, die hier vorgeschlagen wurde, würde ich gleich mal vergessen, das kostet einfach viel zu viel Zeit und wird elendig unübersichtlich.