{"id":3476,"date":"2018-05-15T09:05:58","date_gmt":"2018-05-15T08:05:58","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=3476"},"modified":"2018-05-15T09:05:58","modified_gmt":"2018-05-15T08:05:58","slug":"c-guns-simdarray-stdarray-for-sse","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=3476","title":{"rendered":"C++ Guns: SIMDarray; std::array for SSE"},"content":{"rendered":"<p>SIMD (Single Instruction, Multiple Data) - besser bekannt als MMX, SSE, AVX u.s.w ist super f\u00fcr die Datenverarbeitung geeignet. So k\u00f6nnen, je nach Ausstattung der CPU, viele Gleitkommazahlen gleichzeitig verarbeitet werden. So bietet SSE 128 bit, also 16 Byte, gro\u00dfe Register. Hier k\u00f6nnen zwei double Variable gleichzeitig verarbeitet werden. Zum Beispiel f\u00fcr einfach Point2D Operationen wie Addition, Division. Hingegen ist es mit AVX und 256 bit Register M\u00f6glich gleich vier double Variablen gleichzeitig zu verarbeiten (Point3D). Seit 2013 gibt es AVX512 mit 512 bit bzw. 64 Byte Register. Willkommen bei PointND.<\/p>\n<p>Die Compiler unterst\u00fctzen dies auch gut, allerdings wird nicht so ohne weiteres der Assember Code erzeugt, den ich mir vorstelle. Ich m\u00f6chte nicht in Schleifen tollen SIMD Code erstellt bekommen, sondern bei normalen Operationen von PointND wie + - * \/. Einfach, weil die Schleifen in meinem Algorithmen nie trivial sind und ich sehe mehr Optimierungspotential f\u00fcr einfache PointND Operationen.<\/p>\n<p>Einfaches Beispiel<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#include &lt;array&gt;\r\n\r\nstruct Point2D : public std::array&lt;double,2&gt; {\r\n};\r\n\r\ninline Point2D operator+(const Point2D&amp; lhs, const Point2D&amp; rhs) {\r\n    return Point2D{lhs&#x5B;0]+rhs&#x5B;0], lhs&#x5B;1]+rhs&#x5B;1]};\r\n}\r\n\r\nauto func(const Point2D&amp; p1, const Point2D&amp; p2) {\r\n    return p1+p2;\r\n}\r\n<\/pre>\n<p>Der generierte Assembercode enth\u00e4lt zwei Additions-Instruktionen addsd. Die beiden letzten Buchstaben geben den Datentype an und ob es eine gepackte Operation ist, also mehrere Zahlen gleichzeitig. sd steht f\u00fcr single value double precision. Also eine Zahl. Erwartet h\u00e4tte ich aber addpd - packed value double precision. <\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\noperator+(Point2D const&amp;, Point2D const&amp;):\r\n  movsd xmm0, QWORD PTR &#x5B;rdi]\r\n  addsd xmm0, QWORD PTR &#x5B;rsi]\r\n  movsd xmm1, QWORD PTR &#x5B;rdi+8]\r\n  addsd xmm1, QWORD PTR &#x5B;rsi+8]\r\n<\/pre>\n<p>Man kann dem Compiler mit der Erweiterung \"Vector Instructions\" aber etwas auf die Spr\u00fcnge helfen. Durch die Definition des Attributs vector_size wird SSE Code produziert, so wie ich es mir vorstelle. Hier das Beispiel:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#include &lt;array&gt;\r\n\r\nstruct Point2D {\r\n    typedef double v2d __attribute__ ((vector_size (16)));\r\n    v2d _data;\r\n\r\n    const double&amp; operator&#x5B;](size_t pos) const {\r\n        return _data&#x5B;pos];\r\n    }\r\n};\r\n\r\ninline Point2D operator+(const Point2D&amp; lhs, const Point2D&amp; rhs) {\r\n    return Point2D{lhs._data + rhs._data};\r\n}\r\n\r\nauto func(const Point2D&amp; p1, const Point2D&amp; p2) {\r\n    return p1+p2;\r\n}\r\n<\/pre>\n<p>Es wird nur noch eine Addition Instruktion erzeugt. Wir haben die Geschwindigkeit der Operation verdoppelt!<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nfunc(Point2D const&amp;, Point2D const&amp;):\r\n  movapd xmm0, XMMWORD PTR &#x5B;rdi]\r\n  addpd xmm0, XMMWORD PTR &#x5B;rsi]\r\n<\/pre>\n<p>Darauf l\u00e4sst sich doch aufbauen und analog zu std::array ein SIMDarray erzeugen. Damit ist es M\u00f6glich f\u00fcr beliebige Arithmetische Typen beliebiger Anzahl effizienten SIMD Code zu erzeugen. Gesagt, getan. Die Klasse findet ihr in ACPL core\/util\/SIMDarray.hpp<\/p>\n<p><a href=\"https:\/\/sourceforge.net\/p\/acpl\/code\/ci\/master\/tree\/acpl\/acpllib\/include\/core\/util\/SIMDarray.hpp\">https:\/\/sourceforge.net\/p\/acpl\/code\/ci\/master\/tree\/acpl\/acpllib\/include\/core\/util\/SIMDarray.hpp<\/a><\/p>\n<p><a href=\"https:\/\/gcc.gnu.org\/onlinedocs\/gcc-8.1.0\/gcc\/Vector-Extensions.html#Vector-Extensions\">https:\/\/gcc.gnu.org\/onlinedocs\/gcc-8.1.0\/gcc\/Vector-Extensions.html#Vector-Extensions<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>SIMD (Single Instruction, Multiple Data) - besser bekannt als MMX, SSE, AVX u.s.w ist super f\u00fcr die Datenverarbeitung geeignet. So k\u00f6nnen, je nach Ausstattung der CPU, viele Gleitkommazahlen gleichzeitig verarbeitet werden. So bietet SSE 128 bit, also 16 Byte, gro\u00dfe Register. Hier k\u00f6nnen zwei double Variable gleichzeitig verarbeitet werden. Zum Beispiel f\u00fcr einfach Point2D Operationen [&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-3476","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\/3476","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=3476"}],"version-history":[{"count":5,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3476\/revisions"}],"predecessor-version":[{"id":3481,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3476\/revisions\/3481"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3476"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3476"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3476"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}