Open-Source-Cinder von Facebook, ein Fork von CPython, der von Instagram verwendet wird

Facebook hat den Quellcode für Project Cinder veröffentlicht, einen Fork von CPython 3.8.5, der wichtigsten Referenzimplementierung der Programmiersprache Python. Cinder wird in der Produktionsinfrastruktur von Facebook zur Stromversorgung von Instagram verwendet und umfasst Optimierungen zur Verbesserung der Leistung.

Der Code wird veröffentlicht, um die Möglichkeit der Portierung der vorbereiteten Optimierungen auf das Haupt-CPython-Framework zu diskutieren und anderen Projekten zu helfen, die an der Verbesserung der CPython-Leistung beteiligt sind. Facebook beabsichtigt nicht, Cinder in Form eines separaten Open-Source-Projekts zu unterstützen, und der Code wird in der Form präsentiert, in der er in der Infrastruktur des Unternehmens verwendet wird, ohne zusätzliche Durchkämmung und Dokumentation. Sie versuchen auch nicht, Cinder als Alternative zu CPython zu bewerben – das Hauptziel der Entwicklung ist der Wunsch, CPython selbst zu verbessern.

Der Cinder-Code gilt als recht zuverlässig und wurde in Produktionsumgebungen getestet. Wenn jedoch Probleme festgestellt werden, müssen Sie diese selbst lösen, da Facebook nicht garantiert, dass er auf externe Fehlermeldungen und Pull-Anfragen reagiert. Gleichzeitig schließt Facebook eine konstruktive Zusammenarbeit mit der Community nicht aus und ist bereit, Ideen zu diskutieren, wie man Cinder noch schneller machen oder die Übertragung vorbereiteter Änderungen in den Hauptteil von CPython beschleunigen kann.

Wichtigste in Cinder implementierte Optimierungen:

  • Inline-Caching von Bytecode („Schattenbytecode“). Der Kern der Methode besteht darin, Situationen zu identifizieren, in denen ein typischer Opcode ausgeführt wird, der optimiert werden kann, und einen solchen Opcode dynamisch durch schnellere Spezialoptionen zu ersetzen (z. B. das Ersetzen häufig aufgerufener Funktionen).
  • Eifrige Coroutine-Auswertung. Bei asynchronen Funktionsaufrufen, die sofort verarbeitet werden (Warten führt nicht zu einem Warten und die Funktion erreicht die Return-Anweisung früher), wird das Ergebnis solcher Funktionen direkt ersetzt, ohne dass eine Coroutine erstellt oder eine Ereignisschleife beteiligt ist. In Facebook-Code, der häufig Async/Await verwendet, führt die Optimierung zu einer Geschwindigkeitssteigerung von etwa 5 %.
  • Selektive JIT-Kompilierung auf der Ebene einzelner Methoden und Funktionen (method-at-a-time). Wird über die Option „-X jit“ oder die Umgebungsvariable PYTHONJIT=1 aktiviert und ermöglicht Ihnen, die Ausführung vieler Leistungstests um das 1.5- bis 4-fache zu beschleunigen. Da die JIT-Kompilierung nur für häufig ausgeführte Funktionen relevant ist, ist es nicht ratsam, sie für selten verwendete Funktionen zu verwenden, deren Kompilierungsaufwand die Programmausführung nur verlangsamen kann.

    Über die Option „-X jit-list-file=/path/to/jitlist.txt“ oder die Umgebungsvariable „PYTHONJITLISTFILE=/path/to/jitlist.txt“ können Sie eine Datei mit einer Liste von Funktionen angeben, für die JIT verwendet werden soll kann verwendet werden (Pfadformat .to.module:funcname oder path.to.module:ClassName.method_name). Die Liste der Funktionen, für die JIT aktiviert werden sollte, kann basierend auf den Profilerstellungsergebnissen bestimmt werden. Zukünftig wird die Unterstützung der dynamischen JIT-Kompilierung auf der Grundlage einer internen Analyse der Häufigkeit von Funktionsaufrufen erwartet, aber unter Berücksichtigung der Besonderheiten der Startprozesse auf Instagram ist die JIT-Kompilierung in der Anfangsphase auch für Facebook geeignet.

    JIT konvertiert zunächst den Python-Bytecode in eine High-Level-Intermediate-Repräsentation (HIR), die dem Python-Bytecode ziemlich nahe kommt, aber für die Verwendung einer registerbasierten virtuellen Maschine anstelle einer stapelbasierten Maschine konzipiert ist und außerdem Typinformationen und weitere Informationen verwendet leistungskritische Details (z. B. Referenzzählung). Anschließend wird der HIR in die SSA-Form (Static Single Assignment) konvertiert und durchläuft Optimierungsschritte, die Referenzzählergebnisse und Speicherverbrauchsdaten berücksichtigen. Als Ergebnis wird eine Low-Level-Zwischendarstellung (LIR) generiert, die der Assemblersprache ähnelt. Nach einer weiteren Phase LIR-basierter Optimierungen werden Montageanweisungen mithilfe der asmjit-Bibliothek generiert.

  • Strikter Modus für Module. Die Funktionalität umfasst drei Komponenten: Typ StrictModule. Ein statischer Analysator, der feststellen kann, dass die Ausführung eines Moduls keine Auswirkungen auf Code außerhalb dieses Moduls hat. Ein Modullader, der feststellt, dass sich die Module im strikten Modus befinden (der Code gibt „import __strict__“ an), prüft, ob es keine Schnittmengen mit anderen Modulen gibt, und lädt strikte Module als StrictModule-Objekt in sys.modules.
  • Static Python ist ein experimenteller Bytecode-Compiler, der Typanmerkungen verwendet, um typspezifischen Bytecode zu generieren, der dank JIT-Kompilierung schneller ausgeführt wird. In einigen Tests zeigt die Kombination von Static Python und JIT bis zu siebenfache Leistungsverbesserungen im Vergleich zu Standard-CPython. In vielen Situationen wird geschätzt, dass die Ergebnisse der Verwendung der MyPyC- und Cython-Compiler nahe kommen.

Source: opennet.ru

Kommentar hinzufügen