Cinder open source di Facebook, un fork di CPython utilizzato da Instagram

Facebook ha pubblicato il codice sorgente di Project Cinder, un fork di CPython 3.8.5, la principale implementazione di riferimento del linguaggio di programmazione Python. Cinder viene utilizzato nell'infrastruttura di produzione di Facebook per alimentare Instagram e include ottimizzazioni per migliorare le prestazioni.

Il codice viene pubblicato per discutere la possibilità di trasferire le ottimizzazioni preparate al framework principale CPython e per aiutare altri progetti coinvolti nel miglioramento delle prestazioni di CPython. Facebook non intende supportare Cinder sotto forma di un progetto open source separato e il codice viene presentato nella forma in cui viene utilizzato nell'infrastruttura dell'azienda, senza ulteriore analisi e documentazione. Inoltre, non cercano di promuovere Cinder come alternativa a CPython: l'obiettivo principale dello sviluppo è il desiderio di migliorare CPython stesso.

Il codice Cinder è considerato abbastanza affidabile e testato in ambienti di produzione, ma se vengono identificati problemi dovrai risolverli da solo, poiché Facebook non garantisce che risponderà a messaggi di errore esterni e richieste pull. Allo stesso tempo, Facebook non esclude una cooperazione costruttiva con la comunità ed è pronto a discutere idee su come rendere Cinder ancora più veloce o su come accelerare il trasferimento delle modifiche preparate alla parte principale di CPython.

Principali ottimizzazioni implementate in Cinder:

  • Caching in linea del bytecode (“bytecode shadow”). L'essenza del metodo è identificare le situazioni in cui viene eseguito un tipico codice operativo che può essere ottimizzato e sostituire dinamicamente tale codice operativo con opzioni specializzate più veloci (ad esempio, sostituendo le funzioni richiamate di frequente).
  • Valutazione coroutine desiderosa. Per le chiamate di funzioni asincrone elaborate immediatamente (await non dà come risultato un'attesa e la funzione raggiunge prima l'istruzione return), il risultato di tali funzioni viene sostituito direttamente senza creare una coroutine o coinvolgere un ciclo di eventi. Nel codice di Facebook che utilizza pesantemente async/await, l'ottimizzazione comporta un aumento della velocità di circa il 5%.
  • Compilazione JIT selettiva a livello di singoli metodi e funzioni (metodo alla volta). Abilitato tramite l'opzione "-X jit" o la variabile d'ambiente PYTHONJIT=1 e consente di accelerare l'esecuzione di molti test delle prestazioni di 1.5-4 volte. Poiché la compilazione JIT è rilevante solo per le funzioni eseguite di frequente, non è consigliabile utilizzarla per funzioni utilizzate raramente, il cui sovraccarico di compilazione può solo rallentare l'esecuzione del programma.

    Tramite l'opzione “-X jit-list-file=/path/to/jitlist.txt” o la variabile d'ambiente “PYTHONJITLISTFILE=/path/to/jitlist.txt” è possibile specificare un file con un elenco di funzioni per cui JIT può essere utilizzato (formato del percorso .to.module:funcname o path.to.module:ClassName.method_name). L'elenco delle funzioni per le quali JIT deve essere abilitato può essere determinato in base ai risultati della profilazione. In futuro, è previsto il supporto per la compilazione JIT dinamica sulla base dell'analisi interna della frequenza delle chiamate di funzione, ma tenendo conto delle specificità dei processi di avvio su Instagram, la compilazione JIT è adatta anche per Facebook nella fase iniziale.

    JIT converte innanzitutto il bytecode Python in una rappresentazione intermedia di alto livello (HIR), che è abbastanza vicina al bytecode Python, ma è progettata per utilizzare una macchina virtuale basata su registri anziché una basata su stack e utilizza anche informazioni sul tipo e ulteriori dettagli critici per le prestazioni (come il conteggio dei riferimenti). L'HIR viene quindi convertito nel formato SSA (assegnazione singola statica) e passa attraverso fasi di ottimizzazione che tengono conto dei risultati del conteggio dei riferimenti e dei dati sul consumo di memoria. Di conseguenza, viene generata una rappresentazione intermedia di basso livello (LIR), vicina al linguaggio assembly. Dopo un'altra fase di ottimizzazioni basate su LIR, le istruzioni di assemblaggio vengono generate utilizzando la libreria asmjit.

  • Modalità rigorosa per i moduli. La funzionalità include tre componenti: Tipo StrictModule. Un analizzatore statico in grado di determinare che l'esecuzione di un modulo non ha alcun impatto sul codice esterno a quel modulo. Un caricatore di moduli che determina che i moduli sono in modalità rigorosa (il codice specifica "import __strict__"), controlla l'assenza di intersezioni con altri moduli e carica i moduli rigorosi in sys.modules come oggetto StrictModule.
  • Static Python è un compilatore di bytecode sperimentale che utilizza annotazioni di tipo per generare bytecode specifici del tipo che vengono eseguiti più velocemente grazie alla compilazione JIT. In alcuni test, la combinazione di Static Python e JIT dimostra miglioramenti delle prestazioni fino a 7 volte rispetto a CPython standard. In molte situazioni, si stima che i risultati siano vicini all'utilizzo dei compilatori MyPyC e Cython.

Fonte: opennet.ru

Aggiungi un commento