2017-05-11 1 views
2

Gibt es einen (möglichen) Leistungsunterschied zwischen folgenden Switch-Anweisungen oder sind sie vollständig äquivalent?Irgendwelche Leistungsunterschiede bei der Rückkehr vom Schalterblock?

Ich habe keinen signifikanten Unterschied beim Profiling gefunden, aber ich bin immer noch neugierig, ob ein Compiler/Flag es verbessern kann, wenn man den einen oder anderen benutzt.

// f, g, h can be functions such as int f(int) 

int choose1(int x) { 
    switch (x) { 
    case 0: return f(x); 
    case 2: return g(x); 
    case 5: return h(x); 
    } 
    return x; 
} 

int choose2(int x) { 
    switch (x) { 
    case 0: return f(x); 
    case 2: return g(x); 
    case 5: return h(x); 
    default: return x; 
    } 
} 

Was ist, wenn Case-Anweisungen sind nicht so einfach, wie:

int choose3(int x) { 
    switch (x) { 
    case 0: /* some actions1 */; return f(x); 
    case 2: /* some actions2 */; return g(x); 
    case 5: /* some actions3 */; return h(x); 
    } 
    /* more actions */ 
    return x; 
} 

int choose4(int x) { 
    switch (x) { 
    case 0: /* some actions1 */; return f(x); 
    case 2: /* some actions2 */; return g(x); 
    case 5: /* some actions3 */; return h(x); 
    default: /* more actions */; return x; 
    } 
} 

Auch wenn für eine Weile gesucht um ich nur Beiträge habe im Zusammenhang mit dem einzigen Ausgang-Punkt gefunden (sehr häufig in C) oder nur über Programmierpraktiken sprechen (Wartung, Lesbarkeit ...). Eine ähnliche Frage ist this one bezogen auf die if-Anweisung, aber alle Antworten enden im Grunde zu diskutieren frühe Rückkehr Komfort (Programmierung Praxis), anstatt tatsächliche Leistungsunterschiede.

Ich bin jetzt nicht in solchen Programmierpraktiken interessiert, obwohl ich froh sein werde, Ihre Beiträge in Kommentaren zu kennen.

+0

Warum sollte es anders sein? ... Weil Compiler heute total dumm sind. :) Im Zweifelsfall schauen Sie sich den generierten Assembler-Code an ... online. – knivil

+0

@knivil nette Idee, ich tat genau das, sehen Sie meine Antwort und lassen Sie mich über Ihre Gedanken wissen! – gsamaras

+0

Ein Problem besteht darin, dass es gegen die "Ein-Eintrag-Eins-Exit" -Regel vieler Kodierrichtlinien (wie MISRA) verstößt. –

Antwort

3

Dies ist eine vorzeitige Optimierung Sorge.

Beide sind gleichermaßen effizient.

Wenn Sie möchten, können Sie die Maschinenanweisungen generieren und das in, aber eine switch-Anweisung ist normalerweise eine Reihe von if-Anweisungen.

Daher ist die Verzweigungsprognose wahrscheinlich der Engpass hier. Daher besteht ein einfacher Optimierungsansatz darin, im ersten Fall die Bedingung zu platzieren, die am wahrscheinlichsten ist (so dass Sie nicht müssen bewerte den Rest von ihnen).

Sie können Efficient switch statement und Default in Switch case für mehr lesen.


PS - In Ihrem Fall, dass Sie eine int zurückkehren, so dass keine große Sache, aber wenn der Rückgabetyp eine Klasse oder etwas, das groß sein kann, ist von Wert zurückgibt teuer. Aber RVO sollte sich darum kümmern.


Update:

In diesem Compiler Explorer Sie die Assembly sehen:

choose1(int): 
     push rbp 
     mov  rbp, rsp 
     sub  rsp, 8 
     mov  DWORD PTR [rbp-4], edi 
     mov  eax, DWORD PTR [rbp-4] 
     cmp  eax, 2 
     je  .L9 
     cmp  eax, 5 
     je  .L10 
     test eax, eax 
     jne  .L13 
     mov  eax, DWORD PTR [rbp-4] 
     mov  edi, eax 
     call f(int) 
     jmp  .L12 
.L9: 
     mov  eax, DWORD PTR [rbp-4] 
     mov  edi, eax 
     call g(int) 
     jmp  .L12 
.L10: 
     mov  eax, DWORD PTR [rbp-4] 
     mov  edi, eax 
     call h(int) 
     jmp  .L12 
.L13: 
     mov  eax, DWORD PTR [rbp-4] 
.L12: 
     leave 
     ret 
choose2(int): 
     push rbp 
     mov  rbp, rsp 
     sub  rsp, 8 
     mov  DWORD PTR [rbp-4], edi 
     mov  eax, DWORD PTR [rbp-4] 
     cmp  eax, 2 
     je  .L16 
     cmp  eax, 5 
     je  .L17 
     test eax, eax 
     jne  .L20 
     mov  eax, DWORD PTR [rbp-4] 
     mov  edi, eax 
     call f(int) 
     jmp  .L19 
.L16: 
     mov  eax, DWORD PTR [rbp-4] 
     mov  edi, eax 
     call g(int) 
     jmp  .L19 
.L17: 
     mov  eax, DWORD PTR [rbp-4] 
     mov  edi, eax 
     call h(int) 
     jmp  .L19 
.L20: 
     mov  eax, DWORD PTR [rbp-4] 
.L19: 
     leave 
     ret 

und wie erwartet, dass der Code gleich ist.

+0

Ich verwendete Ints genau, um Diskussion zu vermeiden, Konstruktion/Kopie und die Single zu vermeiden -Ausgangspunkt. – cbuchart

+0

Es ist eher eine Kuriosität über tatsächliche Unterschiede als ein Optimierungsproblem (wie ich sagte, Profiling zeigt keinen signifikanten Unterschied) – cbuchart

+0

Deshalb habe ich erwähnt, dass als PS @ cbookart, hmm ich aktualisiert meine Antwort, hoffe es dient dir jetzt besser! =) Nette Frage BTW, +1! – gsamaras

Verwandte Themen