Ich habe zwei Arrays: char* c
und float* f
und ich muss diese Operation ausführen:
Ich suche nach einem schnellen Weg, es zu tun: ohne Bedingungen und mit SSE (4.2 oder AVX) wenn möglich.
Wenn float
anstelle von char
zu schnellerem Code führt, kann ich meinen Code so ändern, dass er nur floats verwendet:
Danke
Der folgende Code verwendet SSE2 (glaube ich).
Er führt 16 Vergleiche von Bytes in einer Anweisung durch ( _mm_cmpgt_epi8
). Es setzt voraus, dass char
signiert ist; Wenn Ihr char
unsigniert ist, erfordert es zusätzliches Fiedeln (das höchstwertige Bit jedes char
wird umgedreht).
Die einzige Nicht-Standard-Sache ist die magische Zahl 3f80
, um die Gleitkommakontante 1.0
darzustellen. Die magische Zahl ist tatsächlich 0x3f800000
, aber die Tatsache, dass die 16 LSB Null sind, macht es möglich, das Bit-Fiedeln effizienter zu machen (unter Verwendung von 16-Bit-Masken anstelle von 32-Bit-Masken).
Wenn Sie auf Floats umschalten, können Sie die Schleife in GCC automatisch vektorisieren und sich nicht um intrinsische Daten kümmern. Der folgende Code wird tun, was Sie wollen und auto-vektorisiert.
%Vor%Kompiliert mit
%Vor%Sie können die Ergebnisse sehen und den Code selbst bearbeiten und auf coliru kompilieren. MSVC2013 hat die Schleife jedoch nicht vektorisiert.
Umwandlung nach
%Vor%- wird auch mit Intel Compiler automatisch vektorisierbar (von anderen auch für gcc als zutreffend)
Falls Sie eine verzweigte Schleife im Allgemeinen automatisch vektorisieren müssen, - können Sie auch #pragma ivdep oder pragma simd ( Das letzte ist ein Teil von Intel Cilk Plus und OpenMP 4.0-Standards). Diese Pragmas auto-vectorize geben Code für SSE, AVX und zukünftige Vektorerweiterungen portabel weiter (wie AVX512 ). Diese Pragmas werden von Intel Compiler (alle bekannten Versionen), Cray und PGI Compilern (nur ivdep), wahrscheinlich kommenden GCC4.9 Releases und teilweise unterstützt von MSVC (nur ivdep) ab VS2012 unterstützt.
Für das gegebene Beispiel habe ich nichts geändert (habe if und char * behalten), habe einfach pragma ivdep:
hinzugefügt %Vor%Auf meinem Core i5 ohne AVX-Unterstützung (nur SSE3), für n = 32K (32000000), wird c [i] zufällig generiert und mit c_thresh gleich 0 (wir verwenden signed char), gegebener Code bietet ~ 5x Beschleunigung durch Vektorisierung mit ICL.
Vollständiger Test (mit zusätzlicher Testfall-Korrektheitsprüfung) ist verfügbar hier (es ist coliru, dh gcc4.8 nur, kein ICL / Cray; deshalb wird es nicht in coliru env) vektorisiert.
Es sollte möglich sein, weitere Leistungsoptimierungen durchzuführen, indem Sie mit mehr Pragma / Optimierungen für das Pre-Fetching, Alignment und Typkonvertierungen umgehen. Auch das Hinzufügen von restrict keyword (oder restrict abhängig vom verwendeten Compiler) kann anstelle von ivdep / simd für einen einfachen Fall verwendet werden, während für allgemeinere Fälle die pragmas simd / ivdep am mächtigsten sind.
Hinweis: Tatsächlich weist #pragma ivdep "den Compiler an, vermutete kreuz-iterationale Abhängigkeiten zu ignorieren" ( grob spricht diejenigen an, die zu Datenrennen führen, wenn Sie dieselbe Schleife parallelisieren). Compiler sind in diesen Annahmen aus bekannten Gründen sehr konservativ. Im gegebenen Fall gibt es offensichtlich keine Schreib-nach-Lese- oder Lese-nach-Schreib-Abhängigkeiten. Bei Bedarf könnte man das Vorhandensein solcher Abhängigkeiten zumindest bei gegebener Auslastung mit dynamischen Tools wie Advisor XE Korrektheitsanalyse, wie in meinen Kommentaren unten gezeigt.
Tags und Links optimization c performance sse simd