thysol
BIOS-Overclocker(in)
mach das
solange das Karnickel nicht geschlachtet wird![]()
Die Testversion schicke ich dir dann wahrscheinlich am WE.
![Zwinker ;) ;)](/styles/ctec/images/smilies/zwinker4.gif)
mach das
solange das Karnickel nicht geschlachtet wird![]()
Geforces sind bei so kurzen Berechnungen deutlich schneller als Radeons. Ich gehe davon aus das die Geforces schneller auf 3D Takt umschalten und deswegen schneller sind bei diesem Benchmark.![]()
Begenzt, C#.net ist eine schlechte basis für so einen vergleich (langsam durch cli)...Mein Code ist sowohl fuer CPU und auch GPU sehr parallelisiert. Da die GPU eine sehr parallele Architektur hat ist sie meist schneller als die CPU.
Naja, SSE kann max 4 Floats gleichzeitig verarbeiten, ne Geforce macht 32 Threads/Zyklus ("Warp")wenn du nativen maschinen code benutzt, und den ein ganz bisschen optimierst (sse) ist bei so einer kurzen berechnung der vorsprung der gpu dahin.
Ich würde mich auch bereit erklären die Multi - GPU - Version zu testen.
Als GPUs würde ich HD4870 verwenden.
Nope, Radeons brauchen nur ein paar optimierungen im code, um die register der vliw zu füllen (der armselige opencl compiler von amd schafft das net, wenn du den code nicht dafür vorbereitest). dann kannst du die brachiale rechenleistung der radeons nutzen...
und die 2.7 tflops der radeon 5870 sind dann einsame spitze...
Begenzt, C#.net ist eine schlechte basis für so einen vergleich (langsam durch cli)...
wenn du nativen maschinen code benutzt, und den ein ganz bisschen optimierst (sse) ist bei so einer kurzen berechnung der vorsprung der gpu dahin.
Naja, SSE kann max 4 Floats gleichzeitig verarbeiten, ne Geforce macht 32 Threads/Zyklus ("Warp")
Und dann muss man sich im Falle von SSE noch mit so Sachen wie Memory ALignment rumquälen![]()
Register erhöhen, sodass du mehr operationen pro "thread" hast, am besten auch nach ausführort sortiert (z.b. erst alle operationen für die alu, dann alle für die fpu).Wie sehen denn solche Optimierungen aus?![]()
Zunächst einmal: C#.net (CLR) ist wie java nicht in maschinencode compilert, sondern wird nur in einen "zwischencode" übersetzt. die entgültige compilierung in maschinencode erfolgt zur laufzeit (just in time). Das kostet ausführzeit.Wie genau koennte ich denn so einen Maschinen Code schreiben?![]()
Register erhöhen, sodass du mehr operationen pro "thread" hast, am besten auch nach ausführort sortiert (z.b. erst alle operationen für die alu, dann alle für die fpu).
Abhängige Operationen sollten dabei vermieden werden (das packen die compiler einfach nicht).
lokale arbeitsbreite optimieren, so das immer für die vorhandene gpu die ideale arbeitsbreite gewählt wird. keine leerlaufenden threads.
anzahl der threads pro recheneinheit verringern, mehr operationen in einem thread.
das ist allerdings nicht immer einfach, da wenn du zu viele operationen pro thread hast (im verhältnis zur threadanzahl), das alles wieder langsamer wird.
für das alles ist abermeist eine erhebliche unstrukturierung des codes nötig.
aber selbst ein tesla c2060 kann dadurch fast doppelt so schnell werden.
und der leistungszuwachs bei radeons ist gigantisch.
(gilt übrigens auch für vertex und pixelshader, nicht nur für gpgpu)
was du machen kannst:
schleifen ausrollen (faktor 8 sollte gut sein), abhänigkeiten auflösen und gleiche operationen zusammenschieben (nochbesser: verwende vektortypen).
achtung beim schleifenausrollen: #pragma unroll N sortiert nicht nach operationen, aber grade das führt zu einem enormen leistungszuwachs.
sry, weiß grad nicht, wie ichs verständlicher erklären soll... ich mach mal ein beispiel:
aus:
int *a; float *b;
for(int i = 0; i < n; i++)
{
a *= 2; //alu
b *= 2; //fpu
}
wird z.B. (4 fach ausgerollt)
int *a, i;
float *b;
for (i = 0; i < n-4; i+=4)
{
a *=2; //alu
a[i+1] *= 2;
a[i+2] *= 2;
a[i+3] *= 2;
b *=2; //fpu
b[i+1] *= 2;
b[i+2] *= 2;
b[i+3] *= 2;
}
for(int j = i * 4; j < n; j++ )
{
a *= 2; //alu
b *= 2; //fpu
}
Wenn der Code unabhänig ist (a ist unabhänig von b) ist das sehr einfach. ich kenne deinen code nicht, aber sobald die berechnungen abhängig voneinander sind, was sehr häufig der fall ist, kann das sehr kompliziert werden, den code für die alu und die fpu zu trennen.
noch besser wäre vektorisierter code (ählich wie sse), da du damit dem compiler gleiche operationen aufzwingst:
int4 *a, i;
float4 *b;
for (i = 0; i < n / 4; i++)
{
a * = 2; // alu
b *=2; //fpu
}
for(int j = i * 4; j < n; j++ )
{
a *= 2; //alu
b *= 2; //fpu
}
(das jetzt idealerweise nochmal ausrollen)
wenn du die daten gleich als vector an die gpu überträgst, erhöhst du auch die bandbreite
operationen in einem thread pro einheit erhöhen, würde ich dir nicht empfehlen, das kann die ausführzeit zwar massiv verbessern, aber dafür musst du sehr genau über die hardware bescheid wissen. stark vereinfacht: 10 operationen auf 10000 threads ist schlechter als 100 operationen auf 1000 threads, solange du weniger als 1000 recheneinheiten hast. ganz so pauschal erreicht man leider nur wenig geschwindigkeitszuwachs.
welche optimierung am meinsten bringt, bzw. welche enventuell sogar nachteile bringt, hängt stark vom eingesetzten code ab.
auch verringern der anzahl an variablen bringt geschwindigkeitsvorteile,
local arrays statt private variablen kann vorteile birngen, muss aber nicht...
Zunächst einmal: C#.net (CLR) ist wie java nicht in maschinencode compilert, sondern wird nur in einen "zwischencode" übersetzt. die entgültige compilierung in maschinencode erfolgt zur laufzeit (just in time). Das kostet ausführzeit.
Maschinencode bekommst du, indem du z.B c/c++ oder fortran verwendest (mit visual studio geht das aber nur wenn du dann consolenprogramme erzeugst, denn visual c++ ist auch CLI (qt als gui wäre eine maschinencode alternative).
SSE ist vektorisierter Code, du kannst damit statt einem 32 bit datentypen, einen 128 bit dateintypen (oder 4 32bit datentypen) in einem taktzyklus ausführen. normal führst du eine operation auf eine variable pro takt aus. mit sse können bis zu 4 sein.
sse bekommst du in erster linie durch inline assambler bzw. durch die c++ headerfile xmmintrin.h (muss auch z.T. mit einem compilerflag aktiviert werden (gnu: -msse, -msse2 usw.)).
es gibt auch compiler, die automatisch sse code erzeugen können, meist aber nur für schleifen, was nur ein kleiner teil der möglichkeiten von sse ist.
das effizienteste ist, wenn man die performance kritischen stellen in assembler schreibst... nur das will man nicht
Wenn du maximale effizenz willst, musst du dich aber auch mit der x86 architektur auskennen, da das alles sehr hardware nah ist.
wenn du das in c# schneller machen willst: nutze die bitoperatoren (gilt auch für den opencl c code)...
Du kannst trotzdem so weit wie möglich ausrollen (um faktor > 5).Die Daten sind aber leider in dieser Berechnung abhaengig voneinander.
Also im khrono-opencl-c binding musst du immer eine lokale arbeitsbreite angeben. im schlechtestenfall 1.Waehlt der Compiler ansonsten automatisch die lokale arbeitsbreite?
auf der gpu kannst du einen "thread" nicht direkt mit einem programmthread auf der cpu vergleichen. aber auch auf der cpu ist ein "opencl-thread" nicht gleich einem programmthreadMacht der Compiler aus einem Kernel ein Thread pro Array Index? Oder pro jeder Operation in dem Kernel?
hier hast du mich falsch verstanden. der code würde auf gpus unter 1000 recheneinheiten gut laufen, und auf gpus mit mehr als 1000 recheneinheiten werden dann einige recheneinheiten nicht genutzt. das kannst du aber durch abfrage der recheneinheiten und entsprechende threadanzahl verhindern (ideal: anzahl recheneinheiten = anzahl threads --> ideale ausnutzung der recheneinheiten und kein leistungsverlust durch threadverwaltung).Ich haette es lieber wenn der Code auf jeder GPU gut laeuft und nicht nur mit GPUs ueber 1000 Recheneinheiten.
Vektoren benutze ich bereits.![]()
muss jetzt nochmal nachfragen, weil sich das oben nicht so angehört hat, als du gesagt hast, deine daten wären abhängig. wahrscheinlich ich mich auch zu ungenau ausgenau ausgedrückt, sry. ich meine nicht die "c# vectoren" sondern ich meine die aus opencl. die haben nichts miteinander zu tun.Ja, ich bewege bereits die Daten als Vektoren zur GPU.
Das ist egal. Dann war nur das beispiel oben nicht ideal. Du musst nur versuchen, Operationen, die auf die gleich variable angewendet werden, zusammenzubringen. das tritt immer beim ausrollen von schleifen aus. Wenn du #pragma unroll verwendest, macht der compiler das grundsätzlich falsch (weil es häufig sehr schwierig ist, maschinell fast immer unmöglich, manchmal auch komplett unmöglich).Leider benutze ich fast ausschliesslich floats. Ausserdem sind die einzelnen Daten voneinander abhaengig in meinem code.
gut, wenn du kein c kannst, ist es wohl nicht sinnvoll mit sse anzufangen.Dass ist mit leider etwas zu aufwendig da ich leider nur C# halbwegs gut kann.![]()