Quicksort mit 32-Bit Integerwerten

    • Offizieller Beitrag

    In GetUniqueColors gab es die Aufgabenstellung alle Farben in einem Bild zu zählen.

    Hier soll es jetzt um das sortieren von 32-Bit-Integerwerten gehen. Wenn man ein AutoIt-Array mit 1Mio Elementen hat und dieses mit _ArraySort sortieren will, dann dauert das ziemlich lange (ca. 26 Sekunden auf meinem Rechner und mit Zufallsdaten).

    Das Ganze dauert in Assembler ca. 56 Millisekunden. Zumindest das reine sortieren. Um in Assembler mit dem AutoIt-Array arbeiten zu können, müssen wir es in eine Struct kopieren und nach dem sortieren in Assembler müssen wir die Daten aus der Struct wieder in das Array zurück kopieren.

    Dieses umkopieren dauert jedes Mal ca. 1.2 Sekunden. Somit ergibt sich für das sortieren mit dem Assemblerprogramm eine Gesamtlaufzeit von ca. 2.5 Sekunden. Das ist aber immer noch ein mächtiger Geschwindigkeitsgewinn (nur ein Zehntel der Zeit).

    Dieses Assemblerprogramm möchte ich euch hier vorstellen.

    Dazu habe ich die Quicksort-Funktion aus dem obigen Thread noch verbessert:

    - Beim Start wird überprüft, ob die Daten bereits sortiert vorliegen. Das kostet zwar ein paar Millisekunden für den Test, aber es ist schneller als die sortierten Daten erneut durch die Funktion zu schicken.

    - Quicksort wird nicht ausschließlich verwendet. Bei weniger als 45 Elementen pro Partition werden die verbleibenden Elemente mit InsertionSort sortiert. Diese Kombination ist schneller, als ein reines Qiucksort.

    - Das Pivotelement ist jetzt nicht mehr das erste (linke) Element einer Partition, sondern das Mittlere. Das bringt einen enormem Geschwindigkeitsgewinn bei teilsortierten Listen.

    Ausgabe bei mir:

    Code
    ASM-Code-Size:    221 Bytes
    Test-Array:    1000000 Elemente
    ArrayCreate:    1237.211 ms
    
    Array2Struct:    1116.148 ms
    ASM_Sort:    55.360 ms
    Struct2Array:    1190.879 ms
    
    _ArraySort:    25923.010 ms

    Wer selbst am ASM-Code rumbasteln will, benötigt "Assembleit2_64" von Andy und muss die Zeilen 4 und 166 aktivieren und die Zeilen 167 und 168 auskommentieren.

    Ansonsten habe ich alles ausgiebig kommentiert, sodass der Ablauf verständlich wird.

  • Hallo Oscar !

    Vielen Dank, insbesondere für die extra-ausführlichen Kommentare :thumbup:

    Hier zum Vergleich mal die Laufzeitdaten meines, schon etwas in die Jahre gekommenen, PC's :

    Code
    ASM-Code-Size:    221 Bytes
    Test-Array:    1000000 Elemente
    ArrayCreate:    2065.598 ms
    
    Array2Struct:    1797.610 ms
    ASM_Sort:    65.873 ms
    Struct2Array:    1999.078 ms
    
    _ArraySort:    56228.328 ms

    Gruß Musashi

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

  • Hallo Oscar,

    in diesem Post GetUniqueColors habe ich eine Version verwendet, welche aus den Speicherinhalten (UINT/DWORDS) "lesbare" Zahlen (bestehend aus Ziffern^^) macht.

    Das geht relativ schnell, dann hast du einen Text, welchen du per Stringsplit in ein AutoIt-Array umwandeln kannst.

    Ich habe eben mal getestet, bei 1Mio Elementen (in diesem Fall Pixelfarben) dauert auf meinem Rechner der Stringsplit() ca. 500 ms! Die Handvoll Takte zum Erstellen des Textes aus den DWORDS fallen dabei nicht auf....

  • Hallo Oscar ,

    ich bin vor einiger Zeit über diesen Thread gestolpert, der sicher auch für dich interessant ist.

    Accessing AutoIt Variables

    Accessing variables

    AutoIt is a BASIC-like language. In BASIC-like languages simple variables are internally stored as variants, and arrays are internally stored as safearrays contained in variants.

    Assuming that an AutoIt variable is internally stored as a variant, is it possible to get a pointer to this variant?

    Assuming that an AutoIt array is internally stored as a safearray contained in a variant, then it should be possible to get a pointer to the safearray through the pointer to the variant.

    Why is a pointer to a safearray interesting? Because such a pointer can be passed as a parameter to a function coded in assembler, C, C++, C# or FreeBasic. We can thus access an AutoIt array directly from a function coded in another language, without the need to convert the array to a structure (DllStructCreate) or similar. In this way it's possible to code very fast array manipulation functions in a real compiled language.

    • Offizieller Beitrag

    Andy: Das erfordert dann aber einen zusätzlichen Speicher (bei 1Mio. DWORDs = 4 Mio. Bytes wären das zusätzliche 8 Mio. Bytes für die Chars). Aber das bestätigt eigentlich meine Vermutung, dass die vielen DLLStructGetData die eigentliche Bremse sind. Es fehlt in AutoIt, die Möglichkeit die Structur wieder schnell in ein Array umzuwandeln.

    Bitnugger: Ich bin noch am durchtesten, aber verstehe ich das richtig, dass dort quasi ein Pseudo-Variant-Array erzeugt und das dann zur Übergabe nach AutoIt benutzt wird. Kann ich das dann von beiden "Seiten" aus benutzen? Und was ist, wenn man mehrere Arrays benötigt?

    Wie werden da dann die Daten umkopiert?

  • verstehe ich das richtig, dass dort quasi ein Pseudo-Variant-Array erzeugt

    Es wird ein SafeArray erzeugt... wie du das von beiden Seiten handhaben kannst, ist z. B. gut in den Examples in .\Tests\Examples\2) Array variables\ zu sehen.

    ==>> An AutoIt array is a safearray contained in a variant.

    Und was ist, wenn man mehrere Arrays benötigt?

    Dann erzeugst du halt mehrere SaveArrays. Wenn du dir die Examples angeschaut hast, wirst du sicher durchblicken. ;)

  • Andy: Das erfordert dann aber einen zusätzlichen Speicher (bei 1Mio. DWORDs = 4 Mio. Bytes wären das zusätzliche 8 Mio. Bytes für die Chars). Aber das bestätigt eigentlich meine Vermutung, dass die vielen DLLStructGetData die eigentliche Bremse sind. Es fehlt in AutoIt, die Möglichkeit die Structur wieder schnell in ein Array umzuwandeln.

    Jetzt bin ich mal unverschämt und frage, wer bei der Verwendung von 1 Mio DWORDS als Integerwerte überhaupt mit AutoIt-"Arrays" arbeitet?!

    Eine wie auch immer Struct ist bereits ein Array. In einer der früheren AutoIt-Versionen hatte ich mal einen Vergleich erstellt, der Struct-Funktionen und Arrayfunktionen verglichen hat, wobei beide Verfahren etwa gleich schnell waren.

    Daraufhin hatte ich ein Script geschrieben, welches meine bisherigen "Array"-Funktionen-Scripte in "DllStruct..."-Scripte umschrieb. So war es auch kein Thema, mit schnellen (bei mir ASM-) Funktionen diese Daten zu bearbeiten. Das hat so lange zu meiner Zufriedenheit funktioniert, bis ich festgestellt hatte, dass "irgendjemand" aus der AutoIt-Entwicklercrew die "Struct"-Funktionen massiv in der Geschwindigkeit beschnitten hatte....Soviel zum Update-Wahn und "alles wird besser...". Sch*** drauf!

    Ich hatte mich übrigens mit LarsJ´s Scripten beschäftigt. Sehr intensiv. Um dann festzustellen, dass GENAU das, was eigentlich der riesengroße Vorteil von AutoIt-Arrays ist, nämlich beliebige Datentypen in einem Array zusammenzuwürfeln, nur über massive Umwege wieder in SaveArrays umzuwandeln ist!

    Nur, und da liegt der Hase im Pfeffer, wozu braucht man überhaupt Array´s?!

    Damit irgendwelche Programmieranfänger mit Antwortposts zu _FileReadToArray-Anfragen zugeschmissen werden und davon ausgehen, das sei der ultimative Heilsbringer. Und sich dann wundern, warum 800MB große CSV-Files eine Viertelstunde brauchen um eingelesen zu werden...:Face:

    Arrays machen da Sinn, wo man relativ problemlos und schnell "kleine" Probleme lösen will/muss. Für alles andere MUSS es auch andere Lösungsansätze geben. Und ein "Array" aus 1 Mio 32-Bit-DWORDS ist imho nichts, was man mit AutoIt-Arrays angehen sollte:theke:. Jedenfalls wenn man Wert auf Geschwindigkeit legt.:P

    Übrigens umgeht man mit der Verwendung der SaveArrays nur die AutoIt-interne umkopiererei. Wenn man bspw. an eine Dll-Funktion den Pointer auf einen Datentyp (bspw. String) übergeben muss und dann denkt, "einfach" nur mit "ptr",$string* sei das Problem gelöst, dann fängt der Ärger schon an. AutoIt alloziert zunächst einen Speicherbereich, kopiert dann den String in diese extra dafür(!) erstellte Struct im Speicher und liefert dann den Pointer zurück:Face:.Bei kurzen Strings kein Thema, bei einem MB großen String sind 2 Sekunden weg nur für die Kopieraktion. Bei 100MB großen Strings fängt es dann an, SEHR zäh zu werden...und Strings sind nur ein Beispiel, man kann Pointer auf beliebige Datentypen verwenden...X/

    • Offizieller Beitrag

    Ich habe meine Zeit jetzt erstmal in eine Multi-Thread-Version investiert.

    Eigentlich macht es ja wenig Sinn, gerade die ASM-Funktion weiter zu beschleunigen, wenn Array2Struct und Struct2Array ein Vielfaches der Zeit für die ASM-Funktion ausmachen.

    Aber ich wollte mal mit mehreren Threads arbeiten und die Sortierfunktion war gerade da. :D

    Da die Threads von AutoIt aus gestartet werden, muss ich ihnen also entsprechende Aufgaben zuweisen.

    Hier habe ich das jetzt so gemacht, dass zuerst ein Master-Thread gestartet wird, der die erste Partitionierung vom Quicksort übernimmt und dann die Splitposition zurück gibt (das geht recht schnell).

    Mit dieser Splitposition starte ich zwei Threads, die dann parallel die beiden Partitionen sortieren (das dauert dann länger, wenn man bei Millisekunden von länger sprechen kann). ;)

    Der Erfolg hängt aber sehr stark von der Splitposition ab. Befindet sich die Splitposition so ziemlich in der Mitte (bei 1Mio Elementen also irgendwo im 500tausender Bereich), dann verkürzt sich die Sortierzeit von ca. 56ms (Singlethread) auf ca. 30ms (Multithread):

    Code
    Split-Element:    513727
    ASM_Sort:    30.647 ms

    Und je schlechter die Splitposition wird:

    Code
    Split-Element:    724651
    ASM_Sort:    42.461 ms

    umso länger dauert das sortieren:

    Code
    Split-Element:    25823
    ASM_Sort:    55.198 ms

    Ich verwende ja das mittlere Array-Element als Pivotwert. Das ist bei bereits sortierten Daten super schnell:

    Code
    Split-Element:    499999
    ASM_Sort:    3.560 ms

    Das garantiert aber nicht, dass beide Partitionen bei Zufallsdaten auch annähernd gleich groß sind. Bei Zufallsdaten ist es schwierig einen geeigneten Pivotwert zu finden. :/

    Trotzdem war es schon ganz interessant, mal etwas Multithreading zu machen. :)

    • Offizieller Beitrag

    Jetzt bin ich mal unverschämt und frage, wer bei der Verwendung von 1 Mio DWORDS als Integerwerte überhaupt mit AutoIt-"Arrays" arbeitet?!

    Eigentlich hast Du Recht!

    Wenn wir schon Assembler für die Geschwindigkeit einsetzen, dann kann man auch den Rest des AutoIt-Programms danach ausrichten.

    Diese SafeArray-UDF erscheint mir auch als ein recht großer "Moloch", den man dann mit rumschleppen muss.

  • Der Erfolg hängt aber sehr stark von der Splitposition ab. Befindet sich die Splitposition so ziemlich in der Mitte (bei 1Mio Elementen also irgendwo im 500tausender Bereich), dann verkürzt sich die Sortierzeit von ca. 56ms (Singlethread) auf ca. 30ms (Multithread):

    [...]

    Ich verwende ja das mittlere Array-Element als Pivotwert.

    Im Mittel kannst du das beschleunigen, - bzw. Worst-Cases vermeiden - in dem du für das Pivot-Element das erste mittlerste und letzte Element nimmst und hiervon den Median bildest.
    Damit ist das Pivot-Element im Mittel viel mehr in der Mitte als wenn man ein einziges Element zufällig auswählt (was im Grunde ja deine bisherige Variante ist).

  • Bei Zufallsdaten ist es schwierig einen geeigneten Pivotwert zu finden

    Quickselect wäre doch eine Möglichkeit, wenn man es mit dem approximierten Median of medians verwendet. Dann hast du zwar nicht den exakten Median (zumindest gibt es kein Garant dafür), aber bist ziemlich nah dran und die Komplexität ist Linear.

    AspirinJunkies Idee gefällt mir auch, heuristisch dürftest du damit fast immer richtig liegen.

    Es gibt sehr viele Leute, die glauben. Aber aus Aberglauben.
    - Blaise Pascal

    • Offizieller Beitrag

    in dem du für das Pivot-Element das erste mittlerste und letzte Element nimmst und hiervon den Median bildest.

    Ja, damit sinkt die Worst-Case-Wahrscheinlichkeit und im Mittel sieht das Ergebnis schon viel besser aus.

    Allerdings habe ich das "Median of three" nur für die Partitionierung des Master-Threads verwendet. Wenn ich das bei jeder Partitionierung verwende, dann frisst die Laufzeit zum ermitteln des Median den Vorteil auf.

    Vor allem bei bereits sortierten Daten steigt damit die Laufzeit auf das Doppelte an.

    Master benutzt "Median of three" und die Slaves den mittleren Pivotwert. Damit liegt die Laufzeit meistens bei 30...40 ms.

    Quickselect wäre doch eine Möglichkeit, wenn man es mit dem approximierten Median of medians verwendet.

    Damit würde die Hauptaufgabe auf den Master-Thread liegen und ich würde mit den Slaves keinen Geschwindigkeitsgewinn mehr erzielen.

    Die Suche nach einem brauchbaren Median muss schon sehr schnell gehen (Laufzeitmäßig).

    Ich werde mal noch den Dual-Pivot-Quicksort ausprobieren. Dann könnte ich auch drei Threads gleichzeitig starten. Mal sehen, wie es damit aussieht.

    Hier mal die "Median of three"-Variante:

    > Diese hier war falsch! Die korrekte Version gibt es in Post#15

  • Vor allem bei bereits sortierten Daten steigt damit die Laufzeit auf das Doppelte an.

    Ja das ist natürlich ein gravierendes Problem.
    Man will Daten sortieren die bereits sortiert sind und nun braucht der Algorithmus dafür 60 statt 30ms.... ;)

    Im Grunde macht die Pivot-Auswahl das nicht gravierend langsamer sondern du nutzt durch die Wahl des mittleren Elementes einfach nur den absoluten Best-Case aus (der in der Realität aber keine Rolle spielt).

    Wenn der Mehraufwand hierfür zu groß wird kannst du auch versuchen das ganze größenabhängig zu machen:

    Bei großen Elementmengen den Median of three, bei kleinen das mittlere/zufällige Element, und bei kleinen Elementmengen Insertion-Sort.

    Auch die Frage ob der 3er Median effizienter implementiert werden kann, könnte noch geprüft werden.

    Also z. B. wenn es ein Min/Max bei Assembler gibt: max(min(a,b), min(max(a,b),c)) oder sowas.
    Wie du es jetzt machst weiß ich nicht - denn ich hab keine Ahnung von Assembler ;)

    Einmal editiert, zuletzt von AspirinJunkie (23. Dezember 2017 um 20:33)

  • Also z. B. wenn es ein Min/Max bei Assembler gibt: max(min(a,b), min(max(a,b),c)) oder sowas.
    Wie du es jetzt machst weiß ich nicht - denn ich hab keine Ahnung von Assembler

    min() und max() gibt es als Befehl in der SSE, imho aber für 32Bit-Zahlen nur für Float. Ggf. muss man die integer zuerst in float umwandeln und nach der Berechnung wieder zurück. https://c9x.me/x86/

    Und hier die (alten, aber um Klassen besseren) AMD-Docs zu den SSE-Befehlen http://www.share-online.biz/dl/QPV4OG1P30 mit sofort nachvollziehbaren Bildern wie die Register miteinander interagieren.

    Ansonsten MIN() als C-Funktion HIER eingeben und schauen, was die diversen Compiler daraus machen :o)

    • Offizieller Beitrag

    Wenn der Mehraufwand hierfür zu groß wird kannst du auch versuchen das ganze größenabhängig zu machen:

    Bei großen Elementmengen den Median of three, bei kleinen das mittlere/zufällige Element, und bei kleinen Elementmengen Insertion-Sort.

    Oh Mist, ich habe einen Fehler bei der Umsetzung von "Median of three" (Post#12) gemacht. Statt ECX habe ich EDX geschrieben. Dadurch war der letzte Swap falsch und verursachte längere Laufzeiten.

    Und das führte auch zu der sehr langen Laufzeit (> 100 ms) bei bereits sortierten Zahlen. :whistling:

    Nachdem ich den Fehler behoben habe, beträgt die Laufzeit bei sortierten Zahlen jetzt nur noch ca. 3 ms.

    Ich verwende jetzt auch immer den "Median of three". Auch für die Slaves. So schwankt die Laufzeit zwischen 30 ms und 45 ms für 1 Mio DWORDs.

    Und Insertionsort für kleine (< 45) Elementmengen verwende ich doch bereits.

    Hier die korrekte Version:

  • Oscar, TOP ASM-Code, handoptimiert und mit Multithreading den letzten Schliff gegeben. :klatschen:

    Bin mal gespannt wo das endet....:rock:

    • Offizieller Beitrag

    Oscar, TOP ASM-Code, handoptimiert und mit Multithreading den letzten Schliff gegeben.

    Bin mal gespannt wo das endet....

    Danke!

    Wobei ich an dieser Stelle Dir auch nochmal für Deine "assembleit2_64.au3"-UDF danken möchte.

    Die macht das einbinden von ASM in AutoIt doch erheblich einfacher. :klatschen:

    Leider ist die Lernkurve bei Assembler ja recht steil. Im Gegensatz zu AutoIt findet man recht wenig passende Dokus.

    Aber vielleicht kannst Du mir weiterhelfen:

    Die XMM-Register sind ja 128 Bit breit. Ich kann also 128 Bit (4 DWORDs) in einem Rutsch aus dem Speicher lesen.

    Aber wie komme ich an die einzelnen DWORDs ran?

    Wie bekomme ich die in ein 32-Bit-Register z.B. nach EAX?

  • Hi!

    Ich hatte im vorigen Post die (alte) PDF-Datei von AMD mit den 128-Bit-Erweiterungen, also die SSE-Befehle, angehängt.

    Ich finde diese PDF deshalb klasse, weil bei den Funktionen sämtliche Vorgänge der Register(inhalte) untereinander bebildert sind. Ich frage mich immer wieder, wie viele "Freaks" die aktuellen Doc´s von Intel und AMD in die Ecke feuern, weil definitiv KEIN MENSCH anhand der dortigen "Erklärungen" weiß, was in einem Register abläuft. Ein Bild sagt mehr als 1000 Worte!

    Leider ist die Lernkurve bei Assembler ja recht steil. Im Gegensatz zu AutoIt findet man recht wenig passende Dokus.

    Du hast ja beeindruckend gezeigt, dass es trotzdem geht. Assembler ist ja kein Hexenwerk entgegen den heutzutage gängigen Programmiersprachen. Du hast eine Handvoll Register, den Speicherplatz und eine Handvoll EINFACHER(!!!) Befehle was gemacht werden soll.

    Schlimmstenfalls muss man den Debugger bemühen. :Glaskugel:Und sich das Vorher-Nachher-Ergebnis anschauen....und "Bugs" GIBT ES NICHT!

    Um etwas tiefer einzusteigen, empfehle ich die Beiträge, Manuals und Doc´s von Agner Fog. Sowohl für Compilerverwender als auch für die hardcore-ASM-Freaks ist das alles Stoff für unter das Kopfkissen:rtfm:

    Die XMM-Register sind ja 128 Bit breit. Ich kann also 128 Bit (4 DWORDs) in einem Rutsch aus dem Speicher lesen.

    Aber wie komme ich an die einzelnen DWORDs ran?

    Bei SSE gibt es sicher 20 unterschiedliche MOV(XXX)-Befehle. Alle transferieren Speicherbereiche in Register bzw Register in Register. Das einzige, was beachtet werden muss ist das sog. alignment des Speicherzugriffs auf 16-Byte-Adressen. Aber auch für unaligned Speicherzugriffe gibt es (etwas langsamere) Befehle.

    Um 4 DWORDS aus dem Speicher in ein Register zu schieben, bietet sich MOVDQU (das U für Unaligned) an. Bei Bitmaps liegen die Daten oder Pixel idR. hintereinander im Speicher. Da die Bitmap beim Erstellen durch GDI(plus) glücklicherweise schon 16-Byte aligned angelegt wird, bietet sich zum blockweisen auslesen von 4 dword/int/uint usw. der aligned Zugriff, also MOVDQA, an.

    Aber das ist schon die hohe Kunst. Zum Erstellen von einfachen Tests und Programmen verwende einfach immer die Unaligned-Befehle, die Handvoll Speichertakte für den "länger dauernden" Zugriff sind meist die Mühe durch den Absturz(!) nicht wert. Beim aligned Zugriff auf eine unaligned Adresse folgt nämlich der Absturz, man bemerkt seine Fehler SOFORT deutlich:D

    Übrigens macht es durchaus Sinn, die SSE-Befehle nur auf einen Teil der 128 Bit anzuwenden, viele Compiler machen das so, da die SSE-Befehle in einer eigenen Pipeline im Prozessor laufen und zu allem Überfluss auch noch extrem schnell abgearbeitet werden, idR. für die Standard-Befehle nur EIN Prozessortakt! Übrigens kann man die Registerinhalte, also die DWORDS, BYTES usw. innerhalb der Register beliebig anordnen, Eukalyptus hier aus dem Forum hat dazu ein wunderschönes AutoIt-Script erstellt.

    Wenn du Fragen hast, egal zu was, bitte fragen! Ich weiß zwar nicht (mehr) viel, aber habe eine umfangreiche Sammlung von Dokumenten, Scripten und Tips und Tricks.

    Und da du ja fit in C(++) bist, die Seite https://godbolt.org zeigt dir anschaulich, was diverse Compiler aus C++-Code machen, und wie mies dieser dann oft ist! Das "rumspielen" mit Compilerschaltern ändert dann oft das Compilerverhalten und zeigt meist auf den ersten Blick den "besseren" Code!

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    Einmal editiert, zuletzt von Andy (27. Dezember 2017 um 08:25)

  • Hallo Andy !

    Und hier die (alten, aber um Klassen besseren) AMD-Docs zu den SSE-Befehlen http://www.share-online.biz/dl/QPV4OG1P30 mit sofort nachvollziehbaren Bildern wie die Register miteinander interagieren.

    Frage :

    Wenn Du schreibst, dass die alten AMD-Docs um Klassen besser sind, meinst Du das im Vergleich zu den aktuellen Revisionen dieser Docs, oder zu neueren Dokumentationen im Allgemeinen ?

    Auf den schnellen Blick scheint die Revision 3.10 (September 2007) des Volumes 4 tatsächlich einige Grafiken zu enthalten, die in der Revision 3.21 (Dezember 2017) fehlen, bzw. anders dargestellt werden.

    Ich habe den aktuellen Stand des AMD-Programmer’s Manual (mit Links) hier mal zusammengefasst !

    Das Manual setzt sich aus den folgenden Volumes zusammen :

    Volume 1: Application Programming 24592

    Volume 2: System Programming 24593

    Volume 3: General-Purpose and System Instructions 24594

    Volume 4: 128-Bit and 256-Bit Media Instructions 26568

    Volume 5: 64-Bit Media and x87 Floating-Point Instructions 26569

    Downloadinfos :

    AMD64 Architecture - Programmer’s Manual Volume 1

    Application Programming

    Publication No.=24592 Rev.=3.22 Date=December 2017

    Download : https://support.amd.com/TechDocs/24592.pdf

    AMD64 Architecture - Programmer’s Manual Volume 2

    System Programming

    Publication No.=24593 Rev.=3.29 Date=December 2017

    Download : https://support.amd.com/TechDocs/24593.pdf

    AMD64 Architecture - Programmer’s Manual Volume 3

    General-Purpose and System Instructions

    Publication No.=24594 Rev.=3.25 Date=December 2017

    Download : https://support.amd.com/TechDocs/24594.pdf

    AMD64 Architecture - Programmer’s Manual Volume 4

    128-Bit and 256-Bit Media Instructions

    Publication No.=26568 Rev.=3.21 Date=December 2017

    Download : https://support.amd.com/TechDocs/26568.pdf

    'Ältere Version' von Andy :

    AMD64 Architecture - Programmer’s Manual Volume 4

    128-Bit Media Instructions

    Publication No.=26568 Rev.=3.10 Date=September 2007

    Download : http://www.share-online.biz/dl/QPV4OG1P30

    AMD64 Architecture - Programmer’s Manual Volume 5

    64-Bit Media and x87 Floating-Point Instructions

    Publication No.=26569 Rev.=3.14 Date=September 2016

    Download : https://support.amd.com/TechDocs/26569_APM_v5.pdf

    Ob man diese PDF's direkt hier im Forum posten darf, kann und möchte ich nicht beurteilen ;).

    Im Lizenztext steht (Auszug) :

    "Durch dieses Dokument wird keine Lizenz, auch nicht implizit oder durch Rechtsverwirkung, für geistige Eigentumsrechte gewährt."

    Da die Links zu den neuen Revisionen aber von 2016/2017 stammen, dürften sie wohl noch für längere Zeit Bestand haben.

    Schlussbemerkung :

    Ich finde das ganze Thema wirklich spannend, auch wenn mir wahrscheinlich (leider) die Zeit fehlt, intensiver einzusteigen. Meine oberflächlichen Gehversuche dbzgl. stammen noch aus dem letzten Jahrtausend ^^.

    Trotzdem dürfte es einige interessierte, wenn auch stille, Mitleser geben. In diesem Sinne - Weiter so :thumbup:

    Gruß Musashi

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

  • Wenn Du schreibst, dass die alten AMD-Docs um Klassen besser sind, meinst Du das im Vergleich zu den aktuellen Revisionen dieser Docs, oder zu neueren Dokumentationen im Allgemeinen ?

    Ich meine die 128Bit-Media-Instructions, also die Referenz der SSE-Befehle Public.nr. #26568. In den neueren Versionen ist keine einzige (!) grafische Entsprechung. Kein Wunder, dass so gut wie niemand diese Befehlserweiterungen nutzt, übrigens auch per Intrinsics aus diversen Hochsprachen heraus, wenn niemand auch nur annähernd lt. der Beschreibung in der Lage ist nachzuvollziehen, was diese Befehle überhaupt bewirken!

    Der Witz dabei ist, dass jeder sofort anhand der grafischen Entsprechung im Debugger SEHEN kann, wie die Inhalte der 128-Bit-Register aussehen sollten.

    Siehe Eukalyptus´Shuffle-Script. Da sieht jeder sofort durch und "sieht" auch direkt den Befehl, den man benutzen muss um eine bestimmte Aktion auszulösen....

    pasted-from-clipboard.png

    Da lese ich nicht mal mehr den Text sondern suche in den Doc´s nur noch nach den entsprechenden "Bildern". Die kann man sich auch merken, wenn man diese Befehle nicht oft benutzt, so nach dem Motto "...habe ich doch schon mal irgendwo gesehen...."

    Wie gesagt, alle diese SSE-Befehle sind (mindestens) per Intrinsics in C++ bzw. den gängigen Compilersprachen nutzbar!!! Verwendung dort...so gut wie NULL! Wieso?....Siehe die "neuen" entsprechenden Beschreibungen....Von AVX ganz zu schweigen....

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    Einmal editiert, zuletzt von Andy (26. Dezember 2017 um 23:10)