Performance Verbesserungen mit SIMD (Single Instruction multiple data)

„Single Instruction Multiple Data“ (SIMD) bezieht sich auf eine Art von paralleler Datenverarbeitung, bei der eine CPU oder ein Prozessor mehrere gleiche Operationen auf mehreren Daten gleichzeitig ausführt. Diese Methode wird oft eingesetzt, wenn sehr große und ähnliche Datenmengen effizient verarbeitet werden müssen.

Um sich das genauer vorzustellen, können wir uns das Beispiel der Vektor-Addition ansehen. Normalerweise würden wir jedes Element der Vektoren einzeln durchlaufen und addieren, um den Ergebnisvektor zu erhalten.

Im Code Beispiel würde die Implementation so aussehen:

C
int main(){
  float a[4] = {1.0f, 2.0f, 3.0f, 4.0f};
  float b[4] = {5.0f, 6.0f, 7.0f, 8.0f};
  float c[4];

  for (int i = 0; i < 4; i++) {
    c[i] = a[i] + b[i];
  }

  return 0;
}

Deutlich zu erkennen ist, dass der Operator immer derselbe ist (single instruction). Die Daten ändern sich jedoch mit jedem Schleifendurchlauf (multiple data).

SIMD ermöglicht die Ausführung derselben Addition in nur einem Schritt anstelle von vier Schritten, indem die Arrays in SIMD-Register kopiert werden. Diese Register haben typischerweise Größen von 128, 256 oder 512 Bit. Im vorliegenden Beispiel wird ein 128-Bit-SIMD-Register verwendet, da genau 4 float-Werte darin Platz haben.

C
#include <xmmintrin.h>

int main() {
  float a[4] = {1.0f, 2.0f, 3.0f, 4.0f};
  float b[4] = {5.0f, 6.0f, 7.0f, 8.0f};
  float c[4];

  __m128 vecA = _mm_load_ps(a);
  __m128 vecB = _mm_load_ps(b);
  __m128 vecC = _mm_add_ps(vecA, vecB);
  _mm_store_ps(c, vecC);

  return 0;
}

Muss ich meinen Code extra anpassen, um von SIMD zu profitieren?

Ja und nein. Moderne Compiler sind in der Lage solche Konstrukte zu identifizieren und automatisch in SIMD-Code umzuwandeln (Automatic vectorization). Auch wenn dies in der Theorie möglich ist erkennen Compiler nicht jede Stelle, vor allem an komplizierten Code Stellen. Daher ist es ratsam diese Explizit mit den C Compiler Intrinsics zu schreiben.

Hardwareimplementierung

SIMD wird in modernen CPUs und Prozessoren durch spezielle Schaltkreise implementiert, die als SIMD-Units oder Vector Units bezeichnet werden. Diese Schaltkreise sind speziell für die parallele Verarbeitung von Daten ausgelegt und können eine hohe Anzahl von Daten gleichzeitig bearbeiten.

In CPUs von Intel und AMD wird SIMD durch die SSE (Streaming SIMD Extensions) und AVX (Advanced Vector Extensions) implementiert. Die SSE-Technologie unterstützt SIMD-Operationen auf 128-Bit-Datenblöcken, während AVX bis zu 256-Bit-Datenblöcke unterstützt. AVX-512 erweitert die Technologie auf 512-Bit-Datenblöcke.

Bei Arm Prozessoren werden die SIMD-Funktionalitäten durch den Neon Befehlssatz hinzugefügt. Diese haben eine Breite von 128 Bit.

Hinweise

Wichtig zu berücksichtigen ist, dass das Kopieren von Daten zwischen den normalen und den SIMD-Registern einen zusätzlichen Overhead verursacht, der die Laufzeit des Programms beeinträchtigen kann. Daher sollte das Kopieren nur so selten wie möglich erfolgen, um negative Auswirkungen auf die Gesamtlaufzeit zu vermeiden.

Zusätzlich beschränkt die Verwendung von C-Compiler-Intrinsics die Zielplattformen, da nicht alle Prozessoren über SIMD-Register verfügen. In solchen Fällen ist es möglicherweise notwendig, eine alternative Codeversion ohne SIMD zu implementieren, um auch die Prozessoren ohne diese Register zu unterstützen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert