So verwenden Sie den verbundenen Speicherzugriff

8

Ich habe 'N' Threads, die gleichzeitig auf dem Gerät ausgeführt werden, von dem sie M * N float aus dem globalen Speicher benötigen. Was ist der richtige Weg, um auf den globalen Speicher zuzugreifen? Wie kann der Shared Memory helfen?

    
BehzadX 03.07.2011, 13:51
quelle

1 Antwort

15

Normalerweise kann ein guter zusammengewachsener Zugriff erreicht werden, wenn die benachbarten Threads auf benachbarte Zellen im Speicher zugreifen. Wenn also tid den Index Ihres Threads enthält, dann greifen Sie auf:

  • arr[tid] --- ergibt eine perfekte Koaleszenz
  • arr[tid+5] --- ist fast perfekt, wahrscheinlich falsch ausgerichtet
  • arr[tid*4] --- ist nicht mehr so ​​gut, wegen der Lücken
  • arr[random(0..N)] --- schrecklich!

Ich spreche aus der Perspektive eines CUDA-Programmierers, aber ähnliche Regeln gelten auch in einer einfachen CPU-Programmierung, obwohl die Auswirkungen dort nicht so groß sind.

"Aber ich habe so viele Arrays, die jeder etwa zwei oder drei Mal länger hat als die Anzahl meiner Threads und die Verwendung des Musters wie" arr [tid * 4] "ist unvermeidlich. Was könnte eine Heilung dafür sein ? "

Wenn der Offset ein Vielfaches einer höheren 2-Potenz ist (z.B. 16 · x oder 32 · x), ist dies kein Problem. Wenn Sie also ein relativ langes Array in einer For-Schleife verarbeiten müssen, können Sie Folgendes tun:

%Vor%

(Obige Array-Größe ist ein multiple der Anzahl der Threads)

Wenn also die Anzahl der Threads ein Vielfaches von 32 ist, ist der Speicherzugriff gut.

Noch einmal: Ich spreche aus der Perspektive eines CUDA-Programmierers. Für verschiedene GPUs / Umgebungen benötigen Sie möglicherweise weniger oder mehr Threads für die perfekte Koaleszenz des Speicherzugriffs, aber es sollten ähnliche Regeln gelten.

Ist "32" mit der Warp-Größe verknüpft, die parallel zum globalen Speicher zugreift?

Obwohl nicht direkt, gibt es eine Verbindung. Der globale Speicher ist in Segmente von 32, 64 und 128 Bytes unterteilt, auf die durch Halbketten zugegriffen wird. Je mehr Segmente Sie für eine bestimmte Speicherabrufanweisung zugreifen, desto länger dauert es. Im CUDA-Programmierleitfaden können Sie mehr in Details lesen, zu diesem Thema gibt es ein ganzes Kapitel: "5.3. Maximieren des Speicherdurchsatzes".

Außerdem habe ich etwas über den geteilten Speicher gehört, um den Speicherzugriff zu lokalisieren. Ist dies für die Koaleszenz von Speicher bevorzugt oder haben sie ihre eigenen Schwierigkeiten? Shared Memory ist viel schneller, da es auf dem Chip liegt, aber seine Größe ist begrenzt. Der Speicher ist nicht wie global segmentiert, Sie können fast zufällig auf keine Strafkosten zugreifen. Es gibt jedoch Speicherbankzeilen mit einer Breite von 4 Bytes (Größe von 32-Bit-Int). Die Speicheradresse, die jeder Threadzugriff hat, sollte modulo 16 (oder 32, abhängig von der GPU) unterschiedlich sein. Die Adresse [tid*4] ist also viel langsamer als [tid*5] , weil der erste Zugriff nur die Bänke 0, 4, 8, 12 und die letzten 0, 5, 10, 15, 4, 9, 14, ... ( Bank-ID = Adresse modulo 16).

Auch hier können Sie mehr im CUDA Programmierhandbuch lesen.

    
CygnusX1 03.07.2011 15:09
quelle

Tags und Links