[VC++’08]Unterschied zwischen if/else-if und switch

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
Krishty
Establishment
Beiträge: 8244
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

[VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Krishty »

Hi,

Hat es irgendeinen besonderen, mir unbekannten – z.B. in der Spezifikation festgelegten – Grund, dass Visual C++ switch-Statements anders behandelt als gleichwertige if/else-if-Statements, oder ist das bloß Schlampigkeit?

Speziell geht es darum, dass switches auf höchster Optimierungsstufe fast immer zu Lookup-Tables oder Binärbäumen umgewandelt werden und damit recht fix sind, während gleichwertige if/else-if-Statements unoptimiert bleiben und dann (bei entsprechend vielen Möglichkeiten) viel mehr Mnemonics produzieren.

Gruß, Ky
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Aramis »

Wohl eher 'Schlampigkeit', wenn man es so nennen kann.

switch'es sind vom Sprachstandard ja - neben der verringerten Schreibarbeit im Vergleich zur äquivalenten if/else-Bauweise -bereits als Hinweis an den Optimizer vorgesehen. Ich denke nicht, dass es die Aufgabe des Optimizers ist Dinge zu optimieren, die man bei klarem Kopf sowieso nicht machen würde, z.B. Fensternachrichten mit gigantischen if/else-Blöcken behandeln ...

Mag auch sein dass die einschlägigen Benchmarks keine Stellen haben, an denen diese Optimierung nützlich wäre ... :D
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von kimmi »

Vielleicht wollten die Autoren auch einfach vermeiden, daß irgendwelche Optimierungen in den id / else if / else Blöcken böse Side-Effects auslösen. Schließlich müßte man dann die Optimierung in irgendeiner Form mit der Semantik des Ausdrucks koppeln, was auch nicht gerade der weisheits letzter Schluß ist.

Gruß Kimmi
Benutzeravatar
Lord Delvin
Establishment
Beiträge: 577
Registriert: 05.07.2003, 11:17

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Lord Delvin »

Der Grund wird wohl sein, dass switch statesments in C++ für gleichwertige Auswahl und (verschachtelte)if/else blöcke für sehr ungleichmäßige vorgesehen sind.
Wenn du z.b. durch dein bild läufst und immer was anders machen musst, wenn du einen rand triffst, dann passiert das ja nur 1 + breite(oder höhe) mal, während das andere breite*höhe - F mal passiert, d.h. wenn du dein if/else entsprechend hinschreibst, dann stimmt das if statement quasi immer und der prozessor tut so als wäre es ein unbedingter sprung, was zu einer erheblich schnelleren ausführungszeit führt.

Das es von der Sprache her nicht gleichwertig ist, sieht man ja auch schon am argumenttyp von if bzw. switch.
Gruß
XML/JSON/EMF in schnell: OGSS
Keine Lust mehr auf C++? Versuche Tyr: Get & Get started
Benutzeravatar
Krishty
Establishment
Beiträge: 8244
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Krishty »

Ich habe der Klarheit wegen Pseudo-Code:

Code: Alles auswählen

SomeEnum Value;

// switch-Version
switch(Value) {
    case Enum1:
        return 0;
    case Enum2:
        return 1;
    case Enum3:
        return 2;
    default:
        throw Error;
};

// if/elseif-Version
if(Enum1 == Value)
    return 0;
else if(Enum2 == Value)
    return 1;
else if(Enum3 == Value)
    return 2;
else
    throw Error;
Aramis hat geschrieben:Ich denke nicht, dass es die Aufgabe des Optimizers ist Dinge zu optimieren, die man bei klarem Kopf sowieso nicht machen würde, z.B. Fensternachrichten mit gigantischen if/else-Blöcken behandeln ...
Natürlich, genau dafür ist der Optimizer doch da … und naja, die Blöcke sind vollkommen homogen und bestehen nur aus return Value;, if/else habe ich nur gewählt, weil es einfacher wartbar ist. Weiterhin hätte ich erwartet, dass es in den Entscheidungsbäumen, die der Compiler baut, eh gleich aussieht und deshalb vom Optimizer auch gleich behandelt wird.
Aramis hat geschrieben:Mag auch sein dass die einschlägigen Benchmarks keine Stellen haben, an denen diese Optimierung nützlich wäre ... :D
Genau das befürchte ich auch.
kimmi hat geschrieben:Vielleicht wollten die Autoren auch einfach vermeiden, daß irgendwelche Optimierungen in den id / else if / else Blöcken böse Side-Effects auslösen. Schließlich müßte man dann die Optimierung in irgendeiner Form mit der Semantik des Ausdrucks koppeln, was auch nicht gerade der weisheits letzter Schluß ist.
Von diesen Side-Effects habe ich auch gelesen. Es ging darum, dass der Compiler die Ausführungsreihenfolge der Blöcke aufrecht erhalten muss. Kapiert habe ich das aber nicht, denn das muss er bei switch ja genauso tun (ohne break; „flutscht“ die Ausführung unten durch)?
Lord Delvin hat geschrieben:Der Grund wird wohl sein, dass switch statesments in C++ für gleichwertige Auswahl und (verschachtelte)if/else blöcke für sehr ungleichmäßige vorgesehen sind.
Du hast – von Compiler-spezifischen Erweiterungen mal abgesehen – ja keine Möglichkeit, der CPU mitzuteilen, welcher Zweig öfter ausgeführt werden wird. Außerdem läuft die Sprungvorhersage der CPU durch die Tabellen, die switch erzeugt, erheblich schneller durch (weil keine Vergleichsoperation durchgeführt werden muss) und ist damit auch bei großer Streuung zwischen oft oder selten genutzten Zweigen performanter.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Lord Delvin
Establishment
Beiträge: 577
Registriert: 05.07.2003, 11:17

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Lord Delvin »

Krishty hat geschrieben: Außerdem läuft die Sprungvorhersage der CPU durch die Tabellen, die switch erzeugt, erheblich schneller durch (weil keine Vergleichsoperation durchgeführt werden muss) und ist damit auch bei großer Streuung zwischen oft oder selten genutzten Zweigen performanter.
Das glaubst du jetzt nicht wirklich? Ich mein wie willst du denn dann wissen, was deine nächste Operation ist? Du darfst in ein switch ja auch default und "löchrige" werte verwenden. D.h. du musst MINDESTENS einen vergleich durchführen, auf den du vor deinem Sprung warten musst.

Des weiteren hab ich mich mit der CPU sagen ob das genommen wird vielleicht ungechickt ausgedrückt. Die CPU rät das natürlich selbständig, aber wenn du in ner kurzen schleife ein if verwendest, dass einen vergleich und daran gebunden einen Sprung hat, dann wirst du feststellen, dass dein code schneller zuende ist, wenn die auswertung der bedingung nahezu konstant ist.

Btw. ist das if / else if / else if ... in den allermeisten fällen ein zeichen dafür, dass man was falsch gemacht hat, wenn man C++ programiert.
Gruß
XML/JSON/EMF in schnell: OGSS
Keine Lust mehr auf C++? Versuche Tyr: Get & Get started
Benutzeravatar
Krishty
Establishment
Beiträge: 8244
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Krishty »

Lord Delvin hat geschrieben:
Krishty hat geschrieben: Außerdem läuft die Sprungvorhersage der CPU durch die Tabellen, die switch erzeugt, erheblich schneller durch (weil keine Vergleichsoperation durchgeführt werden muss) und ist damit auch bei großer Streuung zwischen oft oder selten genutzten Zweigen performanter.
Das glaubst du jetzt nicht wirklich? Ich mein wie willst du denn dann wissen, was deine nächste Operation ist? Du darfst in ein switch ja auch default und "löchrige" werte verwenden. D.h. du musst MINDESTENS einen vergleich durchführen, auf den du vor deinem Sprung warten musst.
Natürlich sind löchrige switches und default-Werte eine Ausnahme (obwohl der Compiler auch dort mit binären Entscheidungsbäumen besser wegkommt als mit unoptimiertem if/else). In meinem Beispiel kommt auch immer mindestens ein Vergleich für default bzw das finale else vor. Die Sache sind die nicht-default-Sprünge … ich zeige dir, wie das in Pseudo-Assembler aussieht, default, letztes else, Prolog und Epilog der Klarheit halber außen vor (ja, meine Funktion macht tatsächlich nichts anderes als enums zwischen 0 und x entgegenzunehmen und dafür andere Werte zurückzugeben):

Code: Alles auswählen

enum EValue {
    Enum1 = 0,
    Enum2 = 1,
    Enum3 = 2
};
EValue Value = …

switch(Value) {
    case Enum1:
        return 3;
    case Enum2:
        return 2;
    case Enum3:
        return 1;
};

00 jump [01 + Value * 2]
01 push 3
02 return
03 push 2
04 return
05 push 1
06 return

if(Enum1 == Value)
    return 3;
else if(Enum2 == Value)
    return 2;
else if(Enum3 == Value)
    return 1;

00 compare Value, 0
01 jump not equal [04]
02 push 3
03 return
04 compare value, 1
05 jump not equal [08]
06 push 2
07 return
08 push 1
09 return
Mein „echtes“ if-/else-if hat 25 Zweige, im Schnitt werden also 25/2 + 1 (für else) Vergleiche durchgeführt. Bei switch ist es nur einer für das default und ein kleineres Programm insgesamt. Das ist schon ein Unterschied.
Lord Delvin hat geschrieben:Des weiteren hab ich mich mit der CPU sagen ob das genommen wird vielleicht ungechickt ausgedrückt. Die CPU rät das natürlich selbständig, aber wenn du in ner kurzen schleife ein if verwendest, dass einen vergleich und daran gebunden einen Sprung hat, dann wirst du feststellen, dass dein code schneller zuende ist, wenn die auswertung der bedingung nahezu konstant ist.
Okay, das mag stimmen (für diesen Fall kenne ich mich zuwenig mit der Sprungvorhersage aus).
Lord Delvin hat geschrieben:Btw. ist das if / else if / else if ... in den allermeisten fällen ein zeichen dafür, dass man was falsch gemacht hat, wenn man C++ programiert.
Die Funktion wird aus endlich rekursiven Templates zusammengesetzt (jedes else ist ein Aufruf) … würde ich sie von Hand schreiben, würde ich wohl switch oder einen selbstgeschriebenen Lookup einsetzen … aber Compiler-generiertem Code traue ich immer mehr als eigenem, darum möchte ich den Compiler dazu kriegen, das gefälligst richtig zu optimieren. Habe übrigens auch mal den Operator ?: ausprobiert, leider mit selbem Ergebnis wie else-if.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von kimmi »

Ich wage zu behaupten, daß die Zeit in den meisten Codes nicht zu großen Teilen in den if / else if / else Blöcken hängt, sondern noch von einigen anderen Parametern beeinflußt wird. Hast du festhestellt, daß du in deinen Vergleichen zu viel Zeit verbringst oder wie kommt es, daß du dir gerade diese Ecke so genau betrachtest? Ich frage aus reiner Neugierde.

Gruß Kimmi
Benutzeravatar
Krishty
Establishment
Beiträge: 8244
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Krishty »

kimmi hat geschrieben:Ich wage zu behaupten, daß die Zeit in den meisten Codes nicht zu großen Teilen in den if / else if / else Blöcken hängt, sondern noch von einigen anderen Parametern beeinflußt wird. Hast du festhestellt, daß du in deinen Vergleichen zu viel Zeit verbringst oder wie kommt es, daß du dir gerade diese Ecke so genau betrachtest? Ich frage aus reiner Neugierde.
Ich habe gerade mit der Optimierung einer Klasse angefangen, dabei ist mir dieser Code besonders ins Auge gefallen, weil er in drei Funktionen vorkommt, die von der Initialisierung über innere Schleifen bis zur Freigabe laufend aufgerufen werden. Noch dazu stehe ich vor einem Space-Time-Tradeoff, da ich ihre Ergebnisse auch einfach speichern könnte, statt jedes Mal den Auswahlblock zu durchlaufen …

Bevor ich #pragma inline_recursion gefunden habe, hat der Compiler noch jedes else als eigenen Funktionsaufruf kompiliert(!) …

Benchmarks habe ich nicht, im Internet geht man von 10 bis 30% Performance-Unterschied zwischen switch und if-else aus … so schnell, wie die Funktion nun ist, ist das – für das Programm als großes Ganzes – vernachlässigbar. Da ich aber eh schon über dem Assembler hockte, wollte ich wissen, warum die Funktion jetzt zwar ausreichend, aber nicht optimal kompiliert wird. Ihr kennt mich ja, solche winzigen Inkonsistenzen können mich auf die Palme bringen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
kkrahl
Beiträge: 56
Registriert: 20.10.2008, 13:41

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von kkrahl »

Der Geschwindigkeitsunterschied zwischen if/else und switch liegt darin das if/else eine Vergleichoperation auf Assebler-Ebene(Maschienencode) ist und switch eine Sprungoperation.

d.h:

Code: Alles auswählen

if(i == 1) {}
else if(i == 2) {}
else if(i == 3) {}
else if(i == 4) {}
else if(i == 5) {}
... ist auf Assember-Ebene 5 Vergeichsoperationen + 5 Sprungbefehle -> also 10 Befehle

Code: Alles auswählen

switch(i)
{
case 1:
    {} break;
case 2:
    {} break;
case 3:
    {} break;
case 4:
    {} break;
case 5:
    {} break;
}
... ist auf Assember-Ebene 1 Sprungoperation + 1 Sprungbefehle für das break -> also 2 Befehle

Das ist auch der Grund warum switch in der Regel nur Basistypen unterstützt, wobei manche Compiler auch komplexe Typen zulassen und diese dann via Bäume abbilden.

Das ist zumindest was ich von 15 Jahren im Programmierunterricht gelernt hatte.

mfg

Karl
Benutzeravatar
Krishty
Establishment
Beiträge: 8244
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Krishty »

… und ziemlich deckungsgleich mit meinem Code-Beispiel oben :)

