[C++] Mikrooptimierungs-Log

Hier können Artikel, Tutorials, Bücherrezensionen, Dokumente aller Art, Texturen, Sprites, Sounds, Musik und Modelle zur Verfügung gestellt bzw. verlinkt werden.
Forumsregeln
Möglichst sinnvolle Präfixe oder die Themensymbole nutzen.

Re: [C++] Mikrooptimierungs-Log

Beitragvon Krishty » 27.08.2017, 00:05

  1. Danke, das ist hervorragend! Branchless Binary Search kannte ich noch nicht.
  2. Ich habe IACA seit einigen Wochen auf der Platte liegen, hatte aber glücklicherweise noch keine Zeit, es zu testen – jetzt weiß ich, dass die Timings ähnlich absurd geraten sind wie damals im AMD GPU Shader Analyzer; danke!
  3. Ich habe schon oft gemerkt, dass Code, der in jeder Hinsicht schneller sein sollte, plötzlich total abstinkt. OR -1 habe ich in dem Zusammenhang oft gesehen, aber nie wirklich wahrgenommen – für so bescheuert, da keinen Dependency Breaker zu nutzen, habe ich bei MS keinen gehalten. Fuck.
  4. Branch Prediction ist mit VC ein *riesen* Problem, für das ich auch neben POGO keine Lösung kenne; es frustriert mich auch von Mal zu Mal mehr. Ich hatte vorletzte Woche wieder so einen Fall, urks, einfach zum Kotzen.
  5. Ich hatte 2011 einen wenig professionellen Vergleich von Binary vs Linear gemacht und kam auf einen Break-Even bei rund 400 Elementen. Passt ungefähr zu den Daten im Artikel.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6032
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [C++] Mikrooptimierungs-Log

Beitragvon Krishty » 02.10.2017, 02:02

Krishty hat geschrieben:Benutzt in Visual C++ keine Initializer Lists.

  struct SRGBC_8888 { unsigned char r, g, b, c; };

  result.ambient = { 0xFF, 0xFF, 0xFF, 0xFF };
  result.diffuse = { 0xFF, 0xFF, 0xFF, 0xFF };
  result.specular = { 0xFF, 0xFF, 0xFF, 8 }; // exponent 1: 255 * sqrt(1 / 1024)
  result.emissive = { 0xFF, 0xFF, 0xFF, 0xFF };


Erzeugt:

Code: Ansicht erweitern :: Alles auswählen
40 55                push        rbp  
48 8B EC             mov         rbp,rsp  
83 4D 10 FF          or          dword ptr [rbp+10h],0FFFFFFFFh  
8B 45 10             mov         eax,dword ptr [rbp+10h]  
83 4D 10 FF          or          dword ptr [rbp+10h],0FFFFFFFFh  
89 41 18             mov         dword ptr [rcx+18h],eax  
8B 45 10             mov         eax,dword ptr [rbp+10h]  
89 41 1C             mov         dword ptr [rcx+1Ch],eax  
C7 45 10 FF FF FF 08 mov         dword ptr [rbp+10h],8FFFFFFh  
8B 45 10             mov         eax,dword ptr [rbp+10h]  
83 4D 10 FF          or          dword ptr [rbp+10h],0FFFFFFFFh  
89 41 20             mov         dword ptr [rcx+20h],eax  
8B 45 10             mov         eax,dword ptr [rbp+10h]  
89 41 24             mov         dword ptr [rcx+24h],eax  
48 8B C1             mov         rax,rcx  
5D                   pop         rbp  
C3                   ret  


wat

  result.ambient.r = 0xFF;
  result.ambient.g = 0xFF;
  result.ambient.b = 0xFF;
  result.ambient.c = 0xFF;

  result.diffuse.r = 0xFF;
  result.diffuse.g = 0xFF;
  result.diffuse.b = 0xFF;
  result.diffuse.c = 0xFF;

  result.specular.r = 0xFF;
  result.specular.g = 0xFF;
  result.specular.b = 0xFF;
  result.specular.c = 8; // exponent 1: 255 * sqrt(1 / 1024)

  result.emissive.r = 0xFF;
  result.emissive.g = 0xFF;
  result.emissive.b = 0xFF;
  result.emissive.c = 0xFF;


Erzeugt:

Code: Ansicht erweitern :: Alles auswählen
48 83 49 18 FF       or          qword ptr [rcx+18h],0FFFFFFFFFFFFFFFFh  
48 8B C1             mov         rax,rcx  
83 49 24 FF          or          dword ptr [rcx+24h],0FFFFFFFFh  
C7 41 20 FF FF FF 08 mov         dword ptr [rcx+20h],8FFFFFFh  
C3                   ret
70 % kürzer. Er hat sogar zwei benachbarte 32-Bit-FFFFFFFFs zu einem 64-Bit-mov mit der 8-Bit-Konstante -1 zusammengefasst :o

fml

