GPU Drano ist ein statisches Analyse -Tool für GPU -Programme. Eine der Analysen in GPU -Drano ist die Suche nach unbekoteten Speicherzugriffen im CUDA -Code. Die andere von GPU Drano unterstützte Analyse ist eine Analyse, um die unabhängige Blockgröße von GPU-Programmen zu beweisen.
Moderne GPUs -Bündelfäden in Warps. Alle Threads in einem Warp führen Operationen in Lockstep durch. Der Speicherzugriff auf verschiedene Speicherorte kann in eine einzelne Last/Speicherung zusammengefasst werden, wenn der Speicher benachbart oder in der Speicher genügend genügend ist. Wenn der Speicher, der von einer Kette zugänglich ist, weit voneinander entfernt ist, sind mehrere Ladungen/Geschäfte erforderlich, um die Speichertransaktion abzuschließen, und wir sagen, der Zugriff ist unbekannt .
Ein GPU-Kernel soll blockgroße unabhängig sein. Wenn Sie die Blockgröße ändern und gleichzeitig die Gesamtzahl der Threads beibehalten, verstößt nicht die Funktionalität des Programms. Dies ist wichtig für die korrekte Stimmung der Blockgröße in GPU-Programmen, die häufig zur Verbesserung der Programmleistung verwendet werden.
Wir haben auch eine dynamische Analyse implementiert, um unbekotete Zugriffe zu identifizieren, die in diesem Repository verfügbar ist.
GPU Drano wird als Compiler -Pass für LLVM mit der Open Source CUDA -Implementierung von Google implementiert: gpucc . Daher ist Drano eng mit LLVM gekoppelt.
Drano benötigt LLVM Version 6.0 oder höher. Es erfordert auch CUDA -Toolkit (Version 7.5 oder höher) von Nvidia. Es wurde auf Ubuntu 16.04 LTS getestet, sollte jedoch mit den meisten vorhandenen Linux -Systemen arbeiten.
Die statische Analyse selbst erfordert keine GPU. Um die Programme auszuführen und dynamische Anlaysis auszuführen, sind eine NVIDIA -GPU und kompatible Treiber erforderlich. Überprüfen Sie die Systemanforderungen von NVIDIA, um weitere Informationen zu erhalten.
Die Details des Algorithmus und der Designoptionen finden Sie in folgenden Papieren:
Das Skript installnrun.sh in den Projekten enthalten die Schritte zum Erstellen und Ausführen von GPU -Drano in einem Ubuntu -System. Das Skript ausführen,
ROOT_DIR auf den Pfad zum heruntergeladenen Ordner.sh installnrun.shDies würde automatisch GPU -Drano auf einem Linux -System installieren. Wir beschreiben die Installationsschritte für die Installation der unkohelzierten Zugriffsanalyse hier weiter. Die Installation für die Unabhängigkeitsanalyse der Blockgröße (auch als Blockgröße invariale Analyse bezeichnet) kann ähnlich durchgeführt werden.
Holen Sie sich LLVM -Quelle:
Stellen Sie sicher, dass subversion installiert ist. Laden Sie die neueste Version von LLVM herunter:
svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
Holen Sie sich Klangquelle:
Ändern Sie Ihr aktuelles Arbeitsverzeichnis in llvm/tools/ und schauen Sie sich clang aus dem SVN -Repository an:
svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
GPU -Drano zu LLVM hinzufügen:
Kopieren Sie src/ Ordner von GPU Drano in das Verzeichnis llvm/lib/Transforms/UncoalescedAnalysis in Ihrem Quellcode:
cp -r src/abstract-execution/* llvm/lib/Transforms/UncoalescedAnalysis
cp -r src/uncoalesced-analysis/* llvm/lib/Transforms/UncoalescedAnalysis
Dadurch wird ein Ordner namens llvm/lib/Transforms/UncoalescedAnalysis/ erstellt. Wir müssen unseren Pass mit dem LLVM -Build -System cmake registrieren. Daher add_subdirectory(UncoalescedAnalysis) an llvm/lib/Transforms/CMakeLists.txt
Beispiel cmakelists.txt -Datei:
$> more CMakeLists.txt
add_subdirectory(Utils)
add_subdirectory(Instrumentation)
add_subdirectory(InstCombine)
add_subdirectory(Scalar)
add_subdirectory(IPO)
add_subdirectory(Vectorize)
add_subdirectory(Hello)
add_subdirectory(ObjCARC)
add_subdirectory(Coroutines)
add_subdirectory(UncoalescedAnalysis)
Bauen Sie LLVM und GPU Drano:
Erstellen Sie aus dem Root -Verzeichnis von Drano ein build/ Verzeichnis. Wechseln Sie dann das Verzeichnis in das build/ Verzeichnis. Stellen Sie sicher, dass CMake auf dem System installiert ist. Führen Sie hier die folgenden Befehle aus:
cmake ../llvm
make
Das ist cmake mit dem Pfad zum LLVM -Verzeichnis ( ../llvm ). CMake konfiguriert LLVM für Ihr System. Es sollte mehrere Dateien in Ihrem aktuellen Arbeitsverzeichnis ( build/ ) generieren. Der Befehl make Builds LLVM und Drano.
Im Idealfall verwenden Sie make -j N , wobei n Ihre Anzahl von Kernen parallel aufgebaut ist, da LLVM es lange dauert, bis sie bauen.
Hinweis : Der LLVM -Build benötigt eine große Menge Speicher, um sich speziell für den Verknüpfungsschritt zu kompilieren. Wenn Sie <8 Gigabyte von Ram haben, kann LLVM möglicherweise nicht bauen. In diesem Fall können Sie ohne die Option -j make wiedergeben. Dadurch wird nur die fehlgeschlagenen Teile des Builds neu kompiliert und sparen immer noch mehr Zeit, als -j von Anfang an nicht zu verwenden.
Installieren Sie LLVM und GPU Drano sudo make install . Dies sollte die Bibliotheken und Binärdateien im Standardort (oder an den angegebenen Speicherort) installieren. Wenn diese Anleitung lokal installiert wird, wird davon ausgegangen, dass Bash den Befehl auf seinem Pfad finden kann.
Das obige ist ein Kurzanleitung. Wenn Sie mit LLVM nicht vertraut sind
Das Skript installnrun.sh beschreibt kurz den Prozess zum Erstellen von NVIDIA -Treibern, Toolkit und dem SDK. Das Skript wurde kommentiert, um das Risiko zu vermeiden, bestehende NVIDIA -Treiber zu überschreiben. Beachten Sie, dass wir nur das Toolkit und das SDK benötigen, um die statische Analyse auszuführen. Wir brauchen auch Treiber und eine arbeitende GPU, um dynamische Analysen und CUDA -Programme selbst durchzuführen.
Installieren Sie die NVIDIA -Treiber, CUDA Toolkit und SDK: Weitere Informationen finden Sie im NVIDIA -Installationsleitfaden.
Zusammenfassend lässt sich sagen, dass Sie das automatische Download -Tool verwenden können, um die erforderlichen Treiber und SDK zu installieren.
Wenn Sie bereits über die erforderlichen Treiber und SDK installiert sind, können Sie diesen Schritt überspringen. Es ist wahrscheinlich keine gute Idee, Ihre vorhandenen Treiber außer Kraft zu setzen, da dies Ihr System möglicherweise unbrauchbar macht.
Möglicherweise benötigen Sie G ++-Multilib, um die erforderlichen Bibliotheken zu installieren, die von clang erforderlich sind.
Dieser Schritt ist optional . Ein einfaches CUDA -Programm wie "Hello World" sollte jetzt mit clang oder clang++ kompilieren:
clang -x cuda helloWorld.cu
Die Option -x cuda gibt die Sprache ausdrücklich an. Sie können es auch weglassen und Clang wird dies als CUDA -Programm schließen.
Hinweis: Ihre Clang -Installation muss möglicherweise nicht in der Lage sein, mehrere interne LLVM -Funktionen zu finden. In diesem Fall müssen Sie möglicherweise -lcudart einbeziehen. Möglicherweise müssen Sie auch auf den Ort des cudart.so hinweisen.
Beispiel:
clang -x cuda -L /usr/local/cuda/targets/x86_64-linux/lib/ -lcudart helloWorld.cu
Der Weg zu Ihrem Cudart.So kann je nach Ihrem System unterschiedlich sein.
LLVM hätte ein freigegebenes Objekt generieren sollen .so build/lib/ -Datei namens LLVMUncoalescedAnalysis.so .
Der LLVM Complier clang generiert beim Kompilieren von CUDA -Programmen ein separates Gerät (den GPU -Kernelcode) und den Host (Code, der auf CPU) IR -Dateien ausgeführt wird. GPU Drano analysiert die LLVM -IR -Dateien für Gerätecode.
Lassen Sie uns beispielsweise den Rodinia -Kernelcode für den gaussian Benchmark analysieren. Wir wechseln das Verzeichnis in rodinia_3.1/cuda/gaussian/ .
Zuerst haben wir Clang generieren LLVM IR -Dateien für den Code, an dem wir interessiert sind:
clang++ -S -g -emit-llvm gaussian.cu
Beachten Sie, dass wir mit dem Debug -Symbol -g kompilieren können, um die Debug -Informationen zu Quellcodeorten im generierten IR zu halten. Dies wird verwendet, um den Quellcode -Standorte mit potenziellen unbekoteten Zugriffen von LLVM IR zu zeigen.
Die Zusammenstellung generiert zwei Dateien:
gaussian-cuda-nvptx64-nvidia-cuda-sm_20.ll
gaussian.ll
Wir können dann die statische Analyse durch LLVM- opt durchführen, indem wir den Pfad zum Binärgpu-Drano-Binary angeben und den ausgeführten Pass -interproc-uncoalesced-analysis angeben. Dieser Pass ist eine interprocedurale Analyse zur Erkennung unkohelierter Zugriffe. Es beginnt mit der Analyse der obersten Funktion im Call-Graph und geht dann mit der Analyse ihrer Callees in topologischer Reihenfolge fort. Während der Analyse einer bestimmten Callee wird der Zusammenhang der Anrufkontexte aller Anrufer berücksichtigt. Um eine intraprocedurale Analyse durchzuführen (bei denen alle anfänglichen Funktionsargumente unabhängig von der ID des Threads sind), geben Sie die von der Analyse ausgeführte Pass- -uncoalesced-analysis anstelle von -interproc-uncoalesced-analysis an.
opt -load ../../../build/lib/LLVMUncoalescedAnalysis.so -instnamer -interproc-uncoalesced-analysis < gaussian-cuda-nvptx64-nvidia-cuda-sm_20.ll > /dev/null 2> gpuDranoResults.txt
HINWEIS opt liest die IR -Datei aus Standardeingaben. opt schreibt, dass die eigene uninteressante Ausgabe standardmäßig ausgeht, sodass wir es in die Ausgabe von /dev/null GPU Drano umleiten können, die in eine Datei umgeleitet werden kann.
Um ausführliche Analyseergebnisse zu generieren (LLVM IR IR, die mit Analyseinformationen kommentiert werden), führen Sie opt mit einem zusätzlichen -debug-only=uncoalesced-analysis aus.
Der folgende Befehl kann verwendet werden, um die Blockgröze-Unabhängigkeitsanalyse für ein Programm auszuführen.
opt -load ../../../build/lib/LLVMBlockSizeInvarianceAnalysis.so - -instnamer -always-inline -interproc-bsize-invariance-analysis < gaussian-cuda-nvptx64-nvidia-cuda-sm_20.ll > /dev/null 2> gpuDranoResults.txt
Die generierten Ergebnisse für unbekotete Zugriffsanalysen berichten alle Zugriffe, die möglicherweise in jedem der GPU -Kernel nicht unbedeutend sind. Hier sind beispielsweise die Ergebnisse für die Analyse von gaussian.cu .
Analysis Results:
Function: _Z4Fan1PfS_ii
Uncoalesced accesses: #2
-- gaussian.cu:295:59
-- gaussian.cu:295:61
Analysis Results:
Function: _Z4Fan2PfS_S_iii
Uncoalesced accesses: #4
-- gaussian.cu:312:38
-- gaussian.cu:312:35
-- gaussian.cu:312:35
-- gaussian.cu:317:23
Jedes Ergebniselement verweist auf einen potenziell unbekoteten Zugriff im Quellcode. Zum Beispiel ist der Zugriff auf m_cuda in Zeile 295, Spalte 59 in Gaußsian.cu bei Method Fan1() unbekannt.
In ähnlicher Weise identifizieren generierte Ergebnisse für die unabhängige Blockgröße alle Kernel, die blockgroße unabhängig sind!
Rodinia ist eine beliebte Benchmark -Suite von GPU -Programmen, die aus 22 Programmen aus verschiedenen Bereichen bestehen. Wir analysierten die Suite und fanden 111 echte ungezogene Zugriffe mithilfe einer statischen Analyse. Um die Ergebnisse zu reproduzieren, sind hier die beteiligten Schritte:
Aktualisieren Sie die CUDA- und Drano -Konfiguration in rodinia_3.1/common/make.config . Setzen Sie CUDA_DIR und SDK_DIR mit Nvidia Toolkit und SDK -Pfaden. Update opt -Alias mit Pfad zu GPU Drano Binary LLVMUncoalescedAnalysis.so .
Gehen Sie zum Benchmarks -Verzeichnis rodinia_3.1/cuda .
Kompilieren Sie Benchmarks:
sh compile.sh
sh run-analysis.sh
Die Analyse jedes Benchmarks generiert Ergebnisse in seinem jeweiligen Ordner in log-files mit dem Namen log_<filename> .
./summarize-results.sh
Nvidia bietet eine Reihe von CUDA -Proben, die für verschiedene Anwendungen verwendet werden können. Wir haben die Suite analysiert, um unabhängige Kernel von blockgroßen Kern in den Proben zu identifizieren. Um die Ergebnisse zu reproduzieren, sind die Schritte:
Aktualisieren Sie HOME Variable in NVIDIA_CUDA-8.0_Samples/common/drano.mk zum Root GPU-Drano-Verzeichnis.
Installieren Sie OpenGL (erforderlich, um einige Benchmarks zu erstellen). Auf Ubuntu kann der folgende Befehl verwendet werden:
sudo apt-get install freeglut3-dev
Gehen Sie zum Verzeichnis NVIDIA_CUDA-8.0_Samples
Kompilieren Sie Benchmarks:
sh compile.sh
sh run-analysis.sh
Die Analyse jedes Benchmarks generiert Ergebnisse in seinem jeweiligen Ordner in log-files mit dem Namen log_<filename> .
./summarize-bsize-independence.sh