{"id":3804,"date":"2018-12-08T13:52:37","date_gmt":"2018-12-08T12:52:37","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=3804"},"modified":"2018-12-08T13:52:37","modified_gmt":"2018-12-08T12:52:37","slug":"c-guns-level-of-indirection-dereferencing","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=3804","title":{"rendered":"C++ Guns: Level of Indirection (\"dereferencing\")"},"content":{"rendered":"<p>Die Performance ist ein Opfer von Level of Indirection. Jetzt auch bei mir. Ich will keinen langweiligen Code zeigen wie so etwas aussieht, oder wie man es verhindern kann. Viel interessanter ist es doch, wie das aus Assembler Ebene aussieht.<br \/>\nDazu zwei Assembler Ausz\u00fcge. Der erste mit zwei zus\u00e4tzlichen Indirektionen. Es wird auf das i-th Element eines <em>std::vector<\/em> zugegriffen und zur\u00fcck gegeben.<\/p>\n<pre class=\"brush: plain; highlight: [6,7]; title: ; notranslate\" title=\"\">\r\nfunc(std::vector&lt;T&gt; const&amp;, int):\r\n        movq    %rdi, %rax       }\r\n        movslq  %edx, %rdx       |\r\n        salq    $4, %rdx         | Addressberechnung\r\n        addq    (%rsi), %rdx     }\r\n        movq    (%rdx), %rdx     * Indirektion \r\n        movq    (%rdx), %rdx     * Indirektion\r\n        movdqu  (%rdx), %xmm0    }\r\n        movups  %xmm0, (%rdi)    |\r\n        movdqu  16(%rdx), %xmm1  | Kopieren der 4 double Variablen\r\n        movups  %xmm1, 16(%rdi)  }\r\n        ret\r\n<\/pre>\n<p>Ohne zweimalige Indirektion:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nfunc2(std::vector&lt;T&gt; const&amp;, int):\r\n        movq    %rdi, %rax        }\r\n        movslq  %edx, %rdx        |\r\n        salq    $5, %rdx          | Addressberechnung\r\n        addq    (%rsi), %rdx      }\r\n        movdqu  (%rdx), %xmm0     }\r\n        movups  %xmm0, (%rdi)     |\r\n        movdqu  16(%rdx), %xmm1   | Kopieren der 4 double Variablen\r\n        movups  %xmm1, 16(%rdi)   }\r\n        ret\r\n<\/pre>\n<p>Es sind zwei Dinge zu erkennen.<br \/>\nErstens gibt es zwei zus\u00e4tzliche mov Anweisungen, welche eine Dereferenzierung eines Pointers bewirken. Die zus\u00e4tzliche Arbeit den Befehl zu bearbeiten ist nicht das Problem. Vielmehr, dass die Daten nicht mehr hintereinander im RAM stehen. Es wird im RAM umher gesprungen. Dies geht bekanntlich auf die Performance, Cache misses u.s.w.<\/p>\n<p>Bei dem konkreten Problem, aus dem dieses Beispiel hervorgegangen ist, lief das Programm nach dem Entfernen der zwei Indirektionen 10 mal schneller!<\/p>\n<p>Zweitens ist zu erkennen, dass die zur\u00fcck gegebenen Variablen aus 4 double Werten besteht, aber nur zwei Kopieraktionen zu erkennen sind. Von dem Register rdx, nach xmm0, nach rdi. Und noch einmal mit einem Offset von 16Byte (2 double Werte). Der Compiler hat erkannt, dass SIMD angewendet werden kann. Das Kopieren von zwei Werten mit einer Instruktion. Und das ohne zus\u00e4tzlichen Bem\u00fchungen meinerseits C++ Code extra SIMD tauglich zu schreiben!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Die Performance ist ein Opfer von Level of Indirection. Jetzt auch bei mir. Ich will keinen langweiligen Code zeigen wie so etwas aussieht, oder wie man es verhindern kann. Viel interessanter ist es doch, wie das aus Assembler Ebene aussieht. Dazu zwei Assembler Ausz\u00fcge. Der erste mit zwei zus\u00e4tzlichen Indirektionen. Es wird auf das i-th [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[17],"class_list":["post-3804","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-cpp"],"_links":{"self":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3804","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3804"}],"version-history":[{"count":14,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3804\/revisions"}],"predecessor-version":[{"id":3818,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3804\/revisions\/3818"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3804"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3804"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3804"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}