Jetzt würde mich nur interessieren, warum der Compiler if/else nicht darauf prüft, ob sie sich wie ein switch optimieren lassen. Ich meine, nach der Optimierung bleibt vom ursprünglichen Code nichts mehr übrig, soviel Datenflussanalyse, Schleifentransformation etc da durchgeführt wird – da kann es doch unmöglich „durchrutschen“, ohne dass es einen bestimmten Grund gibt?

Könnte jemand testen, ob der das GCC schafft? Würde mich mal interessieren.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Alexander Kornrumpf
Moderator
Beiträge: 2113
Registriert: 25.02.2009, 13:37

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Alexander Kornrumpf »

Zur allgemeinen Verwirrung hab ich noch ein bisschen google bedient und dieses gefunden:
Place case labels in narrow range

If the case labels are in a narrow range, the compiler does not generate a if-else-if cascade for the switch statement. Instead, it generates a jump table of case labels along with manipulating the value of the switch to index the table. This code generated is faster than if-else-if cascade code that is generated in cases where the case labels are far apart. Also, performance of a jump table based switch statement is independent of the number of case entries in switch statement.
Place frequent case labels first

If the case labels are placed far apart, the compiler will generate if-else-if cascaded code with comparing for each case label and jumping to the action for leg on hitting a label match. By placing the frequent case labels first, you can reduce the number of comparisons that will be performed for frequently occurring scenarios. Typically this means that cases corresponding to the success of an operation should be placed before cases of failure handling.
Break big switch statements into nested switches

The previous technique does not work for some compilers as they do not generate the cascade of if-else-if in the order specified in the switch statement. In such cases nested switch statements can be used to get the same effect.

To reduce the number of comparisons being performed, judiciously break big switch statements into nested switches. Put frequently occurring case labels into one switch and keep the rest of case labels into another switch which is the default leg of the first switch.
http://www.eventhelix.com/realtimemantr ... ppcode.htm

Bin mir nicht sicher was die mit "far apart" meinen und warum das einen Unterschied machen sollte...
kkrahl
Beiträge: 56
Registriert: 20.10.2008, 13:41

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von kkrahl »

Meines Wissens nach versucht der Compiler bei eingeschalteter Optimierung auch alle If's durch Sprungbefehle (z.B. switch, aber auch einfache jumps) zu ersetzen. Dies gelingt auch meist bei einfachen Statements, wobei das switch-Statement das Optimum ist was es zu erreichen gilt.

@ Alexander Kornrumpf
Im Assember unterscheidet man zwischen "short", "near" und "far". Short ist jener Code der innerhalb der nächsten 128 Bytes liegt. Near ist der Code des aktuellen Code-Segments, ein Code-Segment hat eine Größe von 64 KByte. Far ist der Rest der Applikation, der nicht im aktuellen Code-Segment liegt.
Aus diesem Grund versuchen die Compiler auch switches, if's aber auch Funktionen immer innerhalb eines Code-Segments unterzubringen da dies die Schnellste Code-Ausführung zur Folge hat.
http://de.wikibooks.org/wiki/Assembler_ ... _Schleifen
Benutzeravatar
Schrompf
Moderator
Beiträge: 4855
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Schrompf »

Ich glaube nicht, dass hier noch die alte NEAR und FAR-Semantic aus 16Bit-Zeiten gemeint ist. Ich vermute eher, es geht hier schlicht um Instruction Caches - je weiter vorne die case-Blöcke im switch kommen, desto näher am Auswerte-Code liegt der Code dazu. Sprich, die nahen Code-Blöcke sind "wärmer" im Cache als die hinteren.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8244
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Krishty »

Nein, sie meinen folgenden Fall:

Code: Alles auswählen

switch(Value) {
case 0x0:
    return 3;
case 0x111:
    return 2;
case 0xBAADF00D:
    return 1;
}
Hier liegen die cases – vom Wertebereich – soweit auseinander, dass der Compiler keinen Jump-Table generieren kann (schließlich müsste der 0xBAADF00D groß sein) und wird stattdessen if-else einsetzen. Ich glaube durchaus, dass bei dieser Entscheidung kkrahls Near-Far-Semantik zum Einsatz kommt, und zwar im Sinne von: „Wie weit läge ein Jump-Table-Eintrag maximal entfernt, passte er noch ins aktuelle Segment?“.

In kkrahls Code-Beispiel liegen alle Werte zwischen 1 und 5 („narrow range“) und können damit optimiert werden.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Alexander Kornrumpf
Moderator
Beiträge: 2113
Registriert: 25.02.2009, 13:37

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Alexander Kornrumpf »

Krishty hat geschrieben:Nein, sie meinen folgenden Fall:

Code: Alles auswählen

switch(Value) {
case 0x0:
    return 3;
case 0x111:
    return 2;
case 0xBAADF00D:
    return 1;
}
Hier liegen die cases – vom Wertebereich – soweit auseinander, dass der Compiler keinen Jump-Table generieren kann (schließlich müsste der 0xBAADF00D groß sein) und wird stattdessen if-else einsetzen. Ich glaube durchaus, dass bei dieser Entscheidung kkrahls Near-Far-Semantik zum Einsatz kommt, und zwar im Sinne von: „Wie weit läge ein Jump-Table-Eintrag maximal entfernt, passte er noch ins aktuelle Segment?“.

In kkrahls Code-Beispiel liegen alle Werte zwischen 1 und 5 („narrow range“) und können damit optimiert werden.
Da hätte ich auch selbst drauf kommen können, stimmt.
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Jörg »

GCC:

Mein billig-Beispiel (switch fuer 0,1,2 und default Zweig vs. if-elseif...else, jeweils mit printfs in den Zweigen) mit gcc 4.3.3 liefert bei -O3 (fast) identischen Code. Ohne Sprungtabellen, mit direkten Vergleichen. Einzig die Reihenfolge der Vergleiche ist verschieden. Andere gcc-Versionen hab ich gerad nicht hier.

