Našumo testai
Phasis yra maždaug dviem dydžio eilėmis lėtesnis už V8, kai našumą riboja JavaScript iškvietimų apdorojimas. Tokias ribas lemia pačios PHP aplinkoje veikiančio interpretatoriaus sąnaudos, palyginti su savuoju JIT kompiliatoriumi. Įterpiančiam įrankį svarbu ne „kaip tai atrodo, palyginti su V8“, o „ar to greičio pakanka mano užduotims“. Daugumoje įterpimo atvejų atsakymas – taip.
Kai šios ribos nesvarbios
- Šablonų apdorojimas — įprasto puslapio SSR tipo atvaizdavimas gerokai greičiau nei per 10 ms.
- Tikrinimo taisyklės — naudotojo pateikto JS formų tikrinimas baigiamas per mikrosekundes.
- Duomenų transformacijos —
array.map(transform)su šimtais elementų apdorojamas per keliasdešimt milisekundžių. - Smėliadėžės vykdyklės — trumpiems naudotojo pateiktiems scenarijams, kai pagrindinė aplinka riboja laiką iki 1 sekundės, lieka didelė atsarga.
Kai šios ribos svarbios
- Skaičiavimams imlios vidinės ciklų iteracijos — vaizdų apdorojimas, didelių masyvų redukcija, simuliacijos. Skaičiavimus perkelkite į savąją PHP biblioteką ir pateikite kaip pagrindinės aplinkos funkciją.
- Animacija realiuoju laiku — visa, kas turi veikti 60 fps dažniu. Tokia JS logika turi veikti kliento pusėje (naršyklėje ar savojoje programėlėje), o ne įterptajame variklyje.
- JS įgyvendinti daug skaičiavimų reikalaujantys algoritmai — kriptografija, glaudinimas, analizavimas. PHP turi savųjų atitikmenų, kurie veikia 1000× greičiau; naudokite juos.
Tinkamas mąstymo modelis: Phasis yra jungiamasis sluoksnis, skirtas JS formos logikai, įterptai į PHP formos programas. PHP pagrindinė aplinka atlieka skaičiavimus, o JS sluoksnis tvarko konfigūraciją, šakojimą ir nedideles transformacijas.
Kodėl variklis greitas (palyginti su paprastu medžio vaikščiotuvu)
- Baitkodo VM — dauguma aktyvių iškvietimų apdorojama per
VM::executeoperacijų kodų jungiklį, o ne AST. - Tinkinta iškvietimų steko realizacija — kiekvieno JS iškvietimo būsena laikoma
VM::executeviduje, o iškvietusiojo kadras išsaugomas telkinyje; kiekvienam JS iškvietimui nesukuriamas naujas PHP kadras. Žr. Baitkodo VM § Tinkinta iškvietimų steko realizacija. - Įterptinės podėlio eilutės — kiekvienam PC monomorfinis podėlis leidžia skaitant prototipo metodą egzemplioriuje (
c.method()forma) praleisti prototipų grandinės peržiūrą. - Kadrų momentinių kopijų generatoriai — paprastų generatorių vykdymas pristabdomas užfiksuojant iškvietimų būseną krūvos objekte, užuot perėjus per PHP Fiber.
- JsToPhp transpiliatorius — skaitines operacijas ir vietinius kintamuosius intensyviai naudojančios funkcijos (įskaitant
obj.method(),new Ctor()irthis.memberskaitymus) kompiliuojamos į PHP uždarymus, kuriuos PHP 8.5 sekimo JIT kompiliatorius paverčia savuoju mašininiu kodu. - JSON.stringify podėlis —
JSON.stringify(o)podėlį saugo įvesties objekte ir transityviai jį anuliuoja pakeitus versiją, taip paspartindamas gilaus klonavimo šablonąJSON.parse(JSON.stringify(o)).
Savo darbo krūvio matavimas
php bench/run.php
Tai paleidžia kartu su bench/microbench.js pateikiamą mikrotikrinimų rinkinį — kelis sintetinius darbo krūvius (ciklų aritmetiką, rekursines funkcijas, objektų kūrimą, prototipų metodų iškvietimus, masyvo papildymą, JSON pirmyn ir atgal ir kt.) ir pateikia kiekvieno bandymo medianinį sieninio laiko rodiklį. Naudinga greitam patikrinimui; naujausi skaičiai po kiekvieno CI našumo bandymo įrašomi į BENCH.md.
Savo kodui vietoj jo naudokite bet kurį scenarijų:
php -d xdebug.mode=off bench/run.php path/to/your-script.js
Norint profiliuoti PHP lygmeniu, Xdebug profiliavimo įrankis veikia su Phasis kaip ir su bet kuria kita PHP programa. Paleiskite scenarijų per xdebug.mode=profile ir peržiūrėkite cachegrind išvestį, kad pamatytumėte, kurios Phasis\ klasės dominuoja.
Kūrimo planas
Kas labiausiai sumažintų V8 atsilikimą, apytikriai pagal įgyvendinimo paprastumą:
- Polimorfiniai įterptiniai podėliai — leisti vienai
LOAD_MEMBERiškvietimo vietai išsaugoti 2–4 podėlio formas prieš pereinant prie lėto iškvietimų apdorojimo. Padeda kodui, apdorojančiam skirtingų tipų gavėjus. yield*ir try-with-yield kadrų momentinių kopijų generatorių kelyje — šios formos šiuo metu nukreipiamos į Fiber pagrįstą medžio vaikščiotuvą. Prieš jas galima užfiksuoti kaip momentines kopijas, reikia aiškiai apdoroti būsenų mašiną (deleguotų iteratorių persiuntimą, per sustabdymą išsaugomą apdorojimo steką).- Asinchroniniai generatoriai ir
awaitmomentinėse kopijose — specifikacija susieja generatoriaus sustabdymą su mikroužduočių eile. Kai baitkodo turinys palaikys iryield, irawait, asinchroniniai generatoriai taip pat bus pritaikyti momentinėms kopijoms. - JsToPhp parametrų tipų išvedimas — funkcijų parametrams pagal numatytuosius nustatymus priskiriamas skaitinis tipas, todėl
function (obj) { obj.method() }sustabdo kompiliatorių. Išvedus objektų parametrų tipus pagal tai, kaip jie naudojami funkcijos turinyje, būtų galima kviesti metodus funkcijos argumentams nereikalaujant, kad gavėjas būtų sukurtas vietoje pernew. - Tiesioginis opcache generavimas — praleisti JsToPhp
eval()žingsnį ir tiesiogiai rašyti opcache formato operacijų kodus. Sudėtingiausias punktas; kitus galima įgyvendinti esamoje architektūroje.
Nė vienas iš šių dalykų nėra būtinas darbo krūviams, kuriems įterpti skirtas Phasis.