Master-Seminar Computergrafik SS 2007
Transcrição
Master-Seminar Computergrafik SS 2007
Master-Seminar Computergrafik SS 2007 General Purpose Computation on Graphics Processing Unit Autor: Stefan Auer Technische Universität München General Purpose computation on Graphics Processing Unit Abstract GPGPU steht für General Purpose computation on Graphics Processing Unit. Da Grafikprozessoren (GPUs) im Laufe der Entwicklung immer weiter programmierbar gemacht wurden, kann ihre hohe Leistung heute auch zur Berechnung von mehr als nur Computergrafik genutzt werden. Diese Arbeit beschäftigt sich mit der allgemeineren Nutzung des Grafikprozessors als Coprozessor zur Bearbeitung rechenintensiver, datenparalleler Probleme. Motivation GPUs handelsüblicher Grafikkarten haben sich zu leistungsfähigen Parallelrechnern entwickelt, die mit ihrer Floatingpoint-Leistung vergleichbare CPUs bei geeigneten Anwendungen weit übertreffen. (Theoretische Leistung Nvidia G80 auf 8800GTX: 86 GB/s Speicherbandbreite, 345 Gflops Floatingpoint Leistung; Vergleich Intel Core 2 Quad Q6600: ~5 GB/s Speicherbandbreite, ~40 Gflops Floatingpoint Leistung) Aufgrund ihrer unterschiedlichen Hardware-Architektur profitieren GPUs mehr als CPUs von den Verbesserungen der Fertigungsprozesse. Eine erhöhte Transistorzahl lässt sich hier leichter in direkte Steigerung der Leistung umwandeln, so dass der Leistungszuwachs in den letzten Jahren bei den GPUs höher war. (Leistungszuwachs Nvidia 8800 GTX (2007) zu 6800 GT (2004) ca. 1350%; Intel Core 2 Quad Q6600 (2007) zu Pentium 4 600 (2004) ca. 500%) Das Hauptanwendungsgebiet leistungsstarker GPUs ist die Darstellung von Echtzeit-3D-Grafik in Computerspielen. Computer und Videospiele sind ein Endverbraucher-, Massenmarkt in dem MilliardenUmsätze gemacht werden. Da dadurch auch die notwendige Hardware ein Massenprodukt darstellt sind die Grafikkartenpreise im Vergleich zu ähnlich leistungsfähiger Spezial-Hardware verschwindend gering. Die Kombination aus enormem Leistungspotential, günstigem Preis und weiter Verbreitung hat GPUs in das Interesse von Forschern und Entwicklern gerückt, welche diese gerne allgemein zur Bearbeitung rechenintensiver Floatingpoint-Probleme zweckentfremden würden. Hardware Design aktueller GPUs Pipeline Aus der Spezialisierung auf Echtzeit-3D-Rastergrafik ergab sich für alle GPUs ein ähnliches HardwareDesign, welches sich auch in der gängigen Hardware-Abstraktion in Grafik-APIs, der Rendering Pipeline, wiederspiegelt. Gemäß diesem Konzept durchläuft alle 3D-Geometrie, welche eine Anwendung auf den Bildschirm darstellen will, dieselben Pipeline Stufen: Bildung der Input-Datenströme, Vertex-Verarbeitung (z.B. Transformation, Beleuchtung), Geometrie-Verarbeitung (z.B. Backface Culling), Rasterisierung, Fragment-Verarbeitung (z.B. Texturierung), Zusammenfassen des Fragment Outputs im Framebuffer (z.B. ZTest, Alphablending). Diese Stufen finden sich mehr oder weniger direkt auch im GPU-Hardware-Design wieder, wo es bis zur letzten DirectX9-Generation gesonderte Vertex-Prozessoren, Fragment-Prozessoren und Raster-OperationPipelines gab, durch welche die Daten sozusagen der Reihe nach geschleust wurden. Die aktuelle GPUGeneration nutzt dagegen meist eine Unified-Shader-Architektur, was bedeutet dass ein einziger Prozessortyp die Vertex-, Geometrie- und Fragment-Verarbeitung übernimmt. Die Daten werden dabei in einer Art Schleife mehrmals von den gleichen Prozessoren aber mit unterschiedlichen Programmen (Kernels) bearbeitet. Das Konzept der Unified Shader bringt für das Rendering Vorteile wie bessere Lastverteilung zwischen den unterschiedlichen Pipeline-Stufen und für die GPU-Hersteller mehr Flexibilität bei der Implementierung der Pipeline (z.B. ist dadurch für Geometrie-Shader kein zusätzlicher Prozessoren-Typ notwendig). Die Verallgemeinerung und Flexibilisierung der Shader-Prozessoren macht die Hardware aber natürlich auch für GPGPU um einiges interessanter. Vergleicht man dabei die Programmierung von GPUs mit der von CPUs muss man beachten, dass beide unterschiedliche Architekturen implementieren. CPU- vs. GPU-Architektur CPUs folgen der Von-Neumann-Architektur: Daten und Programme befinden sich im selben Speicher. Programme werden als Ströme von Instruktionen angesehen, welche jeweils wahlfreien Zugriff auf die Daten im Speicher haben. Der wahlfreie (und teilweise schlecht vorhersehbare) Speicherzugriff macht sehr aufwändiges Caching notwendig, um die Speicher- Latenz als Flaschenhals (Von-Neumann-Flaschenhals) zu minimieren. CPUs weisen daher relativ zu GPUs nur geringe ALU-Leistung (nur 6.5% der Die-Oberfläche eines Itaniums werden für Integer- und Floatingpoint-Arithmetik genutzt) und niedrige Speicherbandbreiten auf. Soweit echt parallele Verarbeitung unterstützt wird (Mehrkernprozessoren), profitieren hauptsächlich aufgabenparallele Probleme (z.B. Ausführung mehrerer völlig unterschiedlicher, unabhängiger Prozesse/Threads) davon. GPUs dagegen folgen näherungsweise der Stream-Processing-Architektur: Dabei werden die Programme als feststehende Verarbeitungsstationen (Kernel) angesehen durch welche die Daten als Ströme, der Reihe nach oder untereinander verzweigt, hindurch geschleust werden. Die Voraussetzung damit diese Architektur funktioniert, ist dass die Daten eine große Zahl gleichartiger Objekte repräsentieren, welche größtenteils unabhängig voneinander verarbeitet werden können (Datenparallelität). Der Vorteil dieser Architektur ist, dass die hohe Speicher-Latenz dabei kaum eine Rolle spielt und so mehr HardwareRessourcen für die Verarbeitung arithmetischer Operationen und Erhöhung der Speicherbandbreite zur Verfügung stehen. Nachteilig sind die Einschränkung auf datenparallele Probleme und die geringere Flexibilität der Programme (Kernel sollten „kleine“ Programme bleiben und auf bedingte Sprünge soweit wie möglich verzichten). GPGPU mit Standard APIs Computational Grids Nachfolgend wird mit „Texturen als Computational-Grids“ der naheliegendste Weg vorgestellt GPUs unter Verwendung von Standard-Grafik-APIs wie Direct3D oder OpgenGL zur allgemeinen Berechnung anstatt zum Rendering zu benutzen. Dabei repräsentieren die Texel die zu verarbeitenden Datenobjekte, Texturen die Datenströme und Fragment-Programme die Kernel welche die Daten verarbeiten. Ein „Pass“ der Berechnung erfolgt dabei durch das Zeichnen eines Fullscreen Rechtecks via render-to-texture auf eine Ausgabe-Textur. Dazu wird die Render-Target-Größe auf die Größe der Ausgabe-Textur gesetzt und der Vertex-Shader konfiguriert „nichts zu tun“ (d.h. die Vertex-Koordinaten entsprechen bereits den „Bildschirmkoordinaten“). Man lädt und bindet den jeweiligen Kernel als Fragment-Programm, eine oder mehrere Texturen als Eingabeströme und die Ausgabe-Textur als Render-Target. Zeichnet man nun ein Dreieck über den gesamten „Bildschirmbereich“, so generiert der Rasterizer für jedes Texel der Ausgabetextur ein Fragment für welches der Kernel als Fragment-Shader ausgeführt wird. Im Shader-Programm kann über Texture-Sampler wahlfrei auf die in den Input-Texturen enthaltenen Daten zugegriffen werden (Gather) und beliebiger Shader-Code genutzt werden um daraus die Ergebnisse zu erzeugen, die als Pixel bzw. Texel in der AusgabeTextur landen. GPGPU Techniken Viele einfache Mechanismen, Algorithmen und Datenstrukturen, die bei gewöhnlicher CPU Programmierung gang und gäbe sind, werden in Shader-Programmen nicht von Haus aus angeboten und müssen über Umwege realisiert werden. Zu diesen „GPGPU Tricks“ zählt auch die Nachbildung des (in Shader-Code nicht unterstützten) Scatters, also des Schreibens von Daten an wahlfreie Speicherpositionen. Dazu kann man, je nach Anforderungen, unterschiedliche Techniken einsetzen wie: 1) Ermitteln der Ergebnisse in Pass eins; Aufsammeln an den bereits vorab (statisch) bekannten Positionen in Pass zwei. 2) Speichern der Er- gebnisse und Ziel-Adressen in Pass eins; Sortieren nach Adressen in Pass zwei; Aufsammeln der Ergebnisse an den Ziel-Positionen durch Binäre Suche in Pass drei. 3) Berechnung durch Zeichnen von Punkten im Vertex-Shader durchführen (dort kann Zielposition verändert werden). 4) Speichern der Ergebnisse und der Adressen im Fragment-Shader in Pass eins ; Wert-Adress-Zuordnung im Vertex-Shader in Pass zwei. Weitere wichtige GPGPU Techniken: (aufgrund von Umfang und Komplexität nicht genauer erläutert) Zeilen- / Spaltenweises oder Blockweises Zusammenfassen von Ergebnissen (Reduce); Filterung der Ergebnisse; Sortierung über Sorting-Networks; parallele Suchalgorithmen; unterschiedlichste Formen von Datenstrukturen (z.B. dünnbesetzte Matrizen, adaptive Datenstrukturen wie shadow maps); Branching (statisch durch zeichnen nur bestimmter Bereiche; Nutzung des z-Buffers; Verwerfen von Ergebnissen durch bedingte Writes; Nutzung mathematischer Ersatzkonstrukte; Branching-Unterstützung in Shadermodel 3 und 4) Anwendungsbeispiele GPGPU unter Verwendung von Standard-Grafik-APIs wird bisher schon in unterschiedlichsten Anwendungsbereichen genutzt. So gibt es Partikel-Systeme und Fluid-Simulationen deren gewöhnlichen und partiellen differentiellen Gleichungen auf der GPU gelöst werden, Lineare Algebra Systeme die z.B. in numerischen Simulationen eingesetzt werden können oder GPU unterstützte Raytracer. GPUs werden ebenso eingesetzt um Datenbank Querys durch schnellere Joins zu beschleunigen, Simulationen auf Basis der finiten Differenzen- und finiten Elementen Methode durchzuführen oder für Bildverarbeitungsprobleme aus Bilderkennung und Computervision. Unter anderem mit realtime global illumination und Dynamik Simulationen existieren auch bereits Anwendungen die eher wieder Verwendung in den verbreiteteren GPUAnwendungen, den Computerspielen, finden dürften. GPGPU alla Nvidia Nachteile von Standard Grafik APIs OpenGL und Direct3D wurden ausschließlich zum Rendern von 3D-Rastergrafik entwickelt und weisen daher bei der Verwendung für grafikfremde Probleme eine Reihe von Nachteilen auf. Vetices, Primitive und Fragmente, auf denen die Shader-Programme der APIs arbeiten, sind reine Grafikabstraktionen, die für allgemeine Probleme unpassend sind. Nur wenige nicht-Grafik-Experten dürften gewillt sein, sich das Computergrafikfachwissen anzueignen, das notwendig ist um sinnvolle GPGPU-Programme mit Standard-3DAPIs zu erstellen. Hinderlich sind auch der umständliche Umgang mit dem Speicher (fehlender Scatter) und die Tatsache, dass viele kritische Entscheidungen von Grafik-API und Treibern getroffen werden, die sich ständig ändern und oft für die GP-Anwendung kontraproduktive Optimierungen enthalten. CUDA: Einführung Da aber glücklicherweise auch die führenden GPU-Hersteller den GPGPU Trend mitbekommen haben, entwickelten sie Software Plattformen, mit denen sich die Grafik-Chips besser für allgemeine Aufgaben verwenden lassen. Das entsprechende Produkt von Nvidia heißt CUDA, was für „Compute Unified Device Architecture“ steht. Dabei handelt es sich um eine GPGPU Plattform die sich erst mit dem aktuellen G80 und zukünftigen Grafik-Prozessoren nutzen lässt. Bei CUDA wird zur Programmierung der Grafikkarte das CSubset von C++ verwendet und herkömmliches Grafik-API und –Treiber sind nicht mehr notwendig (wenn auch weiterhin parallel via Betriebssystem-Multitasking nutzbar). CUDA: Funktionsweise Programmierer die die GPU als Coprozessor nutzen wollen, müssen entweder auf die mitgelieferten CUDA Libraries (enthalten z.B. Funktionen für FFT) zurückgreifen oder selbst Teile ihrer Programme für CUDA schreiben. CUDA-Programme, die sowohl normalen CPU / C++ Code als auch GPU / C Code enthalten, werden mit dem NVCC Compiler Driver übersetzt. Dieser trennt CPU von GPU Code, wobei ersterer mit CUDA-Aufrufcode angereichert und konventionell übersetzt oder an einen vorhanden C++-Compiler weitergeleitet wird. Der GPU-Code wird in Zwischen-Code für die PTX virtuelle Maschine übersetzt, welcher erst bei der Programminstallation vom CUDA-Treiber in Maschinencode für die installierte GPU übersetzt wird. Im CUDA-Programmiermodell wird die GPU als Coprozessor der CPU angesehen. Datenparallele Programmteile, werden in besonders gekennzeichnete Funktionen ausgelagert, welche später als Kernel auf der GPU laufen. Die Kernel-Ausführung geschieht implizit parallel in üblicherweise tausenden Threads, welche jeweils auf unterschiedlichen Daten arbeiten (vergleichbar SIMD-Konzept). CPU und GPU verfügen jeweils über ihre eigenen Speicher (Host-Speicher, Device-Speicher), zwischen denen via DMA hin- und her-kopiert werden kann. Für die GPU-Ressourcen Zuteilung (Threads, Register, Speicherbereiche) ist der Programmierer verantwortlich, welcher den zugehörigen Speicherbereich bei Variablen und die Thread-Aufteilung bei Kernel-Aufrufen bestimmt. CUDA: Threads Das Threadmanagement gliedert die CUDA-Threads hierarchisch in Grids und Blöcke. Ein Grid repräsentiert dabei alle Threads eines einzelnen Kernelaufrufs, ein Block alle Threads die zusammen von einem einzelnen Shader-Multiprozessor der GPU verarbeitet werden. Grids können bis zu 65535 hoch 2 Blöcke enthalten und werden ein- oder zweidimensional indiziert. Blöcke enthalten bis zu 512 Threads und werden ein-, zwei- oder dreidimensional indiziert. Jeder der aktuell (G80) bis zu 16 Shader-Multiprozessoren der GPU führt zu einer Zeit jeweils nur einen aktiven Block aus, kann diesen aber via Scheduling aus bis zu 8 Blöcken wählen. Mit jeder Ausführung einer Instruktion werden alle 32 Threads eines sogenannten „Warps“ gemeinsam verarbeitet. Dadurch ergeben sich je nach Komplexität der Instruktion Laufzeiten von 4 bis 32 Taktzyklen je Warp (einfache Instruktion, 8 Stream-Prozessoren je Multiprozessor => 32/8=4 Taktzyklen). CUDA: Speicherbereiche Die unterschiedlichen CUDA Speicherbereiche orientieren sich ebenfalls am Grid/Block/ThreadKonzept. Jedem einzelnen Thread sind eine gewisse Zahl sehr schneller R/W-Register (Register pro ShadingMultiprozessor / Blockgröße = Register pro Thread; G80: 8192 Register pro SM) und ein sehr langsamer, ungecachter R/W-Device-Speicherbereich (local memory) zugeordnet. Alle Threads eines Blocks teilen sich den schnellen R/W-Shared-Memory (G80: 16kB) ihres Multiprozessors, auf welchen sie mittels Ausführungsbarrieren (alle Threads müssen Code-Stelle erreichen, bevor weitergemacht wird) und atomaren Operationen (Read-Modify-Write; erst in neuersten Hardware-Versionen verfügbar) auch mehr oder weniger synchronisiert zugreifen können. Alle Threads eines Grids teilen sich den sehr langsamen, ungecachten R/W-Global-Device-Memory (keine Synchronisation möglich, vergleichbar Framebuffer), den schnellen gecachten Readonly-Constants-Device-Memory (vergleichbar Shader-Konstanten; G80: 64kB) und den mittelmäßig schnellen Readonly-Texture-Device-Memory (Device-Memory insgesamt G80: bis zu 768 MB). Der Host kann vor und nach einem Kernel-Aufruf lesend und schreibend auf Constants-, Texture- und GlobalMemory zugreifen. CUDA: Spracherweiterungen Die C/C++ Programmiersprache wurde für CUDA mit ein paar Erweiterungen ausgestattet: Der „Ausführungsort“ einer Funktion wird mittels der Schlüsselwörter __host__ (Aufruf und Ausführung auf der CPU; kann auch weggelassen werden), __global__ (Aufruf auf der CPU, Ausführung auf der GPU; entspricht Kernel) und __device__ (Aufruf und Ausführung auf der GPU; implizites Inlining) angegeben. (host und device auch kombinierbar => doppelte Kompilierung) Der Speicherort einer Variablen wird durch Angabe von __device__ , __constant__ und __shared__ bestimmt. Mithilfe der sogenannten Kernel Ausführungskonfiguration Funktionsname<<<Gridsize, Blocksize>>>(...) wird beim Aufruf einer Global-Funktion bestimmt, auf wie vielen Blöcken je Grid und wie vielen Threads je Block der Kernel ausgeführt wird. Die integrierten Variablen gridDim, blockIdx, blockDim, threadIdx geben innerhalb einer Kernelfunktion an, mit welcher Ausführungskonfiguration diese gestartet wurde und um welchen Thread bzw. Block es sich aktuell handelt. Mithilfe der Speicherverwaltungsfunktionen cudaMalloc(…), cudaFree(...), cudaMemcpy(...), cudaMemcpy2D(...) kann Speicher auf dem Device allokiert und freigegeben, sowie zum und vom Host kopiert werden. CUDA: Bewertung und Zukunft CUDA ist eine Programmier-Plattform, die von vornherein auf die Nutzung der GPU als Coprozessor zur Berechnung allgemeiner datenparalleler Probleme ausgelegt ist. Als solche ist sie für nicht-Grafik-nahe GPGPU-Anwendungen sicherlich besser geeignet als ein Grafik-API und hat aufgrund der leichteren Zugänglichkeit auch das Zeug dazu möglicherweise eine kritische Masse von nicht-Grafik-Programmierern für GPGPU zu interessieren. Handelt es sich bei einer Anwendung allerdings beispielsweise um eine Visualisierung, so haben die Grafik-APIs den Vorteil, dass die Daten gleich dort berechnet werden, wo sie auch angezeigt werden können. Zudem sind Direct3D und OpenGL im Gegensatz zu CUDA ausgereifte und gut dokumentierte Systeme, welche von vielen Entwicklern bereits beherrscht werden. Ein weiterer Vorteil der Grafik-APIs ist, dass sie nicht nur mit Nvidia Produkten, sondern mit allen verfügbaren Grafik-Chips funktionieren, was beispielsweise bei Spielen das ausschlaggebende Kriterium sein könnte. Um kommerziell einen Gewinn aus den eigenen GPGPU-Bemühungen zu ziehen, bietet Nvidia mittlerweile unter dem Label „Tesla“ spezialisierte GPGPU-Hardware an. Dabei handelt es sich bisher im Grunde um normale GPUs, verbaut in unterschiedlichen Geräten (Einschubkarte, Workstation, Server-Rack) mit besserem Speicherausbau. Für die Zukunft plant man jedoch neue, ausschließlich GPGPU relevante Features wie double-precition-floatingpoint-Unterstützung nur bei den Tesla-Produkten freizuschalten. Der Erfolg der Tesla-Produkte könnte für die Weiterentwicklung von CUDA maßgeblich sein, was man sowohl positiv, als auch negativ bewerten könnte. GPGPU alla AMD/ATI Auch bei AMD/ATI hat man sich Gedanken über die mögliche Zukunft von GPGPU gemacht. Im Zuge der Übernahme des GPU-Spezialisten ATI durch AMD präsentierte man den Aktionären und der Öffentlichkeit unter dem Codenamen „Fusion“ erste Pläne CPU- und GPU-Kerne gemeinsam auf einem Prozessor-Die unterbringen. Soll es sich bei den ersten, für 2009 erwarteten, Produkten noch hauptsächlich um stromsparende Billigprozessoren für Notebooks handeln, so möchte man bis ca. 2015 zusätzlich Nutzen für die Rechenleistung aus der CPU-GPU-Verschmelzung ziehen. Dabei ist es angedacht, die GPU-Kerne neben der Grafikdarstellung auch als Streaming-Coprozessor für datenparallele Berechnungen zu nutzen. Während Fusion noch reine Zukunftsmusik ist (die möglicherweise hauptsächlich gebracht wurde, um die Übernahme vor den Aktionären zu begründen), ist ein anderes Produkt von ATIs GPGPU-Bemühungen schon seit längerem verfügbar: Hinter „Close to metal“ (CTM) verbirgt sich die Implementierung von ATIs „Data parallel virtual machine“ (DPVM) Konzept für die Radeon R580er Serie (verbaut in Radeon X19x0 Serie und AMD StreamProcessors ehemals ATI FireStream). Die DPVM stellt eine Software-Plattform für GPGPU-Programme dar, welche die GPU, unter Umgehung von Grafik API und Treiber, direkt als Prozessor nutzen. Die virtuelle Maschine abstrahiert die GPU auf einfache Art und Weise als einen „Command Prozessor“, der die in Command-Buffern bereitgestellten Tasks auf die Streaming Prozessoren des „Data parallel processor arrays“ verteilt und einen „Memory controler“ der sämtliche Speicherzugriffe und –transfers regelt. CTM, die Implementierung der DPVM, besteht aus einer Spezifikation der Architektur (ISA, Ressourcen, etc.), der Runtime (implementiert als low-level Treiberkomponenten) und den Support Librarys welche die Generierung von Command-Buffern aus GPU-Assembler-Code sowie die Speicherallokation ermöglichen. High Level Programmiersprachen oder sonstige Entwicklungstools werden von ATI bisher nicht angeboten, sondern diese sollen nach Möglichkeit von Dritten (wie z.B. den Entwicklern von BrookGPU?) realisiert werden. Dementsprechend werden die Vorteile, wie der direkte Zugang zur Hardware unter Ausblendung grafikspezifischer Features, wohl nur von Forschern und Entwicklern genutzt werden die gewillt sind, sich ernsthaft mit einem neuen GPU-Assembler und den Details der R580 Plattform zu beschäftigen (für den R600 ist bisher nichts Vergleichbares verfügbar). Quellen www.GPGPU.org CSE Stony Brook GPGPU Kurs http://www.cs.sunysb.edu/~mueller/teaching/cse690/syllabus.html ECE Illinois CUDA Kurs http://courses.ece.uiuc.edu/ece498/al/Syllabus.html IEEE Visualization 2005 Tutorial http://www.gpgpu.org/vis2005 SIGGRAPH 2005 GPGPU Kurs http://www.gpgpu.org/s2005 A Survey of General Purpose Computationon Graphics Hardware http://www.cs.virginia.edu/papers/ASurveyofGeneralPurposeComputationonGraphicsHardware.pdf A GPU Framework for Interactive Simulation and Rendering of Fluid Effects http://mediatum2.ub.tum.de/doc/604112/document.pdf John Owens - What’s New with GPGPU? http://www.ece.ucdavis.edu/~jowens/talks/berkeley-glunch-060831.pdf John Owens - GPU Computing http://www.cgo.org/cgo2007/presentations/cgo2007-keynote-buck.pdf A performance oriented data parallel virtual machine for GPUs http://ati.amd.com/developer/siggraph06/dpvm_sketch_siggraph.pdf Brent Oster - CUDA http://www.cs.ucsb.edu/~gilbert/cs240aSpr2007/lectures/G80%20CUDA.ppt Hochschule Bremen GPGPU Semesterarbeit http://www.weblearn.hs-bremen.de/risse/RST/WS06/GPGPU/GPGPU.pdf University of Virginia Realtime-Rendering Kurs http://www.cs.virginia.edu/~gfx/Courses/2006/RealTime/lecture21.GPGPU.ppt Nvidia CUDA Programming Guide http://developer.download.nvidia.com/compute/cuda/1_0/NVIDIA_CUDA_Programming_Guide_1.0. pdf Mike Houston - GPGPU http://graphics.stanford.edu/~mhouston/public_talks/R520-mhouston.pdf GPU Gems 1 und 2 Wikipedia http://en.wikipedia.org/wiki/Gpgpu