
# 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](https://phasis.inline0.dev/fi/docs/interop/host-functions) 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](https://phasis.inline0.dev/fi/docs/advanced/bytecode-vm).
- **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

```bash
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`](https://github.com/inline0/phasis/blob/main/BENCH.md) jokaisella CI-benchmark-ajolla.

Voit käyttää omaa koodiasi vaihtamalla tilalle minkä tahansa komentosarjan:

```bash
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.
