Siirry sisältöön

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::execute operaatiokytkimen kautta AST:n sijaan.
  • Mukautettu kutsupino — jokainen JS-kutsu säilyttää tilan kohteessa VM::execute ja 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() ja this.member lukemiset) 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äkopiointitapaa JSON.parse(JSON.stringify(o)).

Oman kuorman mittaaminen

Shell
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:

Shell
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 await tilannevedoksissa — määritys yhdistää generaattorin keskeytyksen mikrotehtäväjonoon. Kun tavukoodirunko tukee sekä kohteita yield että 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 kohteella new.
  • 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.