OpenCl goes AutoIt Update 31.Dezember 2016

  • OpenCl goes AutoIt Update 31.Dezember 2016
    Download: OpenCL_Forum.zip
    //EDIT 31.12.2016

    • einige kleinere Bugs gefixt
    • an AutoIt Version 3.3.14.0 angepasst (Konstantenbezeichnungen)
    • DEVICES64 um Speichertransferzeiten erweitert
    • volle 64Bit-Unterstützung



    Hallo zusammen!
    Um die enorme Rechenpower aktueller CPU´s und Grafikkarten auszunutzen, war AutoIt bisher eher ungeeignet.
    Von den vielen teuer bezahlten Cores der CPU wurde maximal nur einer benutzt, die Rechenleistung der Grafikkarte kam nur einigen Grafikbibliotheken zugute.
    Manch einer kam auf die Idee, den ehrwürdigen AutoIt-Interpreter mittels Assembler- bzw. C-Bibliotheken etwas zu beschleunigen... :rock:


    OpenCl (Open Computing Language) bietet nun die Möglichkeit, die Rechenleistung von CPU, GPU und anderen Prozessoren mittels paralleler Berechnungen und portablem Code Plattformunabhängig auszunutzen!
    OpenCl ist in den neuen Treibern für Grafikkarten bereits integriert. Die SDK´s enthalten reichlich Beispielcode, weiterhin sind tolle Tools enthalten, Profiler, Kerneldebugger und vieles mehr....vollintegriert ins VisualStudio10!
    Ich verweise auf folgende Dokumente, die jeweils aktuellen Versionen erscheinen auf den Entwicklerseiten.
    OpenCL Reference Pages
    Einführung OpenCl auf deutsch
    AMD-SDK
    Nvidia-SDK
    Spezifikation
    AMD-Guide
    Die SDK´s und Treiber gibt es von allen Prozessorherstellern, aktuelle x86-CPU´s und Grafikkarten von AMD und Nvidia werden natürlich unterstützt.


    //EDIT 19.August 2012
    Intel Opencl_runtime only 2012 mehr wird für Intel-Prozessoren nicht gebraucht



    Die OpenCL-API beinhaltet reichlich Funktionen, ich habe die meisten bereits nach AutoIt portiert, aber eine UDF würde ich das im derzeitigen Zustand nicht nennen. Eher ein Proof of concept. Die 2D-Funktionen sind bereits in der Warteschleife 8o



    Was macht OpenCL aus?
    OpenCl lebt von der Parallelisierbarkeit der Algorithmen. Gut parallelisierbar sind z.B. Grafik- und Bildbearbeitungsfunktionen (Filter) oder Sortierfunktionen. Wissenschaftler verwenden bspw. Matrixmultiplikationen, Fouriertransformationen und andere gut parallelisierbare Algorithmen.
    Jedes gut in viele gleiche Teilstücke zu zerlegende programmtechnische Problem wird von OpenCL profitieren!
    Dabei verteilt OpenCL selbstständig das Programm auf alle zur Verfügung stehenden Recheneinheiten.
    Gerade die bis zu mehreren hundert Recheneinheiten auf den Prozessoren der Grafikkarten (GPU) werden ausgenutzt, was gegenüber den CPU´s teilweise immense Geschwindigkeitsvorteile bringt!
    Nicht umsonst werden in den großen Rechenzentren immer häufiger Grafikkarten zum "crunchen" eingesetzt, die CPU´s dienen größtenteils nur noch dazu, diese Grafikkartencluster zu "füttern".


    Wie kommt das Programm nun dazu, auf allen Prozessoren (Cores) gleichzeitig zu laufen? Die Threadverwaltung übernimmt glücklicherweise OpenCl, sind mehr Prozessoren verfügbar, werden diese einfach mitbenutzt...
    Das zentrale Objekt ist der sogenannte "Kernel", ein Programm in C-Syntax, welches während der Laufzeit vom Treiber kompiliert, und dann auf alle Prozessoren verteilt wird.
    Dieser Kernel ist in der Regel in einer einfachen Textdatei abgespeichert, also völlig Plattformunabhängig und somit portabel!


    Die SDK´s enthalten reichlich Beispiele (meistens in C++/C#),aber die dort verwendeten Kernel (die *.cl-Dateien) können logischerweise alle auch mit AutoIt verwendet werden!



    Los gehts mit OpenCL in AutoIt!
    Wer sich ob der Einfachheit gegenüber den Funktionen in den Beispielprogrammen wundert, ich habe viele API-Funktionsaufrufe in EINFACHEN AutoIt-Funktionen gekapselt. Wer hardcore-optimiert oder spezielle API-Funktionen benötigt, kann natürlich auch die API-Calls benutzen!


    Die folgenden Beispiele beinhalten zwar einige Erklärungen, aber wer Fragen oder Probleme hat.....wozu ist das Forum da?^^
    Problembeschreibungen bitte mit Prozessor/Grafikkarte und dem Consolenausdruck posten!
    Beispiel1, eine einfache Quadrierung von Floatzahlen


    Die Funktion _CL_GetDevice() wird verwendet um den Kernel einem bestimmten Gerät (GPU oder CPU) zuzuweisen.
    Bei _CL_GetDevice("CPU") wird die CPU verwendet, _CL_GetDevice("GPU") benutzt den Prozessor der Grafikkarte. _CL_GetDevice("ALL") sucht die nächstbeste mögliche Hardware.
    Der extreme Unterschied zwischen Grafikkarte und CPU wird am folgenden Beispiel deutlich. Wenn eure vorhandene Grafikkarte nicht unterstützt wird, macht nix, es werden wenigstens alle Cores der CPU verwendet!
    Um in den Genuss erhöhterAusführungsgeschwindigkeit durch eine GPU zu kommen, ist eine einfache Einsteiger-Grafikkarte ausreichend. Superteuer muss sie nicht sein, ich habe mir anhand dieser Seite ein Modell in der 70€-Klasse ausgesucht, die passt zu meinem 45€-Prozessor, ist aber zwischen 10 und 100x schneller in der Berechnung einiger Kernel!
    Einige Kernel werden auch auf der CPU (wesentlich) schneller ausgeführt, wieso das so ist, wird sich im Verlauf dieses Threads noch herausstellen...


    Beispiel 2, der aus dem ASM-Tutorial bekannte Tunnelflug, von mir als Basic-Freak wohl eher dilletantisch in das Kernel-C umgesetzt.
    Man beachte den auskommentierten Teil am Ende des Scriptes.


    Besteht bei (von Hand und viel KnowHow und Arbeit) hochoptimiertem Assemblercode (auf der CPU) noch ein gewisser Geschwindigkeitsvorteil gegenüber den gängigen Hochsprachen, wird auf der GPU klar, WO der Hammer hängt!
    Faktor 10-20 in der Geschwindigkeit, OHNE Optimierung! Das funktioniert allerdings nur bei gut zu parallelisierenden Algorithmen. Und Platz für Optimierungen innerhalb der Kernel ist reichlich vorhanden, bedingt durch die "andere" Struktur der Grafikprozessoren, Speicheranbindungen usw.
    Da es für alle gängigen Hochsprachen OpenCL-Unterstützung gibt, reduziert sich der Aufwand zum Beschleunigen eines Programms auf das Umschreiben des "Inner Loop" in einen Kernel, um massiv von der Geschwindigkeit von Mehrkernprozessoren bzw. Grafikkarten zu profitieren!


    Letzes Beispiel: Ein Flug durch die Mandelbrotmenge, diesen Kernel habe ich mir "ausgeliehen" (man muss das Rad nicht immer neu erfinden^^), im Vergleich dazu verweise ich auf den Assemblercode HIER.



    Eins möchte ich noch betonen, die Beispiele sind auf "Einfachheit" getrimmt, es ist natürlich vollkommen blödsinnig, eine Grafik mittels OpenCl auf einer Grafikkarte "rendern" zu lassen, um dann diese Grafik in den Hauptspeicher zu transferieren (DAS kostet ca die 100- bis 1000fache Zeit wie das Rendern an sich!!!) und von dort per GDI wieder zur Darstellung an die Grafikkarte zu schicken....
    OpenGL ist das Stichwort, die üblichen Verdächtigen hier im Forum werden sicherlich passende Beiträge einbringen :thumbup:



    Ich hoffe auf Feedback und einige interessante Vorschläge für Kernel! Viel Spass mit OpenCl!


    P.S.: Großen Dank an TheShadowAE, Sprenger120 und AspirinJunkie fürs Testen auf den diversen Hardware-Plattformen!!!


    //EDIT 8. November 2011:
    Kleine Bugfixes, Log enthält bei Inteltreibern auch ohne Fehler einen Inhalt, Danke an UEZ fürs Testen


    //EDIT 19.August 2012
    Die einige Files sind teilweise angepasst/modifiziert/weiterentwickelt.
    ab diesem Post befinden sich die Vergleiche CPU/GPU als Ergebnis der Mandelbrot-Berechnung


    //EDIT 26. August 2012
    Sollte jetzt auch auf 64Bit-Maschinen laufen
    OpenCl64.au3 ermittelt die vorhandenen Geräte (Devices), mit denen OpenCL-Kernel berechnet werden können.


    //EDIT 31.Dezember 2016
    Funktionen weiter angepasst



    Damit die Bestimmung des Geräts und die Kompilierung des Kernels nicht so aufwendig sind, habe ich diese in eine Funktion gewrappert.
    Mit der Funktion _CL_GetDevice() kann man die Wahl des Devices entweder selbst bestimmen per

    _CL_GetDevice()

    , dann wird das nächste verfügbare Device verwendet

    _CL_GetDevice("CPU")

    verwendet die CPU, GPU die GPU....
    In der Console erscheinen in blauer Schrift die verfügbaren Geräte in einem String, z.B.

    Zitat

    >Device verfügbar= 1;2;2;CPU;AMD Athlon(tm) II X2 250 Processor;129377568;89564448


    die erste Ziffer bezeichnet die Platform (INTEL/AMD/NVIDIA o.a.), die zweite Zahl das dort enthaltene Gerät (Device)
    Wenn man genau dieses Gerät verwenden möchte, dann sollte man

    _CL_GetDevice("ALL",Ziffer_Device,Ziffer_Platform) ;angeben;im vorliegenden Beispiel also_CL_GetDevice("ALL",2,1);verwendet das 2. Device von der 1. Platform


    die 3. Ziffer des Strings vom verfügbaren Device bezeichnet den Typ (GPU/CPU), dann folgt der Name des Geräts, die Device_ID und die Platform_ID


    Nach dem Aufruf von _CL_GetDevice() muss man nur noch die Kernel-Parameter setzen und den Kernel laufen lassen, s. weitere Beispiele.


    OpenCL_Forum.zip

  • HIER
    alternativ:

    Global Const $DIB_RGB_COLORS = 0
    Global Const $SRCCOPY = 0x00CC0020

  • Zitat

    Edit: Bei $num_platforms = 0 solltest du noch einen Fehler werfen, statt deine UDF zu crashen


    Klugsch**** ;)
    Wenn ich nur 5% von deinem Skill hätte, dann WÄRE das jetzt eine UDF, und nicht ein armseliger Haufen halbgarer Funktionen :thumbup:
    Aber ich hab da was für dich..
    autoit.de/wcf/attachment/14534/
    ...die müssten alle noch angepasst und getestet werden^^

  • Zitat von progandy

    Super, Du solltest aber noch doe globale Variable $KernelSource durch einen Funktionsparameter ersetzen


    wieso, der zieht sich den Funktionsnamen doch aus dem Kernel direkt

    ;Kernel erstellen für jedes einzelne workitem
    ;kernelname extrahieren, der Kernelname steht idR vor der öffnenden Klammer, Regex needed^^
    $kname1 = StringInStr($KernelSource, "__kernel")
    $kname2 = StringInStr($KernelSource, "(", 0, 1, $kname1)
    $kname = StringSplit(stringstripws(StringMid($KernelSource, $kname1, $kname2 - $kname1),6), " ", 3)
    $kernel = clCreateKernel($program, $kname[UBound($kname) - 1], $errcode_ret)

  • Hi Andy,


    Wieder mal eine saugeile Idee :thumbup:
    Nur ein Problem tut sich auf:


    Bei mir wird angeblich kein Device (weder GPU noch CPU) gefunden.


    GPU: NVIDIA 9800GTX+ (BlackMod) (1 GByte)
    CPU: Intel Core 2 Duo, 2 x 1.75 GHz (ErsatzCPU, meine normale ist K.O gegangen)


    In Bezug auf Fehlercodes kannst du Sprenger fragen, weil Ich hab die Code's jetzt nicht zur Hand.


    mfg,
    Dominik

  • Hi,

    Zitat von Greenhorn

    Warum tut Ihr beiden Andys euch nicht zusammen und optimiert das zu einer UDF ?!

    Na, schaumamal^^.
    Ich fand ja die Idee sehr interessant, mit einer Scriptsprache "ernsthaft" die Möglichkeiten aktueller Hardware voll ausnutzen zu können.
    Ausserdem hast du mich ja "heiss" gemacht, wie soll man sonst einen Bulldozer mit 8 Kernen mittels AutoIt füttern ohne sich die Finger mit Threadverwaltung usw zu brechen?
    Weiterhin gäbe es nun auch mal die Möglichkeit, gewisse UDF´s wie z.B. die BigNum etwas "aufzumöbeln"....und nicht zuletzt wurde ich gezwungen, mich mit C auseinanderzusetzen (mit dem ++-Gedöns können sie mir (vorerst) aber trotzdem den Buckel runterrutschen :rofl: )


    Blume, bitte Info, ob und wie du Opencl zum Laufen bekommen hast!
    Die neuesten Grafikkartentreiber bringen OpenCl-Unterstützung mit, ansonsten sollte zumindest der Prozessor unterstützt werden (s. Progandys Link)

  • Hi,

    Zitat von Greenhorn

    Funzt OpenCL auch mit nVidia-Karten ?

    ja, bei Verwendung der neuesten Treiber (R280.xx ??) ist OpenCl-unterstüzung implementiert. Ob deine Grafikkarte aber mitspielt, weiss ich nicht^^


    Zitat von UEZ

    Leider funzt es auf meinem Schlepptop mit einer Intel Gfx Karte nicht

    Leider funzt es auf meinem PIII-Celeron mit 1,2Ghz auch nicht^^ Aber auf dem kann man noch sehr schnelle Assemblerprogramme schreiben :rofl:
    Aber Spass beiseite, ggf. funktioniert ja die CPU als Device.

  • Ich bekomme immer Fehlermeldungen (Returncode 1). Z. B. bei der einfachen Quadrierung:


    Code
    C:\Coding\AU3\GFX\OpenCI\opencl_easy.au3 (38) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
    DllStructSetData($context_properties, 1, $platform[1], 2)
    DllStructSetData($context_properties, 1, ^ ERROR


    Gruß,
    UEZ

  • Die eigentliche Abfrage eines Fehlers geschieht mittels der Auswertung des Error-Returncodes des API-Calls.
    Wenn du in der Msgbox die Info "DllCall failed" bekommst, dann ist der Rückgabewert der vom DllCall(), also bei 1 => "@error: 1 Die Dll-Datei kann nicht verwendet werden, "
    ggf 32-Bit-Problem? OpenCl benutzt nur 32Bit-Dll´s!

  • UEZ: Der Fehler kommt solange kein OpenCL-Gerät gefunden wird. Dann musst du je nach CPU das passende SDK installieren und neustarten. Vielleicht hilft das auch bei ein paar Grafikkarten, aber ich beweifle das. Wenn die Graka nicht will, dann hilft auch das SDK nichts. Bei der CPU sieht das aber anders aus ;)