Das Rätsel um –enable-inline-optimization

Wenn man im Internet Tipps sucht, wie man PHP möglichst performant kompiliert, liest man häufig, dass man die Option –enable-inline-optimization einsetzen sollte. Sie aktiviertso genannte Inline Optimizations. Doch worum handelt es sich dabei eigentlich? Sicherlich reicht es oft zu wissen, DASS es damit schneller geht und nicht WARUM. Trotzdem möchte ich einmal die Hintergründe hinter dieser Compiler-Option erklären.

Inline Optimizations oder auch Inline Expansion ist eine Idee, die vom Prinzip her mit meinem Beitrag zu iterativer Programmierung in PHP korresponsiert. Dort habe ich gezeigt, wie man statt einer Funktion den gleichen Nutzen mithilfe der iterativen Programmierung erreichen kann. Wenn es allerdings nicht wirklich um jedes Quentchen Speed geht, programmiert bestimmt niemand heute noch iterativ, weil es einfach übersichtlich wird. Und genau da setzen die Inline-Optimierungen an.
Beim Kompilieren der PHP-Scripte werden die Funktionen, die der PHP-Interpreter als inline-fähig ansieht, so umgeschrieben, dass eine iterative Variante daraus entsteht. Das System dahinter ist unter Comparing Code Coverage and Model Coverage (Punkt 8) recht gut beschrieben.
Ich erläre es anhand des Beispiels der englischsprachigen Wikipedia, habe es aber in PHP umgeschrieben, damit jeder versteht, was gemeint ist.

// diese Funktion wird per inline optimization optimiert
function pred($x) {
    if ($x == 0)
       return 0;
    else
       return $x - 1;
}
 
// diese Funktion rufen wir auf
function f($y) {
    return pred($y) + pred(0) + pred($y+1);
}

Soweit alles ganz normal: 2 Funktionen. Eine davon wird aus dem Hauptprogramm aufgerufen (Funktion f) und diese aufgerufene Funktion ruft dann nochmal eine andere auf (Funktion pred). Nachdem der Compiler die Funktion f kompiliert hat (und die inline optimations angewandt hat), sieht die Funktion so aus:

function f($y) {
    $temp = 0;
    if ($y   == 0) $temp += 0; else $temp += $y - 1;
    if (0   == 0) $temp += 0; else $temp += 0 - 1;
    if ($y+1 == 0) $temp += 0; else $temp += ($y + 1) - 1;
    return temp;
}

Bitte die Funktion kurz wirken lassen und feststellen, dass es sich tatsächlich um eine äquivalente Umsetzung handelt. Die Funktion pred wird dadurch entfernt, da ihre Funktionalität nun iterativ in die Funktion f integriert wurde.

Was ist nun dadurch gewonnen? Jede Menge! Wir sparen Performance für das 3-malige Aufrufen und „returnen“ der pred-Funktion. Natürlich ist der Code nun etwas länger, aber der Compiler ist noch nicht ganz fertig. Nun können die Vorteile erst richtig ausgespielt werden 😉
Worüber Sie sich bestimmt schon gewundert haben, ist, wozu Befehle wie $temp += 0; gut sein sollen. Berechtigte Frage! Diese Befehle tun nix und können deshalb entfernt werden.
Außerdem ist

  • 0==0 immer true, deshalb kann die if-Verzweigung entfernt werden und nur der true-Zweig wird noch benötigt.
  • $y+1==0 äquivalent zu $y==-1
  • ($y + 1) – 1 ist einfach $y
  • $y und ($y+1) können nicht beide gleichzeitig 0 sein, deshalb kann man eine if-else-Verzweigung mit 3 Fällen aufbauen.

Es entsteht also dieser Code nach der weiteren Optimierung:

function f($y) {
    if ($y == 0)
        return $y;            /* or return 0 */
    else if ($y == -1)
        return $y - 1;        /* or return -2 */
    else
        return $y + $y - 1;
}

Dieser Code ist dann in etwa genau so lang wie unser Ausgangscode (nur gültig für dieses Beispiel) mit den 2 Funktionen, allerdings wesentlich einfacher zu verarbeiten.

