Suorituskykytestit
Phasis on noin kaksi kertaluokkaa hitaampi kuin V8 dispatch-painotteisissa JavaScript-tehtävissä. Tämä yläraja johtuu väistämättä PHP-ympäristössä toimivan tulkin kustannuksista verrattuna natiiviin JIT-kääntäjään. Moottoria upottavan kehittäjän kysymys ei ole "miten se vertautuu kohteeseen V8" vaan "onko se riittävän nopea siihen, mitä teen". Useimmissa upotuskäyttötapauksissa vastaus on kyllä.
Milloin ylärajalla ei ole väliä
- Mallipohjat — tyypillisen sivun SSR-tyylinen renderöinti vie reilusti alle 10 ms.
- Validointisäännöt — käyttäjän antaman JS-koodin suorittaminen lomakkeen validointia varten kestää mikrosekunteja.
- Tietomuunnokset —
array.map(transform)sadoille kohteille valmistuu kymmenissä millisekunneissa. - Hiekkalaatikkosuorittimet — lyhyet käyttäjän antamat komentosarjat, joiden isäntä rajoittaa suorituksen sekuntiin, jättävät runsaasti suoritusvaraa.
Milloin ylärajalla on väliä
- Laskentaintensiiviset sisäkkäiset silmukat — kuvankäsittely, suurten taulukoiden pelkistykset ja simulaatiot. Siirrä laskenta natiiviin PHP-kirjastoon ja tarjoa se isäntäfunktion kautta.
- Reaaliaikainen animaatio — kaikki, mikä tuottaa 60 fps:n kuvaa. Tällainen JS kuuluu asiakasohjelmaan (selaimeen tai natiivisovellukseen), ei upotettuun moottoriin.
- JS-toteutukset laskentaintensiivisistä algoritmeista — salaus, pakkaus ja jäsentäminen. Kohteessa PHP on natiivivastineita, jotka ovat 1000× nopeampia; käytä niitä.
Sopiva ajattelumalli: Phasis on liimakerros JS-tyyliselle logiikalle, joka on upotettu PHP-tyylisiin sovelluksiin. PHP-isäntä hoitaa laskennan; JS-kerros vastaa määrityksistä, haarautumisesta ja pienistä muunnoksista.
Mikä tekee moottorista nopean (verrattuna yksinkertaiseen puukävelijään)
- Tavukoodikäyttöympäristö — suurin osa kuumien kutsujen käsittelystä kulkee kohteen
VM::executeoperaatiokytkimen kautta AST:n sijaan. - Mukautettu kutsupino — jokainen JS-kutsu säilyttää tilan kohteessa
VM::executeja tallentaa kutsujan kehyksen varantoon; jokaiselle JS-kutsulle ei luoda uutta PHP-kehystä. Katso Tavukoodikäyttöympäristö § Mukautettu kutsupino. - Sisäiset välimuistit — PC-kohtainen monomorfinen välimuisti ohittaa prototyyppiketjun läpikäynnin prototyyppimetodia lukiessa instanssista (
c.method()-muoto). - Kehysvedosgeneraattorit — yksinkertaiset generaattorirungot keskeyttävät toimintansa tallentamalla suoritusyksikön tilan kekoon sen sijaan, että ne ylittäisivät PHP Fiber -rajapinnan.
- JsToPhp-transpilaattori — numeeriset ja paikallismuuttujapainotteiset rungot (mukaan lukien kohteiden
obj.method(),new Ctor()jathis.memberlukemiset) käännetään PHP-sulkeumiksi, jotka kohteen PHP 8.5 jäljityspohjainen JIT-kääntäjä muuntaa natiiviksi konekoodiksi. - JSON.stringify-välimuisti —
JSON.stringify(o)tallentaa tuloksensa syöteolioon ja mitätöi välimuistin transitiivisen versioinnin perusteella, mikä nopeuttaa syväkopiointitapaaJSON.parse(JSON.stringify(o)).
Oman kuorman mittaaminen
php bench/run.php
Tämä suorittaa kohteessa bench/microbench.js toimitetun mikrotestikokonaisuuden — muutamia synteettisiä kuormia (silmukoiden aritmetiikka, rekursiiviset funktiot, olioiden luonti, prototyyppimetodikutsut, taulukon push, JSON-edestakainen muunnos ja niin edelleen) — ja tulostaa testien seinäkelloajan mediaanin. Hyödyllinen järkevyystarkistus; nykyiset tulokset tallennetaan kohteeseen BENCH.md jokaisella CI-benchmark-ajolla.
Voit käyttää omaa koodiasi vaihtamalla tilalle minkä tahansa komentosarjan:
php -d xdebug.mode=off bench/run.php path/to/your-script.js
PHP-tason profilointiin kohteen Xdebug profiloija toimii kohteen Phasis kanssa aivan kuten minkä tahansa muun PHP-sovelluksen. Suorita komentosarja kohteen xdebug.mode=profile alla ja tarkastele cachegrind-tulostetta nähdäksesi, mitkä Phasis\-luokat vievät eniten aikaa.
Tiekartta
Mikä kaventaisi eniten kohteen V8 suorituskykyeroa, toteutettavuusjärjestyksessä:
- Polymorfiset sisäiset välimuistit — anna yhden
LOAD_MEMBER-kutsukohdan säilyttää 2–4 välimuistimuotoa ennen siirtymistä hitaaseen kutsunkäsittelyyn. Hyödyttää koodia, joka käsittelee erityyppisiä vastaanottajia. yield*ja try-with-yield kehysvedosgeneraattorien polussa — nämä muodot ohjataan tällä hetkellä Fiber-pohjaiselle puukävelijälle. Kumpikin tarvitsee eksplisiittisen tilakoneen käsittelyn (iteraattorin delegoinnin välitys, käsittelijäpino säilytettynä keskeytyksen yli), ennen kuin tilannevedokset ovat turvallisia.- Asynkroniset generaattorit ja
awaittilannevedoksissa — määritys yhdistää generaattorin keskeytyksen mikrotehtäväjonoon. Kun tavukoodirunko tukee sekä kohteitayieldettäawait, myös asynkroniset generaattorit soveltuvat tilannevedoksiin. - Parametrien tyyppipäättely JsToPhp:ssa — funktioparametrien oletustyyppi on numeerinen, joten
function (obj) { obj.method() }saa kääntäjän keskeyttämään. Rungon käytön perusteella päätellyt oliotyyppiset parametrit mahdollistaisivat metodikutsut funktioargumenteille ilman, että vastaanottaja täytyy luoda paikallisesti kohteellanew. - Suora opcache-tulostus — ohita JsToPhp:n
eval()-vaihe kirjoittamalla opcache-muotoiset opkoodit suoraan. Tämä on suurin työ; muut kohdat voidaan toteuttaa nykyisessä arkkitehtuurissa.
Mikään näistä ei ole välttämätön niissä upotuskäyttötapauksissa, joihin Phasis on suunnattu.