Primerjalni preizkusi
Phasis je pri obremenitvah JavaScript, omejenih s pošiljanjem, približno dva velikostna reda počasnejši od V8. Ta zgornja meja je neizogiben strošek tolmača, ki gostuje v PHP, v primerjavi z izvornim prevajalnikom JIT. Vprašanje za tistega, ki vgrajuje tolmač, ni »kako se primerja z V8«, temveč »ali je dovolj hiter za moje potrebe«. Za večino primerov vgradnje je odgovor pritrdilen.
Kdaj omejitev ni pomembna
- Predloge — upodobitev običajne strani v slogu SSR traja precej manj kot 10 ms.
- Pravila preverjanja — preverjanje obrazca z uporabniško določenim JS se konča v mikrosekundah.
- Pretvorbe podatkov —
array.map(transform)nad več sto elementi se zaključi v nekaj deset milisekundah. - Peskovniki za izvajanje — kratki skripti, ki jih poda uporabnik, ob omejitvi gostitelja na 1 sekundo pustijo veliko časovne rezerve.
Kdaj je omejitev pomembna
- Računsko zahtevne notranje zanke — obdelava slik, redukcije velikih polj, simulacije. Računsko delo prenesite v izvorno knjižnico PHP in jo izpostavite kot funkcijo gostitelja.
- Animacija v realnem času — vse, kar poganja 60 fps. To JS sodi v odjemalca (brskalnik, izvorna aplikacija), ne v vdelani pogon.
- JS ponovne implementacije računsko zahtevnih algoritmov — kriptografija, stiskanje, razčlenjevanje. PHP ima izvorne ustreznice, ki so 1000× hitrejše; uporabite jih.
Ustrezen miselni model: Phasis je povezovalni sloj za logiko v obliki JS, vdelano v aplikacije v obliki PHP. Gostitelj PHP skrbi za računanje, sloj JS pa za konfiguracijo, razvejanje in manjše pretvorbe.
Zaradi česa je pogon hiter (v primerjavi z naivnim sprehajalnikom drevesa)
- Navidezni stroj z bajtno kodo — večina vročih dispečerskih klicev poteka prek preklopa za operacijske kode v
VM::execute, ne prek AST-ja. - Po meri izdelan sklad klicev — vsak klic JS ohrani stanje znotraj
VM::executein shrani okvir klicatelja v področje; za vsak klic JS ni novega okvira PHP. Glejte Navidezni stroj z bajtno kodo § Sklad klicev po meri. - Vgrajeni predpomnilniki — enomodni predpomnilnik za posamezni PC omogoča, da branje metode prototipa na primerku (oblika
c.method()) preskoči sprehod po verigi prototipov. - Generatorji s posnetki okvirov — izvajanje preprostih teles generatorjev se prekine tako, da se stanje dispečiranja shrani v objekt na kopici, namesto da bi prečkalo vlakno PHP.
- Transpiler JsToPhp — telesa, ki intenzivno uporabljajo števila ali lokalne spremenljivke (vključno z branji
obj.method(),new Ctor()inthis.member), se prevedejo v zaprtja PHP, ki jih sledilni JIT v PHP 8.5 prevede v izvorno strojno kodo. - Predpomnilnik JSON.stringify —
JSON.stringify(o)predpomni svoj izhodni rezultat na vhodnem objektu s prehodnim razveljavljanjem različic, kar pospeši idiom globokega kloniranjaJSON.parse(JSON.stringify(o)).
Merjenje lastne delovne obremenitve
php bench/run.php
S tem zaženete zbirko mikroprimerjalnih testov, priloženo pod bench/microbench.js — nekaj sintetičnih delovnih obremenitev (aritmetika v zankah, rekurzivne funkcije, ustvarjanje objektov, klici metod prototipov, dodajanje v polje, povratno pretvarjanje JSON itd.) — in izpišete srednji stenski čas za vsak test. Uporabno za osnovni pregled; trenutne številke se ob vsakem izvajanju primerjalnih testov CI zapišejo v BENCH.md.
Za svojo kodo lahko uporabite poljubni skript:
php -d xdebug.mode=off bench/run.php path/to/your-script.js
Za profiliranje na ravni PHP profiler iz Xdebug deluje z Phasis enako kot s katero koli drugo aplikacijo PHP. Zaženite skript z xdebug.mode=profile in preglejte izhod cachegrind, da ugotovite, kateri razredi Phasis\ prevladujejo.
Načrt razvoja
Kaj bi najbolj zmanjšalo vrzel do V8, razvrščeno približno po izvedljivosti:
- Polimorfni vgrajeni predpomnilniki — omogočite, da eno mesto klica
LOAD_MEMBERshrani 2–4 predpomnjene oblike, preden preklopi na počasno dispečiranje. Pomaga pri kodi, ki obdeluje heterogene prejemnike. yield*in try-with-yield na poti generatorjev s posnetki okvirov — te oblike se trenutno preusmerijo na sprehajalnik dreves, podprt z vlakni. Preden bodo primerne za posnetke, je treba izrecno obravnavati stanje (posredovanje iteratorja delegata, ohranitev sklada obravnavalnikov med prekinitvijo).- Asinhroni generatorji in
awaitna posnetkih — specifikacija združuje prekinitve generatorjev z vrsto mikroopravil. Ko telo bajtne kode podpira oboje,yieldinawait, bodo tudi asinhroni generatorji primerni za posnetke. - Sklepanje o vrstah parametrov v JsToPhp — parametri funkcij so privzeto številskega tipa, zato
function (obj) { obj.method() }prekine prevajanje. Sklepanje o objektnih vrstah parametrov na podlagi njihove uporabe v telesu bi omogočilo klice metod na argumentih funkcije, ne da bi bilo treba prejemnik lokalno ustvariti znew. - Neposredno ustvarjanje opkod v opcache — preskočite korak
eval()v JsToPhp tako, da neposredno zapišete opkode v obliki opcache. To je največji poseg; druge izboljšave je mogoče izvesti v obstoječi arhitekturi.
Nobena od teh izboljšav ni potrebna za vdelane delovne obremenitve, ki jih podpira Phasis.