Wie man Ati Stream Programmiert

Mizukag3

Lt. Junior Grade
Registriert
Feb. 2007
Beiträge
336
Hallo CB'ler!

Ich wollte mal meine 2 Grakas (siehe Signatur)programmieren bin jetz aber nochnich durchgestiegen wie man das machen kann.

Hat da jemand erfahrung bzw. weiß jemand wie man das wo schreibt,compiliert usw?

Oder hat jemand Tipps oder sogar ne gute verstehbare Anleitung?
 
Haste mal gelesen was Stream ist? Und macht? Oder haste nur ne Überschrift gelesen und hast jetzt Erwartungen?
 
Wer programmieren kann, der dürfte genug Ahnung haben sich die benötigten Informationen zu beschaffen. GPU-Programmierung ist bestimmt nicht für den Einstieg in die Prgorammierwelt gedacht...

Wieviel Ahnung von Programmierung hast du denn? Was willst du denn konkret machen?
 
Ich kann programmieren java,c++,delphi,vhdl,turbo pascal (haha)... noch nicht so richtig Professionell aber kommt noch bin info student.

jo thx für die Links die zu finden is jetz auch für mich nich das Problem....

ich wollte halt nur wissen ob jemand Erfahrung hat z.B. Erfahrungsberichte sowas in der Richtung :)


ich wollte einfach mal kleine Programme schreiben die was rechnen um zu sehen was die Grakas so an leistung hergeben.


einfach mal schauen was da so möglich ist z.B. zahlen generieren, bisschen was rumrechnen ... ich bin halt am probieren ob man auch damit auch nutzen in größeren Programmen hat Aufwand/zusätzliche Leistung.
 
Zuletzt bearbeitet:
Also ich kann AMD Stream, was willste wissen? Alles?
Wenn man es geblickt hat, dann ist es ganz easy und einfach zu verstehen, aber bis dahin kann es lange dauern. Meiner Meinung ist es sogar einfacher als CUDA von nVidia, aber da hab ich mir nur den Guide durchgelesen, da ich nur eine ATI hab.
 
Blitzmerker schrieb:
Also ich kann AMD Stream, was willste wissen? Alles?
Wenn man es geblickt hat, dann ist es ganz easy und einfach zu verstehen, aber bis dahin kann es lange dauern. Meiner Meinung ist es sogar einfacher als CUDA von nVidia, aber da hab ich mir nur den Guide durchgelesen, da ich nur eine ATI hab.


ja gerne Alles!! :D

Also Programmiert man in Brook+ oder kann man da auch C++ code laufen lassen irgendwie? und wie starte ich das dann?
 
Also man programmiert am schnellsten in Brook+, die hartgesottenen Optimierer können auch IL nehmen.
Das Prinzip ist ganz einfach.
Es gibt 2 Dateien, in einer Datei ist der Kernel Code, dieser wird auf der GPU ausgeführt.
In der 2. Datei ist dein Programm, was auf der CPU läuft.
Die erste Datei wird von Brook geparsed, um dann gültigen C++ Code zu erzeugen. Das heißt, Brook+ ist eigentlich nur zur Compilerzeit wichtig, danach wird alles über die CAL Schnittstelle abgewickelt.

Aber jetzt beginn ich erst mal Schritt für Schritt:
1. SDK donwloaden und alles installieren.
2. (optional) Syntax Highlighting in Visual C++ installieren (siehe Brook+ installing guide Kapitel 5)
3. Benutzerdefinierte Buildregel erstellen:
Visual C++ starten und irgendein Projekt öffnen, dann links im Prjektmappenexplorer auf das Projekt Rechtsklicken und dann auf Benutzerdefinierte Buildregeln... dann Neue Regeldatei da dann Name Dateinam und Verzeichnis auswählen (praktisch egal) und dann Buildregel hinzufügen...
Das ist jetzt der Brook+ Parser:
Einstellungen:
Anzeigennamen egal
Ausführungsbeschreibung egal
Ausgaben $(InputName).cpp
Befehlszeile "<Brook+Pfad>\sdk\bin\brcc_d.exe" -o $(InputName) $(InputName).br
Dateierweiterung *.br
Name irgendwas
Rest so wie er ist
Dann Die Regel und die Datei speichern und den Haken dranmachen, nun ist ein Brok-Compiler, oder wie du es genannt hast verfügbar.

4.) Dieser Schritt muss für jedes Projekt gemacht werden.
Unter Projekt -> Eingenschaften -> Konfigurationseigenschaften -> Linker -> Zusätzliche Abhängigkeiten muss die amdcalcl.lib und amdrt.lib aus <cal-verzeichnis>\lib\xp32\ drinstehen, sonst bekommt man unaufgelöste symbole.

Jetzt zum richtigen Programmieren.
Ich mach jetzt ein Beispielprogramm, was dann analog für (praktisch) alle Programme gilt.

gpu.br
Code:
kernel void add(float a<>,float b<>, out float c<>)
{
    c=a+b;
}

test.cpp
Code:
#include <iostream>
#include <gpu.h>//Diese Datei wird von Brook+ erstellt und enthält all die kernel
using namespace std;
 
int main()
{
unsingned int Dim1[]={1};//Damit kann man die Größen der Dimensionen festlegen also 1 Dimensional mit Größe 1
brook::stream<float>sa(1,Dim1);//dadurch mach ich ein Stream auf der Grafikkarte
brook::stream<float>sb(1,Dim1);
brook::stream<float>sc(1,Dim1);
float aa[1],ab[1],ac[1];/das sind die Arrays, die die Grafikkartendaten entsprechen wrden/sollen
aa[0]=123;
ab[0]=456;
sa.read(aa);//Dadurch werden mit DMA die Dateien auf die Grafikkarte kopiert
sb.read(ab);
add(sa,sb,sc);//Das führt den Kernel aus wie eine einfache Funktion
sc.write(ac);
cout<<ac[0];
system("PAUSE");
return 0;
}

Das wahrs schon, addiert 123 und 456 auf der Grafikkarte uns gibt es über die CPU aus.

Edit: Möglicherweise muss man noch die GPU.cpp zum Projekt hinzufügen (wird bei jedem kompilieren erstellt)
 
Zuletzt bearbeitet:
aaaaaahhhhh..... danke das bringt mich ein ganzes stück weiter!!

werds gleichma ausprobiern

zum Verständniss: man sagt der CPU was die GPU machen soll diese bereitet die Daten dann vor um dann bei der GPU irgendwas zu rechnen und die Ergebnisse stehen dann von der CPU gespeichert im Ram. is das so richtig?

großes Danke nochmal!
 
Also, die Streams sind auf der GPU gespeichert, werden aber von der CPU über dieses Template verwaltet. Die Kernels werden im Vorraus berechnet und dieser Code wird dann als Shader ausgeführt. Der Shader sieht nur die Daten auf der GPU und auch nur die, die beim Aufruf mitgegeben wurden (bis zu 128 in und bis zu 8 out).
Der CPU waret so lange, bis der Kernel fertig ist, dann kann er die Daten lesen schreiben, weitere Kernels ausführen ...
Man hat auf die Streams kein direkten Zugriff, also
brook::stream<float>mystream(x,Dimx);
mystream[myposition]=123;
geht nicht, man kann nur den ganzen Stream auslesen und dan wieder reinkopieren.

Wichtig: Die Streamoperatoren prüfen nicht auf Größe und Zugriff des Arrays, das übergeben wird. Die Operatoren laden einfach so viel, wie die Größe des Streams ist. Dass es keine Probleme gibt, dafür hat der Programmierer zu sorgen.

Was noch so alles geht und was nicht erlaubt ist, dazu solltest du einfach mal das Programming Guide lesen (oder nur überfliegen, da bleibt auch schon was hängen). Es gibt nähmlich noch Speizalkerneltypen und die eingebauten Funktionen und Typen, vor allem bei der Vektorberechnung geht es mit Brook+ (meiner Meinung nach) einfacher als mit der CPU.

Zusammengefasst:
Du hast es fast ganz verstanden, das Ergebnis liegt aber im VRAM, die GPU kann nicht auf die CPU oder auf den RAM zugreifen (theoretisch schon, aber schwer realisierbar).

Der Ablauf ist immer der gleiche:

Daten in den VRAM laden stream.read();
Kernel ausführen kernel(stream,...)
Daten aus dem VRAM auslesen stream.write();


Anmerkung:
Die brook::stream<t> Klasse gibt den reservierten Speicher auf der GPU automatisch wieder frei, wenn die Klasse zerstört wird.
 
ah danke !

werd mir irgendwann mal die Guide reinziehen! (nich gerade Samstag abend)

danke für deine Zeit jetz hab ich den richtigen Ansatz! :)
 
super! danke werds mir merken :)
 
Muss es in dem Quellcode statt add(a,b,c) nicht add(aa,ab,ac) heißen? Was beduetet die Zeile cout<<ac[0];?
 
ja, hast recht, ich korrigiers.
Allerdings heißt es add(sa,sb,sc); da wir ja die Daten auf der Grafikkarte addieren und mit Daten im RAM kann die Grafikkarte nicht arg viel anfangen.

cout<<a[0] heißt gebe Arrayfeld 0 aus (darin ist das Ergebnis der Rechnung), das ist C++.
 
Zuletzt bearbeitet:
Hm, C++ unterscheidet sich doch stärker von Java als ich angenommen habe.

Welche Operationen unterstützen stream-fähige GPUs in Hardware? Auch Winkelfunktionen?
Ist es möglich ein Array der Länge n in den VRAM zu schieben und dort mit nur einem Methodenaufruf eine bestimmte Operation auf alle Daten im Array gleichzeitig anzuwenden? Also quasi wie auf einem Vektorprozessor? Falls ja, wie lang darf das Array höchstens dafür sein?


Darii schrieb:
Ab Sommer wir Stream auch OpenCL unterstützen.
Dann müsste es theoretisch auch auf zukünftigen Nvidia-Karten laufen, oder?
 
Ja das geht, einfach wie im Beispielprogramm die Streams machen, bloß halt mit
unsigned int Dim[]={Elems};
und dann wird diese Operation ausgeführt:
Code:
for(int i=0;i<Elems;i++)
sc[i]=sa[i]+sb[i];
Die Maximale Größe ist (fast) immer 8196 B ohne Addressvirtualisierung und 8196*8196 B mit Addressvirtualisierung oder maximal 2^26 Elemente.
Dabei kann manden Kernelnatürlich durch alles mögliche ersetzten.
Mögliche Spezialfunktionen sind:
Code:
sin 
cos 
tan 
asin 
acos 
atan
sqrt
abs
clamp
cross
dot
exp
floor
fmod
frac
isfinite
isinf
isnan
lerp
log
max
min
normalize
pow
rsqrt
round
sign


Unterstützte Variabeltypen sind:
(unsigned) {int|float|double|char|short}{1|2|3|4}
wobe double maximal 2 Elemente haben kann.

Wer mehr wissen will, sollte mal das Brook+ Programming Guide lesen (Anhang A)
 
Zuletzt bearbeitet:
Blitzmerker schrieb:
Ja das geht, einfach wie im Beispielprogramm die Streams machen, bloß halt mit
unsigned int Dim[]={Elems};
und dann wird diese Operation ausgeführt:
Code:
for(int i=0;i<Elems;i++)
sc[i]=sa[i]+sb[i];

Also die Schleife kommt in die Methode add im Kernel? Das ist ja aber keine parallele Verarbeitung dann. Da wird eine Operation, in diesem Fall Addition, Elems-mal hintereinander ausgeführt.
Oder kümmert sich um die Parallelisierung der Compiler? Ansonsten würden die 160 ALUs der HD4870 nichts bringen.

Ich blätter mal in der Guide rum, vielleicht wird es dort schon erklärt.

Nachtrag: Im Guide steht was von "Short Vectors". Das sind (primitive) Datentypen, z.B.:
float3 vec;
vec besteht nun eigentlich aus drei float-Feldern.
Die Zeile
vec == vec*2;
führt aber dazu, dass jedes Feld mit 2 multipliziert wird.
Das habe ich mit paralleler Verarbeitung gemeint. Die "Short Vecotrs" sind aber auf eine max. Größe von vier Feldern beschränkt. Das haut ja noch keinen um. ;) Ich frage mich, ob man jedem einzelnen Kern der GPU jeweils ein Feld eines laaaangen Vektors übergeben kann und mit bloß einem Kommando auf jedes dieser Felder gleichzeitig dieselbe Operation (z.b. add oder wass die ALUs so noch alles können) loslassen kann.
 
Zuletzt bearbeitet:
Zurück
Oben