Geschwindigkeitsoptimierung in AutoIt

    • Offizieller Beitrag

    Hey,


    Ich wollte hier mal ein kleines Tutorial schreiben, wie man sein Script, wenn es wirklich um jede nanosekunde geht, optimieren kann. Ich würde mir wünschen, das ihr auch was dazu Beiträgt, egal in welchem Bereiech (Sei es nun einfache Funktionen, GDI, GUI, Operatoren, Arrays, ...) - immer alles her damit. :)


    Unten findet ihr ein Script mit dem ihr es testen könnt und eure Ergebnisse teilen könnt:


    Ich mache mal den Anfang:






    Fortsetzung folgt (hoffentlich auch durch euch :) )


    Gruß,
    Spider

  • Hi,


    alles, was nicht über interne (kompilierte oder API) Funktionen läuft, wird bei AutoIt interpretiert.
    Somit gilt bspw. für sämtliche in Schleifen verarbeitete mathematische Funktionen (sin, cos, tan, +-*/ usw.) und auch für sonstigen "normalen" Code:
    Weniger = Schnellerer


    Generell sollte man sein Script profilen und den "inner loop" suchen. Meist sind es nur eine Handvoll Zeilen, welche die Scriptlaufzeit wirklich beeinflussen.
    Wenn es wirklich auf die Millisekunde ankommt, diskutiert man erst gar keine AutoIt-interne Abwicklung, sondern schreibt den "inner loop" in eine FreeBasic/C(++)/ASM/wieauchimmer kompilierte DLL und ruft diese per DllCall() auf. Thema erledigt.

    • Offizieller Beitrag

    Hallo,


    Dem kann ich nur bedingt zu stimmen. Natürlich stimmt es, dass AutoIt nicht für wirklich rechenintensive Aufgaben geeignet ist, sehr wohl aber für eine schnelle Benutzeroberfläche, wenn man es richtig angeht.
    Ich habe z.B. ein Projekt geschrieben, welches auf einem Low Level PC laufen soll (Atom 1,4 GHz; 1gb ram; win7) und welches Live Daten via WinPcap interpretiert und anzeigt und das in Millisekunden raster. Das habe ich nur geschafft in dem ich an jeder Kleinigkeit herum experimentiert habe um es so effizient wie nur möglich zu gestalten, da hier wirklich sehr viel interpretiert wird.


    Klar beim If/Switch Fall ist es relativ egal, man sieht ja das bei einem Aufruf der unterschied bei 0,002 ms ist, aber z.B. die Geschichte mit der For/While Schleife war hier sehr hilfreich und wenn ich nun 50 Interpretationsfunktionen habe, in denen ich alle von While auf For wechsle sind das gut und gerne paar Millisekunden die man direkt merkt.


    Ein paar Daten die da durchlaufen müssen allerdings noch entschlüsselt und entpackt werden, das lagere ich natürlich hier auch auf C aus, da hatte AutoIt keine Chance.


    Trotzdem: Ich arbeite mit AutoIt nach wie vor sehr gerne wenn es um grafische Angelegenheiten geht, da ist AutoIt C/C++ weit überlegen was die Einfachheit angeht; wenn der Kunde ein Änderungswunsch hat --> kein Problem, eine Stunde später steht die neue GUI.


    Deswegen dieser Thread, ich dachte mir falls jemand ein ähnliches Vorhaben hat kann er/sie sich hier paar Tips abholen ;)


    Gruß'
    Spider

  • Klar beim If/Switch Fall ist es relativ egal, man sieht ja das bei einem Aufruf der unterschied bei 0,002 ms ist, aber z.B. die Geschichte mit der For/While Schleife war hier sehr hilfreich und wenn ich nun 50 Interpretationsfunktionen habe, in denen ich alle von While auf For wechsle sind das gut und gerne paar Millisekunden die man direkt merkt.

    Genau DAS meine ich mit dem finden des "inner loop"!
    Wenn ich Millisekunden schinden will/muss, dann kommt die Schleife natürlich mit in die entweder per DllCall() / DllCallAddress() angesprochene Funktion!
    Es bleibt auszuprobieren, ob der overhead von DllCall() / DllCallAddress() nicht den Gewinn über die schnellere Ausführungszeit auffrisst!


    Das habe ich nur geschafft in dem ich an jeder Kleinigkeit herum experimentiert habe um es so effizient wie nur möglich zu gestalten, da hier wirklich sehr viel interpretiert wird.

    Ein langsam programmiertes Programm bzw. Algorithmus bleibt auch langsam, wenn man es auf einem schnellen Rechner oder mit einem schnellen Compiler einsetzt.
    Wenn man, so wie du es gemacht hast, den Algorihmus bzw. den Programmablauf ständig mit Hinblick auf Geschwindigkeit optimiert, ist man schon auf dem richtigen Weg.
    Ich habe allerdings die Erfahrung gemacht, dass sich kaum jemand diese Mühe macht....intensives profiling ist auch nicht jedermanns Sache!


    Ich behaupte mal, dass AutoIt idR. schnell genug ist, gerade im Hinblick auf

    eine schnelle Benutzeroberfläche, wenn man es richtig angeht.

    Die Frage bleibt, ob man, wenn man wirklich bis auf die letzte Rille optimieren muss, nicht einfach nur die GUI und das drumherum in AutoIt programmiert, und den (idR wenigen) zeitintensiven Rest dann "auslagert".

  • Ich denke die wichtigste Regel sollte sein, dass man immer erst zu erst auf Algorithmenebene optimieren sollte bevor man sich an die Optimierung auf der Codeebene macht.
    Die Frage ob man 20 ms bei 1000 Schleifendurchgängen rausholen kann durch z.B. eine For-To statt While-Schleife wird hinfällig wenn man den Programmablauf auch so realisieren kann, dass man nur 100 Schleifendurchgänge braucht.

    • Offizieller Beitrag

    Hey,


    Klar, habt ihr beide recht mit. Irgendwann ist der Algorhytmus (gerade bei sowas wie ein Sniffer) aber Optimiert bis zum geht nicht mehr und dann kann es schon interessant werden ob z.B. GuiCtrlListViewCreate oder _GuiCtrlListView_Create schneller ist. In der Live Darstellung (>30 Aktualisierungen pro Sekunde) geht da bei nicht optimierter Programmierung schnell AutoIt in die Knie (unabhängig vom Prozessor).


    Auch wenn ich C und ein großteil von C++ beherrsche, lager ich gerne trotzdem viele einfache Sachen noch in AutoIt aus, ganz einfach wegen der Einfachheit der Sprache.


    Ich wollte hier aber auch keine Diskussion auslösen, ob man AutoIt für rechenintensive Vorgänge benutzen sollte oder nicht, manche tuns mehr, manche weniger, die Diskussion hatten wir schon oft genug hier im Forum, also lassen wir es jetzt bitte darauf beruhen.


    Falls jemand noch Ideen zur Codeoptimierung hat, natürlich immer gerne her damit :)


    lg,
    Spider

  • @GTA:
    Bei Ram, muss Du da nicht noch mal 1,024 nehmen, da er jetzt, wenn ich das richtig sehe, ein GB als 1.000 sieht und nicht als 1.024. Richtig oder falsch? Bei mit zeigt er 5,87 GB RAM an, mal 1,024 = 6,01 GB RAM, was dann dem Weit näher kommt.

    ...... Lieben Gruß, ........
    ...........
    Alina ............

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Ich habe die Deutsche Hilfe auf meinem PC und
    OrganizeIncludes ist beim Scripten mein bester
    Freund. Okay?

    • Offizieller Beitrag

    Nein Alina, er teilt das Ergebnis von MemGetStats zweimal durch 1024 und das ist korrekt, da MemGetStats das Ergebnis als KB zurückgibt. Durch 1024 geteilt ergibt MB und nochmal durch 1024 geteilt ergibt GB.


    GtaSpider : Bei mir erscheint als Ergebnis Deines Testscript auch, das For...Next am schnellsten ist, aber in der Schleife wird ja auch nichts ausgeführt.
    Wenn man das Script etwas abwandelt (praxisnäher gestaltet), dann relativiert sich das Ergebnis etwas. For...Next ist zwar noch immer am schnellsten, aber nicht derart krass.

  • Na dann denke ich wir fangen am besten mal mit dem Thema Schleifenoptimierung an, da dort wohl eine Menge Potential schlummert.
    Ich gehe einfach mal einige übliche Optimierungen durch. Ich zeige dabei jeweils erst die unoptimierte Variante und dem gegenüber die optimierte. Nicht alles bringt auf AutoIt etwas (besonders die für Cache-optimierenden Verfahren). Deswegen hänge ich immer direkt daran ein kleines Testskript wo man das Potential bei sich selbst schnell ermitteln kann.


    Fangen wir an:








    2 Mal editiert, zuletzt von AspirinJunkie () aus folgendem Grund: Forum hat die StringFormat-Anweisung falsch dargestellt.

  • Hier mal ein paar weitere Methoden. Diesmal thematisch jedoch eher durcheinander:










  • Interessanter Thread!
    Ich selber habe mich noch nie mit der Geschwindigkeit von Programmen befasst. Vielleicht mal wenn es in den Grafischen Bereich ging. Ansonsten war und ist die Geschwindigkeit von AutoIt durchaus ausreichend gewesen. Aber echt interessant was für Kleinigkeiten einige Sekunden einsparen. Ich denke wenn man konsequent dann auf diese kleinen Dinge achtet, dann sollte man einen deutlich merkbaren Unterschied in komplexen Algorithmen spüren. Natürlich sollte man zuerst den Algorithmus an sich verbessern. Wie kommt man eigentlich darauf? Bzw. wo gibt es Lektüre zu diesem Thema? Gibt's da spezielle Begriffe zu um sich das eine oder andere selber zu googeln?


    Um selber mal was beizutragen:
    Wer gerne mit GDI+ arbeitet sollte sich mal überlegen Bitmaps (normalerweise verwendet man ja ein Backbuffer) mit _WinAPI_BitBlt() ins Fenster zu zeichnen. Dies ist um Längen schneller als _GDIPlus_GraphicsDrawImage(). Siehe Codebeispiel:

    • Offizieller Beitrag

    Hallo,


    Schön! Vielen Dank für das Feedback, da kann man sich doch gut was raus holen :)


    GtaSpider : Bei mir erscheint als Ergebnis Deines Testscript auch, das For...Next am schnellsten ist, aber in der Schleife wird ja auch nichts ausgeführt.
    Wenn man das Script etwas abwandelt (praxisnäher gestaltet), dann relativiert sich das Ergebnis etwas. For...Next ist zwar noch immer am schnellsten, aber nicht derart krass.


    Stimmt; das hab ich nicht beachtet. ToolTip ist Grafisch, hier auch mal mit einer nicht grafischen Funktion


  • Natürlich sollte man zuerst den Algorithmus an sich verbessern. Wie kommt man eigentlich darauf? Bzw. wo gibt es Lektüre zu diesem Thema? Gibt's da spezielle Begriffe zu um sich das eine oder andere selber zu googeln?

    Die erste Regel ist, den Code zu profilen!
    In AutoIt haben wir dahingehend etwas gelitten, mehr wie einige Timings bekommt man nicht aus dem ausgeführten Code heraus...
    In anderen Programmiersprachen gibt es Profiling-Tools, welche Ergebnisse bis zum Erbrechen (Anzahl Prozessortakte) bereitstellen!
    Dabei sollte man beachten, dass es nichts nutzt, denjenigen Programmteil zu optimieren, der nur 5% der Gesamtlaufzeit beansprucht!
    Also so die Timings setzen, dass man den Codeteil findet, welcher am öftesten/meisten angesprungen wird!


    Die ersten Schritte wurden ja schon in den Beispielscripten gezeigt. Loop/Funktion ausstoppen, schneller = besser. Fertig!
    Aber wie kommt man zu einem "schnelleren" Algorithmus? Naja, kurz gesagt wurde so gut wie jedes EDV-technische Problem schon bis zum Abwinken behandelt :D
    Entweder man benutzt hochoptimierte Bibliotheken, oder man sucht in den einschlägigen Foren oder Webseiten <<LINK>>
    Aber auch einfaches analysieren bringt oft schon erstaunliche Ergebnisse.
    - Ist der Code zu parallelisieren, kann man ihn in mehrere "Threads" aufteilen?
    - Gibt es mathematische Umformungen, um Berechnungen "anders" durchzuführen?
    - Muss jede Funktion (UDF) unbedingt mit sämtlichen Errorhandlings ausgestattet sein?
    - Habe ich den Vergleich zum unoptimierten Code? Wie viel schneller ist der optimierte Code?
    - Wie viel schneller sind vergleichbare Programme? Lohnt es sich, Stunden/Tage/Wochen aufzuwenden um in einem Programm welches 2x am Tag läuft, 10 Sekunden einzusparen?


    Und man sollte sich fragen, wieso ein Prozessor, welcher heutzutage mit >4 Cores und 4,5Ghz Takt daherkommt, per "Sleeps" dahin gebracht wird, mit 1-2% Last zu laufen...
    Mir ist ehrlich gesagt lieber, der Prozessor hat so viel zu tun, dass mein Profiling-Tool kein einziges Mal den Tiefschlaf registriert! Erst wenn das Ding richtig glüht, wird es auch ausgenutzt! Einen Ferrari kauft man auch nicht, um 3x im Jahr im 2. Gang zum Einkaufen zu fahren....
    GuiGetMsg() ist so ein Kandidat, der in einer geschwindigkeitsoptimierten Schleife NICHTS zu suchen hat!

  • Hy,


    Ich habe mir den Thread mehrfach durchgelesen! Erstmal große Klasse das diese Infos zusammengetragen wurden.


    Ich habe mir das Programmieren vor ewigkeiten selber beigebracht, und meinen Skill ständig weiterentwickelt. Nur fällt mir in den letzten Jahren immer mehr auf, das ich mit den ganzen Bezeichnungen gar nichts anfangen kann... Da wirst du von jemanden gefragt ob du mit der Technik XXY arbeitest - und ich gucke dumm aus der Wäsche, weil ich keinen Schimmer habe was denn gemeint ist. Bis ich vor dem Rechner sitze, und total unbewusst 80% der hier vorgetragenen Techniken seit Jahren anwende - ohne das eigentlich zu Wissen...


    Muss mich umbedingt mehr mit der Theorie auseinander setzen...


    Grüsse!


    P.S:
    Andy hat es bereits angesprochen, Parallelisierung und auch Multi -Threading oder -Processing sind in der Optimierung der letzte große Schritt. Damit kann man, gerade Algoryhtmen, bis zum Faktor 3 bis 4 beschleunigen OHNE große Eingriffe im Algo selber durchführen zu müssen.

  • Warum reden hier alle von Parallelisierung?
    Es ist in nativem AutoIt nicht möglich (zumindestens kein Threading).

    Damit kann man, gerade Algoryhtmen, bis zum Faktor 3 bis 4 beschleunigen OHNE große Eingriffe im Algo selber durchführen zu müssen.

    Und dann wundern wenn dauernd falsche Ergebnisse zurückkommen...
    Parallelisierung ist selten so einfach wie die meisten denken.
    Einfach mal ein OpenMP-Tutorial durchlesen und seine Schleife parallelisieren führt selten zu einer linearen Skalierung mit den Threads.
    Optimierung auf paralleler Ebene ist eben nochmal ein ganz anderer Schuh.


    In anderen Fällen stimmt das Ergebnis auf einmal nicht mehr.
    Man sollte niemanden leichtfertig den Tipp geben, dass er seine Programme mit Parallelisierung mal ganz einfach um mehrere Vielfache beschleunigen kann ohne ihm vorher die Begriffe race condition, lost update oder Cache-Kohärenz zu erklären...


    Da es vorhin schon angesprochen wurde möchte ich es auch nochmal aufgreifen.
    Wenn man seine Programme optimieren will setzt man nicht einfach irgendwelche Tricks in seinem Programm um, sondern man beginnt mit einem Profiling (und zieht das den gesamten Optimierungsprozess auch durch).
    Die Teile, welche als relevant detektiert wurden, werden dann erst einmal auf Algorithmenebene optimiert bevor man die hier vorgestellten Tipps anwendet.
    Aber einfach nach dem Gießkannenprinzip alle Performancetipps auf das Skript verteilen hat mit Optimierung nicht wirklich viel zu tun.

  • Optimierung auf paralleler Ebene ist eben nochmal ein ganz anderer Schuh.

    wohl wahr...
    Das ist auch mit ein Grund, wieso diese Technik, obwohl seit Urzeiten ( >20 Jahren ) möglich, kaum verwendet wird! Es ist nämlich eine große Portion KnowHow und Skill vonnöten...
    Ich behaupte einfach mal, dass 99% der "Programmierer" schon mit dem Setzen der "richtigen" Compilerflags völlig überfordert sind, bzw. diese Art der Optimierung überhaupt nicht verstehen und auch nicht für nötig halten!
    Absolut gesehen rennt die "richtige" Programmierung und Anwendung der in Software verwendbaren möglichen Technik der Hardwareentwicklung 10 Jahre hinterher.
    Wieso ein Programm beschleunigen, wenn man für einige Hunderter einen Rechner kaufen kann, der bis auf eine Handvoll Hardcore-Spiele sowieso jegliches Programm schon im Schlafzustand des Prozessorss mit völlig ausreichender Geschwindigkeit ausführt?!
    Ich rede hier nicht von Forschungseinrichtungen und Hochschulen, welche dankbar sind für jedes kleine Quentchen Hardware-Power. DORT kostet Rechenpower richtig Geld, und genau dort wird bis auf den letzten Prozessortakt Software optimiert. Genau dort finden sich aber auch die Leute mit dem Skill und von dort kommen auch die hochoptimierten Bibliotheken ;)

    • Offizieller Beitrag

    Nachdem ich jetzt alle Beispiele durchprobiert habe, bin ich doch etwas überrascht bezüglich der Ausführungsgeschwindigkeit im X64-Modus.
    Wurde da mittlerweile so viel optimiert bei AutoIt (v3.3.12.0)?
    Ich meine mich erinnern zu können, dass es bei älteren Versionen keinen so gravierenden Unterschied gab, bzw. dass der X64-Modus sogar langsamer war.
    Könnt ihr das bestätigen oder läuft bei mir irgendwas im Hintergrund, was zu diesen Unterschieden führt. Hier mal die Ergebnisse mit dem Test von GtaSpider aus Post#13:

  • Hier mal meine Daten für die NSA: