Συγκριτικές μετρήσεις
Το Phasis είναι περίπου δύο τάξεις μεγέθους πιο αργό από το V8 σε φόρτους εργασίας JavaScript που περιορίζονται από τη διανομή. Αυτό το όριο είναι το αναπόφευκτο κόστος ενός διερμηνευτή που φιλοξενείται στο PHP σε σύγκριση με έναν εγγενή μεταγλωττιστή JIT. Το ερώτημα για όποιον το ενσωματώνει δεν είναι «πώς συγκρίνεται με το V8», αλλά «είναι αρκετά γρήγορο για αυτό που κάνω;». Για τους περισσότερους φόρτους εργασίας ενσωμάτωσης, η απάντηση είναι ναι.
Πότε δεν έχει σημασία το όριο
- Δημιουργία προτύπων — απόδοση τυπικής σελίδας τύπου SSR σε πολύ λιγότερο από 10 ms.
- Κανόνες επικύρωσης — το JS που παρέχει ο χρήστης για την επικύρωση φορμών εκτελείται σε μικροδευτερόλεπτα.
- Μετασχηματισμοί δεδομένων — το
array.map(transform)σε εκατοντάδες στοιχεία ολοκληρώνεται σε δεκάδες χιλιοστά του δευτερολέπτου. - Εκτελεστές σε sandbox — σύντομα σενάρια που παρέχει ο χρήστης, με όριο 1 δευτερολέπτου από τον κεντρικό υπολογιστή, αφήνουν άφθονο περιθώριο.
Πότε έχει σημασία το όριο
- Εσωτερικοί βρόχοι με απαιτητικούς υπολογισμούς — επεξεργασία εικόνας, μειώσεις μεγάλων πινάκων, προσομοιώσεις. Μεταφέρετε τους υπολογισμούς σε μια εγγενή βιβλιοθήκη PHP και εκθέστε την ως συνάρτηση κεντρικού υπολογιστή.
- Κινούμενα γραφικά σε πραγματικό χρόνο — οτιδήποτε οδηγεί σε 60 fps. Αυτό το JS ανήκει στον πελάτη (πρόγραμμα περιήγησης, εγγενής εφαρμογή), όχι στην ενσωματωμένη μηχανή.
- Επαναϋλοποιήσεις σε JS αλγορίθμων με υψηλό υπολογιστικό κόστος — κρυπτογραφία, συμπίεση, ανάλυση. Το PHP διαθέτει εγγενείς αντίστοιχες υλοποιήσεις που είναι 1000× ταχύτερες· χρησιμοποιήστε τες.
Το σωστό νοητικό μοντέλο: το Phasis είναι ένα επίπεδο συνδετικής λογικής για λογική μορφής JS ενσωματωμένη σε εφαρμογές μορφής PHP. Ο κεντρικός υπολογιστής PHP χειρίζεται τους υπολογισμούς· το επίπεδο JS χειρίζεται τη διαμόρφωση, τις διακλαδώσεις και τους μικρούς μετασχηματισμούς.
Τι κάνει τη μηχανή γρήγορη (σε σχέση με έναν απλό περιπατητή δέντρου)
- Εικονική μηχανή bytecode — το μεγαλύτερο μέρος των συχνών διανομών εκτελείται μέσω του διακόπτη κωδικών λειτουργίας του
VM::execute, όχι μέσω του AST. - Προσαρμοσμένη στοίβα κλήσεων — κάθε κλήση JS διατηρεί την κατάσταση στο
VM::executeκαι αποθηκεύει το πλαίσιο του καλούντος σε μια δεξαμενή· δεν δημιουργείται νέο πλαίσιο PHP για κάθε κλήση JS. Δείτε Εικονική μηχανή bytecode § Προσαρμοσμένη στοίβα κλήσεων. - Προσωρινές μνήμες inline — μια μονομορφική μνήμη cache ανά PC επιτρέπει στις αναγνώσεις μεθόδων πρωτοτύπου σε στιγμιότυπο (το σχήμα
c.method()) να παραλείπουν τη διάσχιση της αλυσίδας πρωτοτύπων. - Γεννήτριες στιγμιότυπων πλαισίου — τα απλά σώματα γεννητριών αναστέλλονται καταγράφοντας την κατάσταση διανομής σε αντικείμενο στη μνήμη σωρού, αντί να περνούν από Fiber του PHP.
- Μεταγλωττιστής JsToPhp — σώματα με πολλή αριθμητική ή χρήση τοπικών μεταβλητών (συμπεριλαμβανομένων αναγνώσεων
obj.method(),new Ctor()καιthis.member) μεταγλωττίζονται σε κλεισίματα PHP, τα οποία το tracing JIT της έκδοσης 8.5 του PHP μετατρέπει σε εγγενή κώδικα μηχανής. - Μνήμη cache JSON.stringify — το
JSON.stringify(o)αποθηκεύει την έξοδό του στο αντικείμενο εισόδου με μεταβατική ακύρωση εκδόσεων, επιταχύνοντας το ιδίωμα βαθιάς κλωνοποίησηςJSON.parse(JSON.stringify(o)).
Μέτρηση του δικού σας φόρτου εργασίας
php bench/run.php
Αυτό εκτελεί τη σουίτα μικρομετρήσεων που περιλαμβάνεται στο bench/microbench.js — μερικούς συνθετικούς φόρτους εργασίας (αριθμητική σε βρόχους, αναδρομικές συναρτήσεις, δημιουργία αντικειμένων, κλήσεις μεθόδων πρωτοτύπου, προσθήκη στοιχείων σε πίνακα, αμφίδρομη μετατροπή JSON κ.λπ.) και εκτυπώνει τη διάμεση διάρκεια τοίχου ανά δοκιμή. Χρήσιμος έλεγχος λογικής· οι τρέχουσες μετρήσεις υποβάλλονται στο BENCH.md σε κάθε εκτέλεση μετρήσεων CI.
Για τον δικό σας κώδικα, αντικαταστήστε οποιοδήποτε σενάριο:
php -d xdebug.mode=off bench/run.php path/to/your-script.js
Για δημιουργία προφίλ σε επίπεδο PHP, το πρόγραμμα δημιουργίας προφίλ του Xdebug λειτουργεί με το Phasis ακριβώς όπως με κάθε άλλη εφαρμογή PHP. Εκτελέστε ένα σενάριο στο xdebug.mode=profile και εξετάστε την έξοδο cachegrind για να δείτε ποιες κλάσεις Phasis\ κυριαρχούν.
Οδικός χάρτης
Τι θα μείωνε περισσότερο τη διαφορά του V8, με κατά προσέγγιση σειρά ευκολίας υλοποίησης:
- Πολυμορφικές inline caches — επιτρέπουν σε ένα σημείο κλήσης
LOAD_MEMBERνα διατηρεί 2-4 αποθηκευμένα σχήματα πριν καταφύγει σε αργή αποστολή. Βοηθούν κώδικα που επεξεργάζεται ετερογενείς δέκτες. yield*και try-with-yield στη διαδρομή generator με στιγμιότυπο πλαισίου — αυτά τα σχήματα κατευθύνονται προς το δέντρο-περιπατητή που βασίζεται σε Fiber. Για να είναι ασφαλή για στιγμιότυπα, χρειάζεται ρητός χειρισμός με μηχανή καταστάσεων (προώθηση delegate-iterator, διατήρηση της στοίβας χειριστών κατά την αναστολή).- Async generators και
awaitσε στιγμιότυπα — η προδιαγραφή συνδυάζει την αναστολή generator με την ουρά microtask. Μόλις το σώμα bytecode υποστηρίζει τόσο τοyieldόσο και τοawait, τα async generators θα είναι επίσης συμβατά με στιγμιότυπα. - Συναγωγή τύπων παραμέτρων στο JsToPhp — οι παράμετροι συναρτήσεων έχουν προεπιλεγμένα αριθμητικό τύπο, οπότε το
function (obj) { obj.method() }διακόπτει τη μεταγλώττιση. Η συναγωγή παραμέτρων τύπου object από τον τρόπο χρήσης τους στο σώμα θα επέτρεπε κλήσεις μεθόδων σε ορίσματα συναρτήσεων, χωρίς να απαιτείται η τοπική κατασκευή του δέκτη μέσωnew. - Άμεση έκδοση opcache — παράκαμψη του βήματος
eval()του JsToPhp, με απευθείας εγγραφή opcodes σε μορφή opcache. Είναι το πιο απαιτητικό στοιχείο· τα υπόλοιπα μπορούν να υλοποιηθούν στην υπάρχουσα αρχιτεκτονική.
Τίποτα από αυτά δεν είναι απαραίτητο για τους φόρτους ενσωμάτωσης που στοχεύει το Phasis.