
# 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ą](https://phasis.inline0.dev/lt/docs/interop/host-functions).
- **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::execute` operacijų kodų jungiklį, o ne AST.
- **Tinkinta iškvietimų steko realizacija** — kiekvieno JS iškvietimo būsena laikoma `VM::execute` viduje, o iškvietusiojo kadras išsaugomas telkinyje; kiekvienam JS iškvietimui nesukuriamas naujas PHP kadras. Žr. [Baitkodo VM § Tinkinta iškvietimų steko realizacija](https://phasis.inline0.dev/lt/docs/advanced/bytecode-vm).
- **Į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()` ir `this.member` skaitymus) 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

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

Savo kodui vietoj jo naudokite bet kurį scenarijų:

```bash
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_MEMBER` iš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 `await` momentinėse kopijose** — specifikacija susieja generatoriaus sustabdymą su mikroužduočių eile. Kai baitkodo turinys palaikys ir `yield`, ir `await`, 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 per `new`.
- **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.
