_Au3Optim (Inline-Funktionen und Code-Optimierung)

  • Funktion zur Optimierung von au3-Programmen.

    _Au3Optim

    Anwendung am besten nach einem Durchlauf durch den Obfuscator, damit alle Include-Dateien und Konstanten
    ebenfalls berücksichtigt werden.
    Dabei die Option /om des Obfuscators mit anwenden, damit alle Variablen/Funktionsnamen usw. auf ein Minimum reduziert werden.

    1) #define
    Definition von Makros und Konstanten.

    2) Inline Funktionen
    Ähnlich wie inline-Funktionen in C, Java ...
    Zusätzlich werden die zu ersetzenden Funktionen optimiert:
    - Mathematische Funktionen werden berechnet

    ABER:
    Kann nur Funktionen ersetzen die wie folgt aufgebaut sind:

    Code
    Func _Name($n, ....)
     Return Ausdruck
    EndFunc

    3) Optimierung:
    - Globale Konstanten werden durch ihre Werte ersetzt.
    - Mathematische Ausdrücke werden durch das Ergebnis ersetzt.
    (für bessere Ergebnisse Variablen möglichst an den Anfang oder das Ende setzen)
    - StringFormat (ohne Variablen) wird aufgelöst
    - StringLower/Upper mit konstanten Strings wird ersetzt
    - Zuweisungen wie $i = $i +1 werden durch $i += ersetzt
    - Anweisungen wie

    [autoit]

    If $a = True Then
    ;werden durch
    If $a Then
    ;ersetzt, bzw.
    If $a = False Then
    ;durch
    If Not $a Then
    If @error = 0
    ; durch
    If Not @error

    [/autoit]


    - Strings werden zusammengefaßt

    [autoit]

    "test" & " test"
    ; wird zu
    "test test"

    [/autoit]


    - Statements die über mehrere Zeilen gehen werden zu einer Zeile vereint.
    - Einzeilige If-Blöcke werden zusammengefasst:

    [autoit]

    If $a Then
    ; machwas
    EndIf
    ; wird zu
    If $a Then ;wachwas

    [/autoit][autoit][/autoit][autoit]

    If $a Then
    If $b Then ; machwas
    EndIf
    ; wird zu
    If ($a) And ($b) Then ; machwas

    [/autoit]

    Sinn des Ganzen:
    - Mehr Übersicht beim Programmieren durch "Auslagern" von häufig verwendeten Ausdrücken in Funktionen,
    Durch das Ersetzen mit dieser Funktion spart man dem Interpreter später den Aufruf der eigentlichen Funktionen.
    - Kompakter Programm-Code
    - Höhere Ausführungsgeschwindigkeit

    Test-Programm (input):

    Spoiler anzeigen
    [autoit]

    ; Test.au3 fuer _Au3Optim

    [/autoit] [autoit][/autoit] [autoit]

    #define @InetGetActive InetGetInfo()

    [/autoit] [autoit][/autoit] [autoit]

    Global const $test=2 ; Test 1
    global Const $test2 =4
    global const $test3= 8
    Global Const $test4 = "das ist ein Test" ; Test 4
    global Const $test5 = 'das ist ein anderer Test'

    [/autoit] [autoit][/autoit] [autoit]

    $bla1 = $test+ $test2 + $test3
    $bla2 = $test4
    $bla3 = $test5

    [/autoit] [autoit][/autoit] [autoit]

    DllStructCreate( _
    "dword dwsize;" & _
    "dword cntUsage;" & _
    "dword th32ProcessID;" & _
    "uint th32DefaultHeapID;" & _
    "dword th32ModuleID;" & _
    "dword cntThreads;" & _
    "dword th32ParentProcessID;" & _
    "long pcPriClassBase;" & _
    "dword dwFlags;" & _
    "char szExeFile[260]" _
    )

    [/autoit] [autoit][/autoit] [autoit]

    $s = @InetGetActive

    [/autoit] [autoit][/autoit] [autoit]

    $a7j = _k_()

    [/autoit] [autoit][/autoit] [autoit]

    $ms = $s34 *1000*60*$min
    $t = (3 + 32) * 45
    $ms = "1000*60*34"
    $ms = '1000*60*34'

    [/autoit] [autoit][/autoit] [autoit]

    If _Bla() = 0 And $t = 0 or($t = 0) Then $bla = True
    If $a[0] = False Then $bla = True
    If @error = 0 Then

    [/autoit] [autoit][/autoit] [autoit]

    If $a = 1 Or $t6575 = True Then $bla = True
    If $a = True Then $bla = True
    If @error = 1 Then

    [/autoit] [autoit][/autoit] [autoit]

    $variable = $variable + 1
    $i = $i *10

    [/autoit] [autoit][/autoit] [autoit]

    $s = StringFormat("%s %.2f %s", "test", 4.56345345 , "test")
    $s = StringFormat("%s %.2f", "test", 4.56345345 * $test2)
    $s = StringFormat("%s %.2f %s", "Das ist eine Zahl", 4.56345345 , $test20)

    [/autoit] [autoit][/autoit] [autoit]

    Msg("Hallo Welt")

    [/autoit] [autoit][/autoit] [autoit]

    $c = _F2C($F, 2)
    $c = _F2C(128, 2)

    [/autoit] [autoit][/autoit] [autoit]

    $b1 = _Test0(1, 2)
    $b2 = _Test0(3, 4)
    $b3 = Abs(_Test0(5, 6) + 100)

    [/autoit] [autoit][/autoit] [autoit]

    $a = 1
    _Test1($a, 2)

    [/autoit] [autoit][/autoit] [autoit]

    _Test2("Hallo ", "das ist ein ", "Test") ; Test 2

    [/autoit] [autoit][/autoit] [autoit]

    $b = _Test3("text")

    [/autoit] [autoit][/autoit] [autoit]

    $c = _Test4(5)

    [/autoit] [autoit][/autoit] [autoit]

    ; EndFunc
    ; ==============================================================================
    Func _fg($t = 0, $2 = 1)
    Local $t
    Return
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _k_()
    Return(@YEAR & "/" & @MON & "/" & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _1_()
    Return "test"
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _F2C($F, $iP)
    Return Round(($F - 32) * 5 / 9, $iP)
    EndFunc ;==>_F2C

    [/autoit] [autoit][/autoit] [autoit]

    Func _Test0($a, $z)
    Return $z * 3 * $a + 100
    EndFunc ;==>_Test0

    [/autoit] [autoit][/autoit] [autoit]

    Func _Test1(ByRef $a, $b)
    Return ConsoleWrite($a + $b)
    EndFunc ;==>_Test1

    [/autoit] [autoit][/autoit] [autoit]

    Func _Test2($a, $b, $c)
    Return ConsoleWrite($a & $b & $c & @CRLF)
    EndFunc ;==>_Test2

    [/autoit] [autoit][/autoit] [autoit]

    Func _Test3($u)
    Return $u
    EndFunc ;==>_Test3

    [/autoit] [autoit][/autoit] [autoit]

    Func _Test4($s)
    Local $r = $s * 2
    Return $r
    EndFunc ;==>_Test4

    [/autoit] [autoit][/autoit] [autoit]

    Func Msg($s)
    Return MsgBox(0, "Message:", $s)
    EndFunc ;==>Msg

    [/autoit]


    ergibt:

    Spoiler anzeigen
    [autoit]

    ; Test.au3 fuer _Au3Optim

    [/autoit] [autoit][/autoit] [autoit]

    $bla1 = 14
    $bla2 = "das ist ein Test"
    $bla3 = 'das ist ein anderer Test'

    [/autoit] [autoit][/autoit] [autoit]

    DllStructCreate( "dword dwsize;dword cntUsage;dword th32ProcessID;uint th32DefaultHeapID;dword th32ModuleID;dword cntThreads;dword th32ParentProcessID;long pcPriClassBase;dword dwFlags;char szExeFile[260]" )

    [/autoit] [autoit][/autoit] [autoit]

    $s = InetGetInfo()

    [/autoit] [autoit][/autoit] [autoit]

    $a7j = (@YEAR & "/" & @MON & "/" & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC)

    [/autoit] [autoit][/autoit] [autoit]

    $ms = $s34 *60000*$min
    $t = (35) * 45
    $ms = "2040000"
    $ms = '2040000'

    [/autoit] [autoit][/autoit] [autoit]

    If Not _Bla() And Not $t or($t = 0) Then $bla = True
    If Not $a[0] Then $bla = True
    If Not @error Then

    [/autoit] [autoit][/autoit] [autoit]

    If $a Or $t6575 Then $bla = True
    If $a Then $bla = True
    If @error Then

    [/autoit] [autoit][/autoit] [autoit]

    $variable += 1
    $i *= 10

    [/autoit] [autoit][/autoit] [autoit]

    $s = "test 4.56 test"
    $s = "test 18.25"
    $s = StringFormat("%s %.2f %s", "Das ist eine Zahl", 4.56345345 , $test20)

    [/autoit] [autoit][/autoit] [autoit]

    MsgBox(0, "Message:", "Hallo Welt")

    [/autoit] [autoit][/autoit] [autoit]

    $c = Round(($F - 32) * 0.555555555555556, 2)
    $c = 53.33

    [/autoit] [autoit][/autoit] [autoit]

    $b1 = 106
    $b2 = 136
    $b3 = Abs(290)

    [/autoit] [autoit][/autoit] [autoit]

    $a = 1
    ConsoleWrite($a + 2)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("Hallo das ist ein Test" & @CRLF) ; Test 2

    [/autoit] [autoit][/autoit] [autoit]

    $b = "text"

    [/autoit] [autoit][/autoit] [autoit]

    $c = _Test4(5)

    [/autoit] [autoit][/autoit] [autoit]

    ; EndFunc
    ; ==============================================================================
    Func _fg($t = 0, $2 = 1)
    Local $t
    Return
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Test4($s)
    Local $r = $s * 2
    Return $r
    EndFunc ;==>_Test4

    [/autoit]

    Was noch zu tun ist:
    - Fehler beheben
    - "Berechnungen" in Strings verhindern
    - Ersetzen von konstanten Arrays
    - Ersetzung lokaler Konstanten.
    - Ersetzen von optionalen Parametern, falls sie nicht verwendet werden, durch deren Vorgaben
    - Optimierung
    - Bessere Fehlerkontrolle
    - ausführliche Tests :)
    - Einbau in den Preprozessor von jEdit4AutoIt

    Bekannte Fehler:
    - Befinden sich Aufrufe von Inline-Funktionen in verschachtelten Funktionsaufrufen, werden dieses falsch ersetzt
    - Globale Constanten ersetzen auch Locale Variablen mit gleichem Namen.

    21 Mal editiert, zuletzt von Stilgar (23. Dezember 2009 um 20:11)

  • Wäre auch interessant.
    Da gäbe es sicher einiges Andere auch noch zu machen. Denn wenn man mal ein paar Laufzeitmessungen an "ungünstigen" Programmen vornimmt, dann sieht es so aus als ob der Compiler rein gar nichts optimiert.
    Wäre wirklich schön wenn da dran mal was geändert werden würde.

    [EDIT]
    Update auf V0.2:
    - Optimierung
    - Mathematische Funktionen werden nun stellenweise gleich berechnet.

    Thorsten

    Einmal editiert, zuletzt von Stilgar (13. November 2009 um 10:56)

  • Sehr schöne Idee!
    Man könnte das Script auch im Bezug auf die Verbesserung der Geschwindigkeit der (kompilierten) Programme erweitern. Stichwort kürzere Variablennamen. Ähnlich wie das, was der Obfuscator macht, aber nicht im Sinne von Unleserlichkeit, sondern mit dem Ziel der besseren Performance.
    So könnte man ein Script mit "normalen" Variablennamen bearbeiten, beim Kompiliervorgang würden aber (wie z.B. der Syntaxcheck) die Variablennamen durch ihre "Kurzform" ersetzt.

  • Die Obfuscator-Option /ObfuscateMinumum sollte bezüglich den Namen auch helfen, ist erst seit kurzem dokumentiert.

    [EDIT]
    V0.3
    - Einfache mathematische Ausdrücke werden im gesamten Programm durch das Ergebnis ersetzt.
    (vergessen mit reinzukopieren)

    2 Mal editiert, zuletzt von Stilgar (13. November 2009 um 11:59)

  • Da scheint noch was nicht richtig zu funktionieren:

    SIC2 ist der ursprüngliche Code und SIC2_opt.au3 das Resultat deines Skriptes.

    Z.B. kann man mit Total Commander die Unterschiede beider Dateien übersichtlich einsehen.

    So wird z.B. aus $a3d = StringSplit('31,28,31,30,31,30,31,31,30,31,30,31', ',') => EndIf Not $a3d tringSplit('31,28,31,30,31,30,31,31,30,31,30,31', ',')

    Gruß,
    UEZ

  • Danke für den Hinweis!

    Einige Fehler sind nun behoben, andere noch nicht ...:

    Behoben:
    - ersetzen von Hex-Konstanten
    - EndIf / If: Fehler bei Abfrage-Optimierung
    - Berechungen: Variablen-Namen mit einer Zahl am Ende wurden "mitberechnet"

    Noch nicht behoben:
    - Berechnungen in Strings werden ausgeführt.
    - "Inline"-Funktionen ohne Parameter, werden falsch behandelt

    Neu:
    - Mehrzeilige Statements werden zusammengefaßt.
    - Zusammenfassung von Strings nach dem Ersetzen von Konstanten
    _Define: Einfache "Such und Ersetz"-Funktion per #define

    Einmal editiert, zuletzt von Stilgar (17. November 2009 um 16:51)

  • Nochmal ein Update:

    * Die Funktionen zusammengefaßt
    * ^ wird nun berechnet
    * And / Or / ElseIf Ausdrücke optimiert
    * Abfragen von @error optimiert
    * Behoben: Inline-Funktionen ohne Parameter werden nun korrekt ersetzt.

  • Update:

    * Optimierungen:
    - Step 1 bei For wird entfernt
    - If $a <> ""|'' => If $a
    - If $a = ""|'' => If Not $a
    - RegExen optimierten

    * Korrekturen:
    - Fehler in If-Optimierung behoben
    - Fehler beim Ersetzen von Parametern in "Inline"-Funktionen behoben
    - Fehler beim Ersetzen der Funktions-Aufrufe behoben

  • Update:

    * Neue Optimierungen:
    - Klammern um Return-Werte werden entfernt - keine Ahnung was das überhaupt soll ...
    - Bit*-funktionen werden berechnet, so weit möglich

    * Korrekturen:
    - Mehrere Fehler bei der Optimierungen von IFs behoben.

    • Offizieller Beitrag

    - Unnötige einzeilige If-Blöcke zusammenfassen:


    Gilt das noch oder hast du das evtl. geändert?
    Ich glaube, wir hatten mal in einem Wettbewerb festgestellt, dass einzeilige If-Statements deutlich langsamer sind als If-Then-EndIf. Somit wäre das kontraproduktiv.

  • UEZ:
    Funktionieren nun beide wieder - außer dem Mathe/String-Problem.
    ----------

    BugFix :
    Mit den If-Statements habe ich nun ein bisschen rumgespielt und kann wirklich nicht behaupten, daß eine Version davon wesentlich schneller wäre.
    Wobei es bei einem Interpreter schon seltsam wäre, daß es langsamer wäre eine zusammenhängende "Zeile" auszuwerten, als erst festzustellen, daß nach dem Then nichts mehr kommt und dann noch das EndIf suchen.

    -------

    * Neue Optimierungen:
    - Mathematische Funktionen werden so weit wie möglich vorberechnet
    - StringLower/Upper mit konstanten Strings wird komplett ersetzt
    - $a = $a & $b wird zu $a &= $b

    * Korrekturen
    - Fehler beim Ersetzen der Globalen Constanten behoben

  • Bei den L-Fraktalen fehlt unten die Schrift und beim SIC2 sind auch noch Fehler enthalten:

    • SIC2_opt.au3(119,44) : ERROR: syntax error (illegal character)
      If $a36 = "y" Then $a3a[1] = $a3a[1] + $a37
    • SIC2_opt.au3(119,87) : ERROR: syntax error
      If $a36 = "y" Then $a3a[1] = $a3a[1] + $a37
      If $a36 = "h" Or $a36 = "n" Or $a36 = "s" Then
    • SIC2_opt.au3(133,1) : ERROR: syntax error
      EndIf
    • SIC2_opt.au3(98,16) : ERROR: _g_(): undefined function.
      If Not _g_($a38)
      ~~~~~~~~~~~~~~~^
      SIC2_opt.au3(102,21) : ERROR: _h_(): undefined function.
      _h_($a38, $a3a, $a39)
      ~~~~~~~~~~~~~~~~~~~~^
      SIC2_opt.au3(105,37) : ERROR: _i_(): undefined function.
      $a3b = _i_($a3a[1], $a3a[2], $a3a[3])
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
      SIC2_opt.au3(106,36) : ERROR: _j_(): undefined function.
      _j_($a3b, $a3a[1], $a3a[2], $a3a[3])
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
      SIC2_opt.au3(120,37) : ERROR: _m_(): undefined function.
      $a3c = _m_($a39[1], $a39[2], $a39[3])
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
      SIC2_opt.au3(132,43) : ERROR: _l_(): undefined function.
      _l_($a3c * 1000, $a39[1], $a39[2], $a39[3])
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^


    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Bei SIC2 habe ich die Fehler auch - aber nur wenn ich die Datei nicht als UTF-8 abspeichere. Mache ich das, kommen nur noch Warnungen über unbenutzte Variablen und ein paar DIMs:

    Spoiler anzeigen

    An welcher Stelle in Fractals wird denn die Schrift gesetzt? Der verkürzte Quellcode ist leider etwas schwierig nachzuvollziehen. Schönes Programm übrigends! Gäbe es da evtl. die Möglichkeit für eine "Pause" Taste, damit man ein "Foto" machen kann? Oder vielleicht, daß man jedes Bild einfach speichert?