Erzwingt, dass CUDA das Register für eine Variable verwendet

8

Ich habe viele unbenutzte Register in meinem Kernel. Ich würde CUDA gern sagen, dass ich ein paar Register für einige Daten verwenden soll, anstatt jedes Mal, wenn ich es brauche, eine globale Datenlese durchzuführen. (Ich kann kein geteiltes Mem verwenden.)

%Vor%

kompilieren w /: nvcc -arch sm_20 --ptxas-options = -v simple.cu, und ich bekomme ein   0 Bytes Stapelrahmen, 0 Bytes Überlaufspeicher, 0 Bytes Überlauflasten   Verwendete 2 Register, 40 Bytes cmem [0]

%Vor% Die

Registrierung Deklaration tut nichts.
  0 Bytes Stapelrahmen, 0 Bytes Überlaufspeicher, 0 Bytes Überlauflasten   Verwendete 2 Register, 40 Bytes cmem [0]

%Vor%

volatile Deklaration erstellt Stapelspeicher:
  4096 Byte Stack-Frame, 0 Byte Überlaufspeicher, 0 Byte Überlauflast
  Verwendet 21 Widerstände, 40 Bytes Cmem [0]

1) Gibt es eine einfache Möglichkeit, dem Compiler mitzuteilen, Registerraum für eine Variable zu verwenden?
2) Wo ist 'stack frame': register, global mem, local mem, ...? Was ist ein Stapelrahmen? (Seit wann hat die GPU einen Stack? Ein virtueller Stack?)
3) Die Datei simple.ptx ist grundsätzlich leer: (nvcc -arch sm_20 -ptx simple.cu)

%Vor%

Irgendeine Idee, wo ich den echten Computer / kompilierten Code finden kann?

    
Doug 28.08.2012, 21:41
quelle

2 Antworten

15
  • Dynamisch indizierte Arrays können nicht in Registern gespeichert werden, da die GPU-Registerdatei nicht dynamisch adressierbar ist.
  • Skalare Variablen werden vom Compiler automatisch in Registern gespeichert.
  • Statisch-indiziert (dh wo der Index zur Kompilierungszeit bestimmt werden kann), kleine Arrays (z. B. weniger als 16 Floats) darf vom Compiler in Registern gespeichert werden.

SM 2.0 GPUs (Fermi) unterstützen nur bis zu 63 Register pro Thread. Wenn dies überschritten wird, werden die Registerwerte aus dem lokalen (außerhalb des Chips befindlichen) Speicher, der von der Cache-Hierarchie unterstützt wird, verschüttet / gefüllt. SM 3.5 GPUs erweitern dies auf bis zu 255 Register pro Thread.

Im Allgemeinen ist, wie Jared erwähnt, die Verwendung von zu vielen Registern pro Thread nicht wünschenswert, weil es die Belegung reduziert und daher die Latenz-Verdeckungsfähigkeit im Kernel verringert. Grafikprozessoren profitieren von der Parallelität, indem sie die Speicherlatenz mit Arbeiten anderer Threads abdecken.

Daher sollten Sie Arrays wahrscheinlich nicht in Registern optimieren. Stellen Sie stattdessen sicher, dass der Speicherzugriff auf diese Arrays über Threads so nah wie möglich an der Reihenfolge ist, damit Sie die Koaleszenz maximieren (d. H. Speichertransaktionen minimieren).

Das Beispiel, das Sie angeben, kann ein Fall für gemeinsam genutzten Speicher sein wenn :

  1. Viele Threads im Block verwenden die gleichen Daten oder
  2. Die Pro-Thread-Array-Größe ist klein genug, um genügend Platz für alle Threads in mehreren Thread-Blöcken zu reservieren (1024 Floats pro Thread ist viel).

Wie bereits erwähnt, ist der Grund, warum Ihr Kernel nur zwei Register verwendet, der, dass Sie nichts Nützliches mit den Daten im Kernel machen und der tote Code wurde vom Compiler eliminiert.

    
harrism 29.08.2012, 01:04
quelle
2

Wie bereits erwähnt, können Register (und der "param space" von PTX) nicht dynamisch indiziert werden. Um dies zu tun, müsste der Compiler Code wie für einen switch...case -Block ausgeben, um den dynamischen Index in einen unmittelbaren zu verwandeln. Ich bin mir nicht sicher, ob es jemals automatisch funktioniert. Sie können dabei helfen, eine Tupel-Struktur mit fester Größe und switch...case zu verwenden. C / C ++ Metaprogrammierung ist wahrscheinlich die Waffe der Wahl, um Code wie diesen beherrschbar zu halten.

Verwenden Sie für CUDA 4.0 außerdem den Befehlszeilenschalter -Xopencc=-O3 , um alles andere als einfache Skalare (z. B. Datenstrukturen) den Registern zuzuordnen (siehe dieser Beitrag ). Für CUDA & gt; 4.0 Sie müssen die Debug-Unterstützung deaktivieren (keine Befehlszeilenoption -G - die Optimierung erfolgt nur, wenn das Debugging deaktiviert ist).

PTX-Ebene erlaubt viel mehr virtuelle Register als die Hardware. Diese werden bei Ladezeit den Hardware-Registern zugeordnet. Mit dem von Ihnen angegebenen Registerlimit können Sie eine Obergrenze für die Hardwareressourcen festlegen, die von der generierten Binärdatei verwendet werden. Er dient als Heuristik für den Compiler, um zu entscheiden, wann Spool-Register (siehe unten) beim Kompilieren an PTX übertragen werden, damit bestimmte Nebenläufigkeitsanforderungen erfüllt werden können (siehe "Startgrenzen", "Belegung" und "gleichzeitige Kernel-Ausführung" in der CUDA-Dokumentation) - Sie könnten auch diese interessanteste Präsentation genießen.

Für Fermi-GPUs gibt es maximal 64 Hardware-Register. Die 64. (oder die letzte - wenn weniger als das Maximum der Hardware verwendet wird) wird von der ABI als der Stapelzeiger und somit für "Registerüberlauf" verwendet (es bedeutet das Freigeben von Registern durch temporäres Speichern ihrer Werte auf dem Stapel und geschieht, wenn mehr Register vorhanden sind) werden benötigt als verfügbar), so ist es unantastbar.

    
Dude 29.08.2012 20:28
quelle

Tags und Links