Und wo wir gerade dabei sind: fuck alle anderen. Wenn ich sowas einchecke, kommt immer irgendein Schlaumeier, der meint, er könne es besser machen weil eeeew Wiederholungen und eeew unleserlich und mimimimi. Irgendwann fällt mir dann auf, dass ein Modul doppelt so groß ist wie vorher, und dann darf ich die ganzen „Verbesserungen“ rückgängig machen.
Wow. Also … mandrills Bug Report ist letzten Monat anerkannt worden:
Hi, thanks for the feedback and the small repro case. I confirm the codegen you are seeing. In the "good" case, the optimizer sees a sequence of 1-byte stores to adjacent memory locations and is able to easily merge the stores into the instruction sequence you see.

In the "bad" case, we end up seeing four 1-byte assignments to a local variable, then a 4-byte store of that local. Then another 4 1-byte assignments to a local varibale, then a 4-byte store of that local. etc.

The optimization that would normally address this is copy propagation, and while we have plenty of copy propagation in the optimizer, it is clearly not firing properly in the case you provided. We'll look into addressing this optimizer shortcoming in an upcoming release.

I'll let this MSConnect item open until we fix the issue.

Thanks,
Eric Brumer
Microsoft Visual C++ Team

Im aktuellen Optimizer wird die ausgeschriebene Variante aber schon wieder zerstört. Damals war das „perfekte“ Disassembly durch Ausschreiben:
Code: Ansicht erweitern :: Alles auswählen
48 83 49 18 FF       or          qword ptr [rcx+18h],0FFFFFFFFFFFFFFFFh  
48 8B C1             mov         rax,rcx  
83 49 24 FF          or          dword ptr [rcx+24h],0FFFFFFFFh  
C7 41 20 FF FF FF 08 mov         dword ptr [rcx+20h],8FFFFFFh  
C3                   ret
70 % kürzer. Er hat sogar zwei benachbarte 32-Bit-FFFFFFFFs zu einem 64-Bit-mov mit der 8-Bit-Konstante -1 zusammengefasst :o

Jetzt (VS 2017.3) erzeugt ähnlicher Code:
Code: Ansicht erweitern :: Alles auswählen
C6 44 01 24 FF       mov         byte ptr [rcx+rax+24h],0FFh  
49 03 C9             add         rcx,r9  
49 3B CC             cmp         rcx,r12  
7C EF                jl          triangulateExtrusion+638h (024E70h)  
33 C9                xor         ecx,ecx  
48 8B 43 08          mov         rax,qword ptr [rbx+8]  
C6 44 01 18 FF       mov         byte ptr [rcx+rax+18h],0FFh  
49 03 C9             add         rcx,r9  
49 3B CC             cmp         rcx,r12  
7C EF                jl          triangulateExtrusion+64Bh (024E83h)  
33 C9                xor         ecx,ecx  
48 8B 43 08          mov         rax,qword ptr [rbx+8]  
C6 44 01 1C FF       mov         byte ptr [rcx+rax+1Ch],0FFh  
49 03 C9             add         rcx,r9  
49 3B CC             cmp         rcx,r12  
7C EF                jl          triangulateExtrusion+65Eh (024E96h)
48 8B 43 08          mov         rax,qword ptr [rbx+8]  
33 C9                xor         ecx,ecx  
C6 40 20 FF          mov         byte ptr [rax+20h],0FFh  
48 8B 43 08          mov         rax,qword ptr [rbx+8]  
C6 40 21 FF          mov         byte ptr [rax+21h],0FFh  
48 8B 43 08          mov         rax,qword ptr [rbx+8]  
C6 40 22 FF          mov         byte ptr [rax+22h],0FFh  
48 8B 43 08          mov         rax,qword ptr [rbx+8]  
C6 40 23 08          mov         byte ptr [rax+23h],8  

Kleiner Tipp: Das sind Schleifen.

VC hat echt pro Schreibvorgang eine kleine for-Schleife erzeugt und schreibt pro Iteration ein Byte. Mein WTF-Vokabular reicht nicht mehr aus. Ich dachte lange, ich hätte versehentlich einen Debug Build kompiliert oder sowas.

Nachtrag: Ich hab’s. Ich habe durch eine Referenz auf einen Zeiger geschrieben statt direkt durch eine Referenz oder direkt durch einen Zeiger. VS hat dadurch irrtümlicherweise angenommen, die Adresse könne sich ändern oder so.

Ich sage nochmal gaaanz ganz deutlich: Legt für alles eine lokale Variable an. Niemals geschachtelte Referenzen mehrmals hinschreiben.
Code: Ansicht erweitern :: Alles auswählen

// SCHLECHT:
a->b->c = 1;
a->b->d = 2;

// GUT:
auto & b = *a->b;
b.c = 1;
b.d = 2;
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6032
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Vorherige

Zurück zu Artikel, Tutorials und Materialien

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast