CUDA, der neue heilige Gral der Programmierung "?"



  • ja, mit der c64 floppy wurden schon lustige sachen gemacht. es gab sogar ein buch von 'nem kerl, der das betriebssystem der 1541 reverse engineered hat.
    🙂



  • Hihi, vorallem konnte man ja an den C64 bis zu 4 Floppies in Reihe anschließen. Wer sich das leisten konnte, hätte da sicherlich was reißen können! 😉



  • ^^ja klar, 'massive parallel computing' mit 4 * 1Mhz, kommunikation über 'nen seriellen bus, schlichtweg der hammer. heutige quad-cores sind doch ein dreck dagegen.
    🙂



  • es haengt vom anwendungsgebiet ab, davon wie gut du low level optimieren kannst und wie gut du dich mit der hardware auskennst.
    wenn alles top ist, kannst du ca 50mal schneller sein als mit der cpu.
    wenn eine der sachen schief geht, kannst du auch 50mal langsammer sein.



  • Naja die C64 Geschichte ist ja eher genau das Gegenteil: die Verwendung einer General-Purpose CPU in einem Peripheriegerät.

    Die Verwendung dieser CPU im Floppy-Laufwerk für normale "CPU Dinge" biegt das bloss wieder gerade 🙂



  • hustbaer schrieb:

    Die Verwendung dieser CPU im Floppy-Laufwerk für normale "CPU Dinge" biegt das bloss wieder gerade

    was sind für dich 'normale cpu dinge', oder wieso glaubst du, dass in der 1541 die cpu zweckentfremdet wurde?



  • der erwähnte prozessor im 64-er und dessen floppy war ja eigentlich nur der kern der tastaturen von ibm-pcs.



  • Die 1541 als solches ist aber keine General-Purpose-Hardware. Genauso wie Grafikkarten es nicht sind. Das ist es doch eigentlich, worum es geht, oder? Denn wer sagt dir nicht, das auch eine GPU eine CPU ist? Ist doch nur Interpretation.
    Ich würde das ganze mit der 1541 nicht runter spielen. Würde eher sagen, sowohl das eine CPU (oder besser gesagt Computer!) in einer Floppy drin steckt, UND das ich die Floppy zum Rechnen nutzen kann, sind zwei abgefahrene Dinge. Wobei der Rechner in einer Floppy witzigerweise auch nur aus der Not heraus geboren wurde (C64 zu wenig Rechenpower und wäre bei Diskzugriffen blockiert gewesen... ).



  • Zoom schrieb:

    hustbaer schrieb:

    Die Verwendung dieser CPU im Floppy-Laufwerk für normale "CPU Dinge" biegt das bloss wieder gerade

    was sind für dich 'normale cpu dinge', oder wieso glaubst du, dass in der 1541 die cpu zweckentfremdet wurde?

    Der zweite Satz war nicht umsonst mit einemn 🙂 versehen.
    Mir ist schon klar dass es äusserst üblich war bzw. auch noch ist, GP-CPUs in Peripheriegeräte einzubauen.

    Bulli schrieb:

    Denn wer sagt dir nicht, das auch eine GPU eine CPU ist? Ist doch nur Interpretation.

    Eine GPU ist keine GP-CPU. Und klar ist das Definitionssache. Das ganze Leben ist Definitionssache. Glücklicherweise verstehen wir Menschen uns meistens trotzdem. Was aber nicht heisst dass man jemanden nicht falsch verstehen kann, wenn man es unbedingt will. 🙄

    Mal ne Frage: würde es diesen Thread geben, wenn auf Grafikkarten CPUs wie ein Core 2 oder ein Athlon sitzen würden? Nein? WIESO BLOSS NICHT?



  • http://www.nvidia.de/object/tesla_s1070_de.html

    die idee an sich wird wohl nicht ganz neu sein, aber der unterschied ist doch der, dass intel bisher immer mehr in den bereich multi-prozessoring geht und im moment NUR NOCH dabei ist mehr kerne aufzulöten.
    Aber grade dieser Bereich ist bisher von den Grafikkartenherstellern vollkommen dominiert und ich denke mal, dass die Know-How Technisch viel weiter sind und immer sein werden. Im Prinzip könnte man die CPUS bald als obsolet betrachten, weil die Leistungsunterschiede immer geringer werden.

    Außerdem kommt hinzu, dass die wenigsten sachen, die sich nicht parallelisieren lassen so rechenintensiv sind, dass man zwangsweise nen 4ghz intel cpu bräuchte. bisher geht alles in richtung paralellisierung. spiele, filme und für uns das kompillieren werden immer wichtiger,allerdings sind dass auch alles beispiele die enorm davon profitieren würden, spätestens wenn man mal den kernel in mehreren threads übersetzt, merkt man das^^

    ich frage mich in letzter zeit wirklich, obs überhaupt noch was bringt ne cpu jenseits der core2duos zu holen.... ich denke eher nicht, vorallem wenn zukünftige anwendungen statt threads cuda oä benutzen.



  • @gentoo:
    gut parallelisierbar != gut vektorisierbar
    und
    gut parallelisierbar != gut für einen stream-prozessor geeignet

    Gerade eine Aufgabe wie C oder C++ Compilieren ist für einen Stream-Prozessor denkbar ungeeignet.

    vorallem wenn zukünftige anwendungen statt threads cuda oä benutzen.

    Er. Das wird nicht passieren. Zumindest für den Grossteil der "zukünftigen Anwendungen" nicht.



  • hmm, ich kenn mich mit den hardware-seitigen details zu wenig aus, um da jetzt groß mitreden zu können. ich war bisher nur ziemlich angetan, mit welcher geschwindigkeit ich bilder bearbeiten konnte, und das mit ner billigen grafikkarte (gibts ja mitlerweile für 50€) 😮

    @hustbaer
    sind das im wesentlichen nicht alles fließkommaberechnungen, die so ein prozessor macht? hardware-mäßig ist die grafikkarte zwar voll auf vektor und matrizenberechnungen optimiert, aber vielleicht wird das ja durch die parallelisierung aufgehoben oder teilweise aufgehoben.
    Ich bin mir auch nicht sicher, was die taktfrequenz noch zu sagen hat, aber vielleicht sind die mittlerweile auch bei herkömmlichen operationen gar nicht mehr soweit zurück? ich müssts mal ausprobieren, habe aber zuhause keinen geeigneten rechner ): muss das mal anner uni machen.



  • @gentoo:
    Du scheinst nicht viel Plan davon zu haben, gibst das auch zu, aber wrifst hier mit Mutmassungen um dich... naja.

    Nein, so ein Prozessor (CPU) macht bei den meisten Programmen die meiste Zeit keine Fliesskommaberechnungen. Wie kommst du darauf? Normale Programme machen kaum Fliesskommaberechnungen.

    Normale Programme sind auch meist ziemlich gross (Code-Grösse). Und sind vollgepackt mit bedingten Sprüngen. Und greifen auf höchst nicht-lineare Art und Weise auf den Speicher zu. Und machen allgemein Dinge die die Hardware-Entwickler zum Verzweifeln bringen. Dinge die GPUs nicht gut verkraften.

    Es wundert mich ehrlichgesagt dass du mit vollkommener selbstverständlichkeit davon ausgehst, dass AMD und Intel auf der Nudelsuppe dahergeschwommene Pfuscher-Betriebe wären. Und einfach keine schnelleren CPUs bauen, weil sie zu blöd dafür sind, Firmen wie NVIDIA und ATI das aber ausm Handgelenk schütteln. (Mal ganz davon abgesehen dass ATI mittlerweile von AMG gefressen wurde.)

    GPUs können GPU-Arbeit deswegen sehr schnell, weil sie darauf spezialisiert sind.

    CPUs sind "darauf spezialisiert, nicht spezialisiert zu sein", um alles mögliche halbwegs gut und schnell zu erledigen.



  • gentoo schrieb:

    sind das im wesentlichen nicht alles fließkommaberechnungen, die so ein prozessor macht? hardware-mäßig ist die grafikkarte zwar voll auf vektor und matrizenberechnungen optimiert, aber vielleicht wird das ja durch die parallelisierung aufgehoben oder teilweise aufgehoben.

    die GPUs sind auf parallelisierung optimiert, nicht auf vectorisierung. vectorisierung ist nur etwas was die parallelisierung vereinfacht. wuerdest du eine graphikkarte etwas nicht parallelisierbares ausrechnen lassen, dann waere sie extrem langsam.

    am ende ist alles nur ein speicherproblem.
    was macht ein prozessor wenn die daten nicht da sind auf die er zugreifen will?
    -simple CPUs, z.b. von ARM, Atom usw. machen garnichts, bis der speicher da ist.
    -neuere intel und amd cpus (ab pentium pro bzw athlon) fuehren schon die naechsten instruktionen aus, falls diese nicht auf die daten die gerade gelesen werden zugreifen wollen (beim pentium4 koennen so 205 befehle in den ausfuehrungseinheiten zur gleichen zeit 'schweben')
    -neuste intel und amd cpus laufen schon vorweg ueber die speicher-lade-funktionen und laden die daten spekulativ schoneinmal, falls kein ladebefehl da ist, laden sie spekulativ das naechste speichersegment was im interval liegt dass die beiden vorherigen speicherzugriffe hatten.
    -gpus fuehren die naechsten 'threads' aus.

    'threads'? wtf? an sich ist das nur dummes marketing, es sind einfach nur rieeeesige aufgerollte schleifen. stell dir vor du hast immer mindestens 100pixel die du verarbeitest. dann wuerdest du irgendwann auf die idee kommen, statt

    for(int a=0;a<pixelcount;a++)
       Pixel[a] = ....
    

    etwas wie

    for(int a=0;a<pixelcount;a+=128)
    {
      Pixel[a]=...;
      Pixel[a+1]=...;
      Pixel[a+2]=...;
      Pixel[a+3]=...;
      Pixel[a+4]=...;
      Pixel[a+5]=...;
    .
    .
    .
    }
    

    zu schreiben.

    Und was ist jetzt mit den speicherzugriffen? ganz einfach, der erste Pixel kann einen nicht vorhandenen speicherbereich anfordern, dann arbeitet die gpu auf dem naechsten pixel, der auch einen speicher anfordert, und zwar den pixel daneben, und dann den naechsten und naechsten ....

    bei einer normalen cpu hast du also immer speicherzugriffe die mit laangen stalls verbunden sind und die cpu muss versuchen soviele unabhaengige instruktionen wie moeglich auszufuehren. bei einer gpu hast du einen stall und danach hundert richtige zugriffe (man koennte zwar sagen, 'die sind dann im cache' aber eigentlich ist das dann das was man streaming nennt).

    mit diesem wissen werden dann auch die rechenwerke gebaut.
    bei einer cpu hast du vielleicht etwas wie

    for(int a=0;a<pixelcountl;a++)
    {
    Pixel[a] = Pixel[a]*5.5f+a;
    }
    

    wenn also die cpu es endlich geschaft hat den speicher zu bekommen, dann muss sie so schnell wie nur moeglich machen was zu machen ist und es wieder rausschreiben, damit sie das naechste pixel abarbeiten kann, in diesem moment macht der speicherkontroller und cache eventuell garnichts.
    das bedeutet, dass du sehr viele abhaengigkeiten hast, die cpu muss mit der +a addition warten bis die multiplikation mit 5.5f fertig ist (und versucht vielleicht schon den naechsten befehl auszufuehren).
    bei einer gpu, wenn 128pixel gleichzeitig abgearbeitet werden, dann brauchst du keine schnellen rechenwerke, solange sie pro takt einen befehl aufnehmen koennen, kann eine addition dann ruhig 128takte dauern. das fuehrt dazu, dass die rechenwerke auf der gpu nicht auf geschwindigkeit optimiert werden, sondern auf moeglichst kleine bzw billige bauweise. schau dir bei wikipedia mal sowas wie radix division an, dort siehst du, nur um die geschwindigkeit einer division zu verdoppeln, muss man 3 bis 4mal soviele transistoren verbauen. hat sich fuer den letzten core2 von intel wohl gelohnt.
    gpus bauen hingegen ab, doppelt so lange latenz? dafuer 1/4 transistoren? dafuer also 4mal mehr rechenwerke auf den selben platz? -> 4mal mehr von den "threads" koennen gleichzeitig abgearbeitet werden

    das resultat ist auch, dass der speicher von cpus auf kurze latenz getrimmt wird (ca 100cycles bei 10GB/s) und auf gpus auf durchsatz (400cycles bei weit mehr als 100GB/s).
    und natuerlich 1.2TerraFlops bei einer AMD 4870 graka, und 0.112TerraFlops bei nem neuen Core2 (Nehalem).
    ein weiteres resultat ist, dass eine gpu im schnitt sehr hoch ausgelastet ist (ca 80%) und laut NVidia eine g80 94% auslastung erreichen kann, waehren eine cpu oft 10%auslastung hat und mit wirklich viel SSE optimieren dann auf 30% auslastung kommen kann (beachte maximal-auslastung!=maximal-rechenleistung).

    aber so siehst du auch, wenn du einen loop 128mal unrollst und du wuerdest nun bei jedem 'pixel' einen gaaanz anderen speicherbereich lesen wollen oder z.b. ein switch statement haben, wuerde eine gpu komplett absacken.
    dieser worst-case ist der normalfall fuer eine cpu.
    was die cpu's so an optimierungen fuer schlechten code haben siehst du schoen daran dass ein Celeron mit halben takt von nem Atom diesen schlagen kann (bei nicht vektorisierter software).
    was das alles kostet siehst du auch:
    - Celeron 1.6GHz -> 21Watt
    - Atom 1.6Ghz -> 2.5Watt

    es ist in etwa das was programmiersprachen ausmachen, wuerdest du alles in assembler programmieren und wirklich faehig sein, waere ein Atom architektur otpimal. schreibst du c++ code, z.b. virtual function calls, verursachst du bei den allermeisten cpus schon einen stall wie bei einem if statement das falsch predicted wurde, und natuerlich hat der neuste core2 schon eine optimierung dafuer die in vielen faellen keinen stall mehr hat. hast du sowas wie java, bei der es z.b. mehr indirektionen bei arrayzugriffen gibt (also int[] = new int[...]), muss die cpu erst einen stall ertragen um den ptr zu laden und dann einen um auf den speicher zuzugreifen, waehrend ein stumpfes c array mit int[..] ohne optimierungen dafuer auskommen. hast du einen template tick (;)), kannst du sehr schnell code so aufblaehen dass die cpu mehr den instruction-cache trasht als es irgend ein loop unrollen wert waere.

    entsprechend musst du als programmierer bei den meisten cpus diese sehr gut kennen um was an geschwindigkeit zu erreichen. simples beispiel loops counter:
    Atom: int (weil ein moeglicher int2float schneller ist als uint2float)
    cell-ppu: uint oder int64 (weil jeder signed int mit zwei instructions wegen signed-extension geladen wird)
    cell-spu: uint16 (weil jeder mul, z.b. beim indizieren in nem array von structs sonst 5 statt einer instruction kostet)
    core2: ziemlich egal welcher typ, aber bau ein prefetch auf die wichtigsten daten ein (ansonsten kannst du locker und gerne 50% performance durch stalls verschenken).
    gpu: statische anzahl von loops

    my2cent++

    (nur ein auszug aus meinem "optimizing mit rapso"-buch 🤡 )



  • @rapso:
    Haben denn aktuelle GPUs immernoch die Limitierung, dass "Shader-Units" quasio "synchron" laufen?

    So wie ich das verstehe kann ich schon ein Shader-Programm schreiben, welches z.B. Schleifen/Verzweigungen enthält, und je nach Koordinaten/Texturinhalt/... unterschiedlich arbeitet. Also z.B. auch unterschiedlich viel durchläufe einer Schleife macht.
    Für Pixel 1 brauche ich dann z.B. 20 Durchläufe, für Pixel 2 nur 3, für Pixel 3 dann 5, etc.

    So wie du das beschreibst müsste man nun annehmen, dass *alle* Shader erst mit dem nächsten Pixel anfangen, wenn die 20 Durchläufe für Pixel 1 fertiggerechnet sind.

    So wie ich die Sache verstehe gibt es diese Limitierung aber nicht. Und von daher ist der Begriff Threads nicht so verkehrt.

    Die Shader haben schliesslich ihre eigenen unabhängigen Register und ihren eigenen unabhängigen Call-Stack. Die Limitierung ist bloss dass alle dasselbe Programm ausführen, und vom selben Datenstrom gefüttert werden, die selben Texturen verwenden etc.

    Bitte korrigiere mich wenn ich da jetzt was falsch verstanden habe.



  • hustbaer schrieb:

    @rapso:
    Haben denn aktuelle GPUs immernoch die Limitierung, dass "Shader-Units" quasio "synchron" laufen?

    zu nem gewissen grad: ja

    q[teuo]
    So wie ich das verstehe kann ich schon ein Shader-Programm schreiben, welches z.B. Schleifen/Verzweigungen enthält, und je nach Koordinaten/Texturinhalt/... unterschiedlich arbeitet. Also z.B. auch unterschiedlich viel durchläufe einer Schleife macht.
    Für Pixel 1 brauche ich dann z.B. 20 Durchläufe, für Pixel 2 nur 3, für Pixel 3 dann 5, etc.[/quote]
    dann laeuft der shader 20mal fuer alle durch und maskiert nach dem dritten bzw fuenften durchlauf die resultate fuer diese pixel aus.

    So wie du das beschreibst müsste man nun annehmen, dass *alle* Shader erst mit dem nächsten Pixel anfangen, wenn die 20 Durchläufe für Pixel 1 fertiggerechnet sind.

    mal ein fiktives beispiel:
    stell es dir als ein SIMD vor. die gpu hat eine float unit mit 64cycle latenz, bzw 4fach SIMD mit 16cycles latenz, bzw 16fach SIMD mit 4cycle latenz, egal.
    fest steht, du wirst mit der instruktion bei Pixel[0] erst in 64cycles fertig. also? also arbeitest du schlauerweise 64pixel gleichzeitig ab, weil es dann im nachhinein wirkt also ob du jedes pixel mit einem-cycle-latenz pro instruktion abgearbeitet haettest.

    der fallstrick ist natuerlich, angenommen du hat nun Pixel[0] mit 20 schleifendurchlaeufen und die anderen pixel halt 3 oder 5.
    das resultat, wenn du die anderen pixel nicht abarbeitest, waere dass du nun immer 64cycle latenz abwarten musst, du muestest zusaetzlich eine logik einbauen die diese latenz beachtet, also die stumpfe und guenstige loesung ist, immer mit einer granularitaet von 64pixeln zu arbeiten.

    So wie ich die Sache verstehe gibt es diese Limitierung aber nicht. Und von daher ist der Begriff Threads nicht so verkehrt.

    NV sagt daher, dass sie ihre threads zu "wraps" zusammenfassen, intel spricht von "tuples" usw.

    Die Shader haben schliesslich ihre eigenen unabhängigen Register und ihren eigenen unabhängigen Call-Stack. Die Limitierung ist bloss dass alle dasselbe Programm ausführen, und vom selben Datenstrom gefüttert werden, die selben Texturen verwenden etc.

    nein, shader haben keine unabhaengigen register. es gibt ein paar tausend die sich alle teilen. es gibt auch instruktionen die auf nachbarregister zugreifen, sogar bei hlsl (DDX DDY), ohne das wuerde mipmapping nicht funktionieren.
    die anzahl der 'threads' die du gleichzeitg ablaufen lassen kannst ist entsprechent HardwareRegisterCount/ThreadRegisterCount und wenn dieser wert zu klein ist, bist du vom performance keller weil die latenzen der anderen einheiten nicht gedeckt werden. (steht aber auch alles im cuda manual).

    Bitte korrigiere mich wenn ich da jetzt was falsch verstanden habe.

    naja, ist halt ein starkes marketing was hinter sowas steckt, wenn cuda nicht waere, duerfte ich das hier nichtmal aufklaeren und ohne beweise, wer glaubt schon dass eine shaderinstruktion 64cycles hat ;), nvidia usw. sagen immer 1cycle und einem thread sheduler der ohne 'kosten' branchen kann usw.


Anmelden zum Antworten