Wen das technische Konzept nicht weiter interessiert, darf den näcshten Absatz überspringen.
Einige Probleme stehen den Vorteilen allerdings ebenfalls gegenüber:
Es entsteht (meistens) mehr Code durch Inline Optimierung und dieser Code muss natürlich in den Speicher geladen werden. Auf Servern ist dies sicherlich zu vernachlässigen, da diese über genug Speicher verfügen. Aber beispielsweise bei Embedded Systems (wo natürlich keinesfalls PHP eingesetzt wird, ich aber ja hier hauptsächlich das Konzept erklären möchte) könnte es zu Problemen kommen, da der Speicher dort sehr begrenzt ist.
Ein weiteres Problem könnte sein, dass der nun größere Code nicht mehr komplett in den Cache des Prozessors passt und somit die Seitenfehlerrate steigt und ausdem langsameren RAM nachgeladen werden müsste. Ebenso könnten durch zusätzlich eingesetzte Variablen die Register nicht ausreichen, auch dann muss nachgeladen werden.
Wenn der Code zu groß wird, könnte der verfügbare RAM nicht ausreichen und es kommt zum Thrashing-Effekt. Das heißt die Seitenfehlerrate ist so hoch, dass ständig Seiten im Speicher ausgetauscht werden müssen und dann wird die Festplatte der Flaschenhals des ganzen Systems.

Der PHP-Compiler sowie das zugrunde liegende C trägt aber Sorge dafür, dass diesen Problemen entgegengewirkt werden kann, denn im Prinzip bezieht sich alles auf die RAM-Größe und die kann ja problemlos vom Compiler ermittelt werden.

Es sei noch gesagt, dass die Option –enable-inline-optimization erst ab PHP Version 4.2 eingesetzt werden sollte, davor gab es Fehler. Außerdem ist nach aktuellem Stand der Dinge der Einsatz auf 64-Bit Prozessoren ebenfalls zu vermeiden.

Ich denke man kann am Code sehen, dass Inline Optimizations ein sinnvolles Konstrukt sind und ich hoffe, dass deutlich geworden ist, weshalb sie mehr Geschwindigkeit bringen. Dass ich nur englischsprachige Quellen angegeben habe, liegt nicht daran, dass ich Ihre Kenntnisse auf die Probe stellen möchte, sondern vielmehr daran, dass ich keine deutschen Texte darüber finden konnte. Überall steht nur, dass man diese Option für mehr Performance benutzen soll, aber nicht, was sie genau tut. Genau darum hoffe ich mit diesem Beitrag etwas Licht ins Dunkel gebracht zu haben.
Wenn in Zukunft mehr solch technische Beiträge erscheinen sollen, würde ich mich über ein kleines Feedback im PHP Performance Forum freuen.

Jan hat 158 Beiträge geschrieben

5 Kommentare zu “Das Rätsel um –enable-inline-optimization

  1. Tim sagt:

    Ich habe diesen Blog erst vor Kurzem entdeckt. Als PHP Entwickler muss man ständig seine Scripts nach Performance Schwächen untersuchen. Dieses Blog hilft mir sehr gut, um mehr über Steigerung der Effizienz der Scripts zu erfahren.
    Der Artikel fand ich sehr informativ und gut erklärt.
    Kann man den „konvertierten“ Code ausgeben lassen und dann durch den vorhandenen Code ersetzen, sodass PHP nicht jedes Mal ihn neu zu optimieren? Kann man durch vielleicht durch Caching (MMCache, eAccelerator, etc.) bessere Ergebnisse erzielen, als mit der Inline Optimization oder ist es sogar möglich beides parallel zu verwenden, sodass zweifache Optimierung stattfinden kann?
    Ich würde mich künftig über weitere technische Beiträge freuen!

    Vielen Dank
    Tim

  2. meeero sagt:

    woher hast du denn die information, dass es nicht auf 64bit-systemen eingesetzt werden sollte? genau das habe ich nämlich vor…

  3. admin sagt:

    Puuh, weiß gar nicht mehr, von welcher Quelle ich das hatte. Google spuckt aber beispielsweise unter http://www.vbulletin.com/forum/archive/index.php/t-37978.html aus:
    „PHP disables inline optimizations by default (due to the GCC compiler failing when the target is one of the new 64 bit processors), but inline optimizations result in a two to five fold inccrease in speed. If you’re running on a 64 bit processor, remove `–enable-inline-optimization“

  4. Someone sagt:

    Ich weiß, dass dieser Artikel bereits sehr alt ist. Trotzdem bin ich zufällig bei einer Suche im Internet darüber gestolpert und habe mich gewundert was sich wohl hinter phpperformance.de verbirgt. Wie es scheint, Unwahrheiten.

    –enable-inline-optimization ist eine Option die an gcc übergeben werden kann um die C-Executable zu optimieren und hat nichts, aber auch gar nichts damit zu tun wie der PHP-Code interpretiert oder behandelt wird. Das Einzige was passiert ist, dass in der C-PHP-Executable Funktionen inlined werden und diese dadurch vielleicht etwas schneller ist.

Eine Antwort schreiben

Ihre E-Mail-Adresse wird nicht veröffentlicht. Benötigte Felder sind markiert mit *

You may use these HTML tags and attributes: <a href=""> <blockquote cite=""> <pre lang=""> <b> <strong> <i> <em>