Gruss!

Joerg
Helmut
Establishment
Beiträge: 237
Registriert: 11.07.2002, 15:49
Wohnort: Bonn
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Helmut »

Jörg hat geschrieben:Mein billig-Beispiel (switch fuer 0,1,2 und default Zweig vs. if-elseif...else, jeweils mit printfs in den Zweigen) mit gcc 4.3.3 liefert bei -O3 (fast) identischen Code. Ohne Sprungtabellen, mit direkten Vergleichen. Einzig die Reihenfolge der Vergleiche ist verschieden. Andere gcc-Versionen hab ich gerad nicht hier.
Ich glaub nicht, dass das Krishty viel helfen wird:) Es geht schließlich darum, ob der Compiler if/elseif zu ner Sprungtabelle optimieren kann.
Lord Delvin hat geschrieben:Btw. ist das if / else if / else if ... in den allermeisten fällen ein zeichen dafür, dass man was falsch gemacht hat, wenn man C++ programiert.
Kannst du das begründen? Ich hab eigentlich in letzter Zeit festgestellt, dass die if/else if Variante deutlich leserlicher ist und weniger Codezeilen braucht als die switch Variante. Außerdem gibt es weniger Einrückprobleme, keine Unkonsistenzen wegen Blöcken, die man bei switches braucht, wenn man Variablen anlegt, keine Fehlerquellen durch vergessene breaks oder absichtlich weggelassene breaks, und außerdem sieht man bei if/elseif immer, womit der Wert verglichen wird. Bei nem case 5 muss man immer hochscrollen, wenn man mal vergessen hat, womit nun 5 eigentlich verglichen wird.

Oder meinst du nur ganz allgemein, dass switches böse sind und durch modernere Sachen wie Polymorphie ausgetauscht werden sollen? Das geht zwar, ist aber nicht immer sinnvoll.
Ciao
Benutzeravatar
Krishty
Establishment
Beiträge: 8244
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Krishty »

Helmut hat geschrieben:Ich glaub nicht, dass das Krishty viel helfen wird:)
Doch doch, ich habe ja gesagt, dass mich das interessiert. Wenn GCC das optimiert kriegt, kann ich mir sicher sein, dass es ein Bug/fehlendes Feature von Visual C++ ist. Da gibt es allerdings ein Problem: Mit Funktionsaufrufen erzeugt auch Visual C++ keine Sprungtabelle, sondern wertet einzeln aus. Jörg, könntest du das nochmal testen und diesmal printf() nicht direkt aufrufen, sondern die Zweige so konstruieren, dass sie nur ints/char *s zurückgeben?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Jörg »

Auch ohne Funktionsaufrufe erzeugt der gcc in beiden Faellen cmp-Sequenzen.
Es ist gut moeglich, dass es da noch Parameter gibt, welche diese Entscheidung des Compilers beeinflussen, bin zu faul, da nochmal das Handbuch zu lesen.
Wenn das wirklich ein Bottleneck bei Dir ist, dann schau doch, wie Du generell diese Art von dynamischer Entscheidung vermeidest, vllt. geht das einfacher und hilft dann auch bei mehreren Platformen. Koennte mir vorstellen, dass er auf ARM z.B. auf die Spruenge verzichtet und conditional moves verwendet.
Benutzeravatar
Krishty
Establishment
Beiträge: 8244
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Krishty »

Es ist kein Bottleneck, ich frage mich eben nur, warum der Compiler das nicht optimiert … aber wenn GCC das auch nicht macht, ist es wohl einfach nur ein nicht implementiertes Optimizer-Feature :/

Ich danke euch für die Hilfe.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
NytroX
Establishment
Beiträge: 364
Registriert: 03.10.2003, 12:47

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von NytroX »

Hm, also ich finde das ehrlich gesagt schon ok so, wie es ist.
D.h. "switch"s werden (z.b. als binärbaum) optimiert, "if"s nicht.

Warum? Kann ich einfach erklären:

Punkt 1:
"if"s können alles vergleichen, "switch"s nur zahlen.
Damit ist wohl klar, dass eine standardmäßige optimierung als binärbaum einfach umzusetzen ist für "switch"s, aber bei überladenen ==, <=, usw. operatoren eher schwierig sein könnte.

Punkt 2:
Der Programmierer hat die Kontrolle.
In keiner anderen Sprache ist man so systemnah wie bei C/C++.
Wenn ich weiss, dass bestimmte Fälle oft oder selten vorkommen, dann kann ich die prüf-reihenfolge mit "if"s vorgeben. "switch"s nutzte ich, wenn die cases ausgewogen sind (oder unbekannt, um den schnellsten worst-case fall zu haben).
Der Optimizer würde ja sonst meine Optimierung wegoptimieren, da hab ich schon lieber selbst die Kontrolle.

Und wenn das wirklich mal ein Bottleneck werden sollte, muss man sowieso in ASM proggen, um da noch maßgeblich was rauszuholen, und da werden die "if"s mit Sicherheit nicht alleine den Ausschlag geben...
Benutzeravatar
Krishty
Establishment
Beiträge: 8244
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Krishty »

NytroX hat geschrieben:Wenn ich weiss, dass bestimmte Fälle oft oder selten vorkommen, dann kann ich die prüf-reihenfolge mit "if"s vorgeben. "switch"s nutzte ich, wenn die cases ausgewogen sind (oder unbekannt, um den schnellsten worst-case fall zu haben).
Das ist der erste nachvollziehbare Grund, den ich dafür höre :) Aber auch der ist hier nicht perfekt anwendbar:

Die switch-Version wird hier nicht etwa zu einem Binärbaum optimiert, sondern – weil die cases eng (und sogar chronologisch) vorliegen – zu einem Jump-Table. Selbst, wenn ich die if-elses absichtlich so angeordnet hätte, dass der häufigste Fall zuerst vorkäme, wäre der resultierende Vergleich immernoch langsamer als die Jump-Table, die komplett ohne Vergleiche auskommt.

Lägen die cases weiter auseinder, so dass der Compiler einen Binärbaum generieren müsste, dann wäre das unoptimierte if-else definitiv schneller, da hast du durchaus Recht. Aber wir sprechen hier von einem Jump-Table, der (– afaik –) immer die schnellste Lösung ist, egal wie häufig welcher Zweig ausgeführt wird.
NytroX hat geschrieben:Punkt 2:
Der Programmierer hat die Kontrolle.
In keiner anderen Sprache ist man so systemnah wie bei C/C++.
Daran ist grundsätzlich nichts falsch, weil man wirklich in kaum einer anderen Sprache eine solche Kontrolle über den generierten Code hat – aber das kann man nicht pauschalisieren! C++ erlaubt auch hochabstrakte Programmierung und, in meinem Fall, Meta-Programmierung. Da ich das Programm nicht schreibe, sondern durch templates generieren lasse kann ich an dieser Stelle kein switch einbauen, sondern muss mich bemühen, den Compiler in die Richtung eines möglichst gleichwertigen Konstruktes zu schubsen. Dass er die Optimierung scheinbar nur aufgrund anderer Schlüsselwörter verweigert, ärgert mich.
NytroX hat geschrieben:Und wenn das wirklich mal ein Bottleneck werden sollte, muss man sowieso in ASM proggen, um da noch maßgeblich was rauszuholen, und da werden die "if"s mit Sicherheit nicht alleine den Ausschlag geben...
Ja, manchmal habe ich echt die Schnauze von den Hochsprachen und den Compiler-Zickereien voll und will es nurnoch auf die gute, alte Geoff-Crammond-Art und -Weise machen. Dann schreibe ich hundert Zeilen perfekten Assembler-Code, bilde mir ein, dass Assembler immer die bessere Wahl sei und werde bei der nächsten Funktion in Hinsicht auf die Performance vom Compiler gedemütigt :D
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Jörg »

Krishty hat geschrieben: Jump-Table, der (– afaik –) immer die schnellste Lösung ist, egal wie häufig welcher Zweig ausgeführt wird.
Nicht immer. Stell Dir vor, die Tabelle liegt mal nicht im Cache, weil dein Datenlayout an anderer Stelle mit der Tabelle kollidiert. Und schon geht die Eierei los, so nach dem Motto: Wie sag ich dem Compiler, 'wo' meine Tabelle am besten liegen sollte ;) Oder schlimmer, auf Architekturen, deren Programm- und Datenspeicher unterschiedliche Latenzen aufweisen (embedded Bereich bei getrennten Anbindungen durchaus ueblich), kann es vorteilhaft sein, auf einen Lookup zu verzichten.
Sicherlich gibt es irgendwo einen Punkt, an den beide Varianten gleich schnell sind. Dafuer muesste man aber die Haeufigkeitsverteilung der 'cases' kennen usw. Es ist wichtig, die Alternativen zu kennen, die man hat, falls mal ein Bottleneck an dieser Stelle auftritt. Solange es aber nur Code-Kosmetik ist, dann jedem das seine :)
Helmut
Establishment
Beiträge: 237
Registriert: 11.07.2002, 15:49
Wohnort: Bonn
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Helmut »

Jörg hat geschrieben:Nicht immer. Stell Dir vor, die Tabelle liegt mal nicht im Cache, weil dein Datenlayout an anderer Stelle mit der Tabelle kollidiert. Und schon geht die Eierei los, so nach dem Motto: Wie sag ich dem Compiler, 'wo' meine Tabelle am besten liegen sollte ;) Oder schlimmer, auf Architekturen, deren Programm- und Datenspeicher unterschiedliche Latenzen aufweisen (embedded Bereich bei getrennten Anbindungen durchaus ueblich), kann es vorteilhaft sein, auf einen Lookup zu verzichten.
Hm, soweit ich weiß liegt die Lookuptabelle nicht im Datenspeicher, sondern direkt im Code. Sogar sehr nah an der Instruction, die den Lookup ausführt. Ich würde also schon sagen, dass die Tabelle in jedem Fall schneller ist.

Ich hab mir mal die Mühe gemacht den gcc zu testen. Während er einen switch-Code mit aufeinanderfolgenden cases zu ner LookupTabelle macht, wird das if/else if-Äquivalent nicht optimiert. Also genauso doof wie der von MS. Die Demo vom Intelcompiler ist bei mir leider schon abgelaufen... Dem würde ich am ehesten zutrauen, sowas optimieren zu können.

Ciao
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: [VC++’08]Unterschied zwischen if/else-if und switch

Beitrag von Jörg »

Ja da hast Du natuerlich voellig recht. Ich habe compiler-generierte Sprungtabellen mit normalen Lookup-Tabellen verwechselt, ziemlich daemlich heute.
Antworten