Was bedeutet Vektorisierung?

Lesezeit: 3 Minuten

Benutzeravatar von vehomzzz
vehomzzz

Ist es eine gute Idee, den Code zu vektorisieren? Was sind gute Praktiken in Bezug darauf, wann es zu tun ist? Was passiert darunter?

  • Siehe auch: stackoverflow.com/questions/1422149/what-is-vectorization

    – Stefan Kanon

    4. Oktober 2009 um 19:39 Uhr

Vektorisierung bedeutet, dass der Compiler erkennt, dass Ihre unabhängigen Anweisungen als eine ausgeführt werden können SIMD Anweisung. Übliches Beispiel ist, wenn Sie so etwas tun

for(i=0; i<N; i++){
  a[i] = a[i] + b[i];
}

Es wird vektorisiert als (unter Verwendung der Vektornotation)

for (i=0; i<(N-N%VF); i+=VF){
  a[i:i+VF] = a[i:i+VF] + b[i:i+VF];
}

Grundsätzlich wählt der Compiler eine Operation aus, die gleichzeitig an VF-Elementen des Arrays ausgeführt werden kann, und führt diese N/VF-mal aus, anstatt die einzelne Operation N-mal auszuführen.

Es erhöht die Leistung, stellt aber mehr Anforderungen an die Architektur.

  • Gibt es also irgendetwas, was ein Programmierer tun kann, um die Vektorisierung sicherzustellen (abgesehen von der Aktivierung der Optimierung)?

    – Jacob

    4. Oktober 2009 um 15:32 Uhr

  • Soweit ich weiß, sind Compiler in der Autovektorisierung begrenzt, daher ist es am besten, Ihren Code so trivial wie möglich zu halten. Sie können auch den generierten Assemblercode überprüfen, um festzustellen, ob der Compiler vektorisiert hat oder nicht.

    – Zed

    4. Oktober 2009 um 16:40 Uhr

  • @jacob: du kannst es nicht wirklich “sicherstellen”, vielleicht solltest du es dir ansehen openmp.org for-Methode, um dem Compiler explizit mitzuteilen, dass er vektorisieren soll.

    – D. Shawley

    4. Oktober 2009 um 17:05 Uhr

  • Vektorisierung bedeutet nicht, dass der Compiler dies tut, sondern nur, dass SIMD-Anweisungen verwendet werden. Wenn der Compiler SIMD-Code generiert, wird dies im Allgemeinen als Autovektorisierung bezeichnet.

    – jalf

    4. November 2009 um 13:15 Uhr

Wie oben erwähnt, wird die Vektorisierung verwendet, um SIMD-Befehle zu verwenden, die identische Operationen mit unterschiedlichen Daten ausführen können, die in große Register gepackt sind.

Eine allgemeine Richtlinie, die es einem Compiler ermöglicht, eine Schleife automatisch zu vektorisieren, besteht darin, sicherzustellen, dass es keine Fluss- und Antiabhängigkeits-s/w-Datenelemente in verschiedenen Iterationen einer Schleife gibt.

http://en.wikipedia.org/wiki/Data_dependency

Einige Compiler wie die Intel C++/Fortran-Compiler sind in der Lage, Code automatisch zu vektorisieren. Falls eine Schleife nicht vektorisiert werden konnte, kann der Intel-Compiler melden, warum dies nicht möglich war. Dort können Berichte verwendet werden, um den Code so zu ändern, dass er vektorisierbar wird (vorausgesetzt, es ist möglich).

Abhängigkeiten werden im Buch „Optimizing Compilers for Modern Architectures: A Dependence-based Approach“ ausführlich behandelt.

Benutzeravatar von Ganesh Gopalasubramanian
Ganesh Gopalasubramanian

Die Vektorisierung muss nicht auf ein einzelnes Register beschränkt sein, das große Daten enthalten kann. Wie die Verwendung eines ‘128’-Bit-Registers zum Halten von ‘4 x 32’-Bit-Daten. Es hängt von architektonischen Einschränkungen ab. Einige Architekturen haben unterschiedliche Ausführungseinheiten, die ihre eigenen Register haben. In diesem Fall kann dieser Ausführungseinheit ein Teil der Daten zugeführt werden und das Ergebnis einem dieser Ausführungseinheit entsprechenden Register entnommen werden.

Betrachten Sie zum Beispiel den folgenden Fall.

for(i=0; i < N; i++)
{
a[i] = ein[i] + b[i];
}

Wenn ich an einer Architektur arbeite, die zwei Ausführungseinheiten hat, dann ist meine Vektorgröße als zwei definiert. Die oben erwähnte Schleife wird neu umrahmt als

für(i=0; i<(N/2); i+=2)
{
a[i] = ein[i] + b[i] ;

a[i+1] = ein[i+1] + b[i+1];
}

HINWEIS: Die 2 in der for-Anweisung wird von der Vektorgröße abgeleitet.

Da ich zwei Ausführungseinheiten habe, werden die beiden Anweisungen innerhalb der Schleife in die beiden Ausführungseinheiten eingespeist. Die Summe wird in den Ausführungseinheiten separat akkumuliert. Abschließend wird die Summe der kumulierten Werte (von zwei Ausführungseinheiten) durchgeführt.

Die guten Praktiken sind
1. Die Einschränkungen wie die Abhängigkeit (zwischen verschiedenen Iterationen der Schleife) müssen überprüft werden, bevor die Schleife vektorisiert wird.
2. Funktionsaufrufe müssen verhindert werden.
3. Zeigerzugriff kann Aliasing erzeugen und muss verhindert werden.

Es ist die SSE-Codegenerierung.

Sie haben eine Schleife mit Float-Matrix-Code in Matrix1[i][j] + Matrix2[i][j] und der Compiler generiert SSE-Code.

Vielleicht auch einen Blick auf libSIMDx86 (Quellcode) werfen.

Ein schönes Beispiel gut erklärt ist:

Sich dafür entscheiden, Branches zu vermeiden: Ein kleines Altivec-Beispiel

1403460cookie-checkWas bedeutet Vektorisierung?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy