Code auf der GPU ausführen

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von Facebamm.

    Code auf der GPU ausführen

    Hallo :D


    ich bin gerade dabei bilder zu analysieren, nun hab ich das problem, das meine CPU in die höhe steigt.

    Meine Idee ist nun den code auf der GPU auszuführen, nur weiß ich nicht wie man das macht und was ich gefunden habe ist
    altimesh.com/run-c-code-gpu-minute/

    Kennt jm. andere wege ohne gleich nen neuen Compiler zu nutzen ?


    Edit (28.02.2020) : github.com/facebamm/Se7enCl - rückmeldungen und wünsche wären nett, bei hilfen einfach schreiben :P

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Facebamm“ ()

    Das Problem ist, eine GPU ist fundamental anders als eine CPU. Eine GPU ist dazu da haufenweise "einfache" Berechnungen parallel durchzuführen. Ist dein Code unendlich parallelisierbar ohne sich selbst zu behindern?

    Schau mal hier rein:
    codeproject.com/Articles/1116907/How-to-Use-Your-GPU-in-NET

    Achja, das was du gefunden hast, ist, so wie es aussieht speziell auf Nvidia Karten ausgelegt, da es den C# Code in CUDA Code umwandelt, anstatt OpenCL. Auch ist durch Cryptominer bekannt, dass Nvidia Karten nicht das performanteste sind, was OpenCL angeht.
    Also sobald ich eine AMD Graphikkarte drinnen habe, kann ich mein Programm in die Tonne werfen ?

    wenn nicht kann ich ja beides einbinden und dann einfach abfragen, was vorhanden ist.

    Direkt bin ich jetzt auf Alea GPU (aleagpu.com) gestoßen und finde das gar-nicht so kacke (edit: hat sich gerade verabschiedet, denn dort wird eine Liezens benötigt) ... nur muss ich den kompletten cuda-driver/compiler oder was das genau ist installiern

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Facebamm“ ()

    gelesen hab ich es, begeisterung hält sich noch in grenzen, aber nur weil ich noch nicht genau weiß wie ich das verwende ...
    ich glaub ich werde mir ein eigenen Wrapper für OpenCl schreiben, dann weiß ich zumindestens was alles vorhanden ist.
    ^- oder ich mach es mir wieder zu kompliziert ...

    @EaranMaleasi aber danke schonmal an dich :D
    Ich gib mal kurzes Update.

    ich hab mich ein wenig belesen und mit OpenCl rum gespielt.
    Mein erstes Fazit zur Sache ist, das der Aufruf des eig. Programmes (zb. Blure.cl) bis zu 5 - 10ms kosten kann, was für mein Fall zulange ist.
    Dazu muss ich beifügen das ich über das Nuget OpenCl.Net (nuget.org/packages/OpenCL.Net/) gehe.

    Persönlich wollte ich mal die Direkten verweise ohne diesen Wrapper ausprobieren und schauen was raus kommt und ob es überhaupt Unterschiede macht.

    Facebamm schrieb:

    bis zu 5 - 10ms kosten kann
    Ich fürchte das ist der Preis den du dafür zahlst, wenn du vom CPU zur GPU wanderst. Neben dem Weg über PCI-E kommt halt dazu dass die Grafikkarte an sich eigentlich ein kleiner Rechner in deinem Rechner ist, der das Programm das du mit OpenCL schreibst in den RAM laden muss usw. wie es die CPU eben mit deinem Programm gemacht hat.
    Naja, das hab ich zu diesem Zeitpunkt schon längst.

    Was ich genau mache ist
    --- Init
    1. Gloable variable von Device, dazu den Context und die CommandQueue initialisieren
    2. Content meines Ressource-Script laden
    2.1 CreateProgramWithSource
    2.2 Auf Build-Errors prüfen
    3. ein Kernel mit meinem Programm erzeugen und in ein Dictionary werfen für später
    --- Run
    1. Meine parameter zum Kernel schieben
    2. EnqueueWriteImage-> EnqueueNDRangeKernel-> EnqueueReadImage-> Finish
    3. Marshal.Copy in mein Bild zurück
    Was dein Programm macht wenns in C# ist und du es prinzipiell gleich schreibst:
    --- Init
    1. ....
    2. MSIL Code laden
    2.1. JIT PrepareMethod...
    2.2. Auf MSIL fehler prüfen
    3. ...
    --- Run
    1. ...
    2. Run
    3. Marshal.Copy in Bild zurück...

    Es ist nicht so viel unterschied im Groben. Natürlich hast du viel davon zusätzlich.

    Also Init kannst doch fast nicht zählen, oder? Passiert einmal, da gibts nunmal nicht großartig optimieren, du könntest beim ersten Start für den nächsten Start evtl. cachen, aber abgesehen davon...
    Schritt 3 knnst dir sparen, wenn du das Bild so erstellst, dass es bereits den Memory auf RAM seite verwendet, an den kopiert werden soll.
    Ansonsten algorithmus optimieren und viel mehr geht nicht mehr....

    Die Frage ist jetzt was zur Hölle hast du vor auszuführen und wie schnell muss es denn sein? Denn ohne mehr Informationen kann man nicht sagen, was du falsch machst, bzw. ob und wie es besser geht, wenn es denn besser geht...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    ich hab ein sehr kompliziertes Bild, was im besten Fall spätestens vor 16ms (60fps) analysiert und ausgewertet sein muss.

    Mit MSIL Code hab ich noch nie gearbeitet, ich werd mich mal rein lesen :D Danke vorerst für den Tipp

    Im Init bereich werde ich probieren mir einen fixen Pointer zu GPU legen und dort direkt schreiben, bestens ohne OpenCL.
    Im Run bereich dann an diesen Pointer meine bytes auslesen ohne meine Parameter in den Kernel zu schieben. :D
    Mit MSIL wollt ich nur darauf aufmerksam machen, dass es unfair ist OpenCL dafür "schlecht" zu machen, dass du die ganze initialisierung brauchst, weil im Prinzip tut C# mit deinem Programm dasselbe. Also für dieses Thema brauchst dich nicht wirklich einlesen...

    Mir ist jetzt immer noch nicht klar was auswerten bedeutet. Was bedeutet kompliziertes Bild? Was machst du danach mit den Daten?
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    achsooo xD mein Fehler.

    ich hab ein graues Bild, welches eine angenäherte Parabelförmige kurve beinhaltet, diese durch läuft ein ebenso ein grauen bereich, der aber etwas dunkler ist.
    Ich muss die Line verstärken und mit dem vorigem bild vergleichen, eine Abweichung bestimmen und Toleranzen erkennen.

    Momentan hänge ich aber beim Sobel Algorithmus ?(

    petaod schrieb:

    Benötigst du jeden einzelnen Frame?

    Ja

    petaod schrieb:

    Steuerst du damit ein Fließband oder regelst du einen Produktionsprozess?

    Produktionsprozess überwachung, eingreifen tut es nicht. nur melden falls was falsch läuft.

    -- Gerade schau mir den Code von Intel an (intel.com/content/www/us/en/pr…/opencl/sobel-filter.html)

    Notice: Mich interessiert auch so die Object Erkennung in Kombination mit AI, aber AI ist noch to mutch für mich :D
    Sobel ist nen einfacher Kernel-Operator der auf jeden Pixel angewendet werden muss, natürlich gibt es da dann noch entsprechende optimierungen.

    Was wichtig ist, dass du möglichst wenig Daten an/von die/der GPU übertragen musst. Z.B. vergleichst du immer den vorherigen Frame mit dem aktuellen Frame. Beim nächsten durchlauf verwendest du den aktuellen Frame als vorherigen Frame, d.h. du musst nur 1 frame/vergleich übertragen.

    Weiter geht es damit, dass es sich ja anscheinend um ein Video handelt, woher kommst du an die Video-Daten? Evtl. wird das ja bereits von der GPU decodiert und es gibt eine Möglichkeit direkt auf der GPU an die Frames zu kommen anstatt es hin und her zu übertragen, das dürfte dir fast am meisten Performance von allen Optionen die mir im Moment einfallen bringen...

    Edit:
    Danach kommt dann der eigentliche Algorithmus. Was machst du sobel und dann differenz oder sobel auf die differenz?
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Das Video kommt von einem Frame-Grapper, aber dort hab ich schon ein Ptr liegen aus dem ich in mein Lokales byte[] kopiere.
    Das schiebe ich dann nur noch in die GPU mit einem Speicherobjekt (image2d_t).

    Was ich machen könnte, wäre mir den Kopier befehl in OpenCl übernehmen und von dort aus kopieren, aber dann weiß ich nicht wie sich das ständige kopieren auf die GPU äußer.
    Eher gesagt weiß ich noch zu wenig über OpenCL um ein statisches Speicherobjekt zu erzeugen, welches durch async nicht immer neu geschrieben wird :/

    Zur Kurve: Ich interpoliere im letzten schritt noch über die Kante um eine eindeutige Funktion zu erhalten ... aber so weit bin ich noch nicht. Das soll das Freitag passieren,


    Kleiner Log ausschnitt
    Spoiler anzeigen

    Quellcode

    1. ​00:00:06.6880888 CaptureVideo 10ms
    2. 00:00:06.6890628 Invalid-Call: 0ms
    3. 00:00:06.6907072 Blure-gpu: 8ms
    4. 00:00:06.6907157 Paint: 1ms //Zeichen in die Form
    5. 00:00:06.6918081 CaptureVideo 10ms //Bild Verarbeitungsstuff
    6. 00:00:06.6926901 Invalid-Call: 0ms // sollte logisch sein
    7. 00:00:06.6942617 Paint: 1ms
    8. 00:00:06.7669529 Blure-gpu: 8ms //Part vom Verarbeitungsstuff
    9. 00:00:06.7680312 CaptureVideo 10ms
    10. 00:00:06.7691093 Invalid-Call: 1ms
    11. 00:00:06.7704977 Blure-gpu: 8ms
    12. 00:00:06.7708431 Paint: 1ms
    13. 00:00:06.7715381 CaptureVideo 10ms
    14. 00:00:06.7726775 Invalid-Call: 1ms
    15. 00:00:06.7738847 Paint: 1ms

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Facebamm“ ()

    Wenn du schon nen pointer hast, warum kopierst du den dann überhaupt in ein byte array, anstelle es direkt vom pointer an die GPU zu übertragen?
    Und was ist das für ein "Frame-Grapper"(meinst vlt. Grabber?) woher bekommt der die Daten wie wertet der die aus?
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---