
# Našumo testai

Našumo bandymų aplinka įrašo stabilius JSON ir žmogui skaitomą ataskaitą. Ji yra
`bench/`, [storh saugykloje](https://github.com/inline0/storh) ir
nuo 0.5.2 nebėra Composer paketo dalis, todėl toliau pateiktas `composer bench*`
komandas galima vykdyti tik klonuotoje saugykloje, atlikus `composer install`:

```bash
composer bench
composer bench -- --dataset=100000 --engine=doc
composer bench -- --dataset=100000 --engine=log
composer bench -- --dataset=100000 --engine=queue
composer bench -- --dataset=100000 --engine=cache --cache-validation=trust
composer bench -- --dataset=100000 --engine=filter
composer bench -- --dataset=1000000 --engine=uuid
composer bench:jit -- --dataset=1000000 --engine=uuid
composer bench:repeat -- --dataset=100000 --engine=doc --repeat=5
composer bench:repeat -- --dataset=1000000 --engine=filter --repeat=5 --memory-limit=512M
composer bench:range -- --datasets=1000,10000,50000,100000
composer bench:range -- --datasets=100000 --engines=cache --memory-limit=512M
composer bench:compare build/bench-main.json build/bench-current.json
composer bench:gate -- build/bench-main.json build/bench-current.json --threshold=10 --metric=doc.put --metric=log.stream
composer bench:ci
```

## Etaloniniai rezultatai

Trijų pilnų bandymų aplinkos vykdymų medianos, kiekvienam varikliui – 50,000 įrašų, naudojant
Apple M1 Pro (16 GB, macOS 26.5, APFS) su PHP 8.5 CLI, opcache ir JIT išjungti:

```bash
composer bench:repeat -- --dataset=50000 --engine=all --repeat=3 --memory-limit=512M
```

Kiekvienas įrašymas išsiunčiamas į diską ir atliekamas fsync prieš storh patvirtinant, kad duomenys įrašyti, todėl įrašymo greitis priklauso nuo failų sistemos. Skaitoma iš OS puslapių talpyklos. Greičiai apskaičiuoti iš medianų; išbandykite `composer bench` klonuotoje saugykloje savo įrangoje.

| DocStore, 50k įrašų                          | mediana          |
| ---------------------------------------------- | --------------- |
| `put()`, po vieną ilgalaikį failą kiekvienam įrašui | 3.3k įrašų/s  |
| `putStream()` masinis importavimas                    | 3.7k įrašų/s  |
| `importJsonl()`                                | 3.6k įrašų/s  |
| `get()` nuskaitymas pagal raktą, patikrintas naudojant STAT | 5.6 µs          |
| esamos saugyklos atidarymas iš naujo                       | 0.26 ms         |
| indeksuota lygybės užklausa, `limit(100)`           | 1.1 ms          |
| indeksuota `count()` visoje kolekcijoje        | 41 µs           |
| indekso kūrimas, 2 lygybės ir 1 intervalo laukas        | 52k įrašų/s   |
| pilnas `stream()` su pakartotiniu STAT tikrinimu        | 103k įrašų/s  |
| `exportJsonl()`                                | 104k įrašų/s  |

| SegmentedLog, 50k įrašų, 16 KB segmentai      | mediana         |
| ---------------------------------------------- | --------------- |
| `put()`, fsync po kiekvieno pridėjimo           | 16k pridėjimų/s |
| `appendStream()` masinis įkėlimas                        | 56k įrašų/s     |
| žymeklio skaitymas, 100 įrašų nuo vidurio    | 2.1 ms          |
| laiko intervalo skaitymas                      | 1.1 ms          |
| lygybės `count()`                                 | 11 µs           |
| `compact()` visų uždarytų segmentų                  | 69k įrašų/s     |
| atidarymas iš naujo ir nutrūkusios pabaigos atkūrimas | 218k įrašų/s |

Bandymas kas 16 KB uždaro segmentą, kad būtų dažniau pereinama prie naujo segmento; numatytasis segmento dydis yra 1 MiB.

| Eilė, 50k užduočių                            | mediana         |
| ---------------------------------------------- | --------------- |
| `enqueue()`, fsync po kiekvieno įvykio              | 22k užduočių/s  |
| `claim()`                                         | 23k užduočių/s  |
| `complete()`                                         | 23k užduočių/s  |
| `enqueueMany()`                                         | 209k užduočių/s |
| `claimMany()`                                         | 467k užduočių/s |
| `completeMany()`                                         | 512k užduočių/s |

| SQL Mirror, SQLite, 50k įrašų               | mediana         |
| ---------------------------------------------- | --------------- |
| pradinis `push()`                                | 61k eilučių/s   |
| `push()`, kai niekas nepasikeitė                 | 86k įrašų/s     |
| `flush()`, 100 ID                              | 7.1 ms          |
| indeksuotas SQL `COUNT` per veidrodį          | 6.9 ms          |
| `rebuild()`                                         | 65k eilučių/s   |
| `pull()` atkūrimas, vienas patvarus failas įrašui | 3.2k įrašų/s    |

| Micro                                          | mediana         |
| ---------------------------------------------- | --------------- |
| talpykloje saugomas `get()`, šaltas, tada šiltas (MemoryCache, STAT) | 83 µs / 6.3 µs |
| UUIDv7 generavimas                             | 1.3 µs          |
| UUIDv7 tikrinimas                               | 0.30 µs         |
| predikatų filtravimas atmintyje                 | 4.4M eilučių/s  |

Išbandytos užduotys:

- DocStore įrašymas, srautinis įrašymas, JSONL eksportavimas / importavimas, gavimas, trynimas, srautinis skaitymas ir indekso kūrimas
- DocStore užklausos pagal lygybę, sudėtinį indeksą, intervalą, didėjimo ir mažėjimo tvarka surikiuotus intervalus, indeksuotą skaičiavimą, ID paiešką ir be indeksų
- SegmentedLog įrašymas, srautinis įrašymas, žymeklių skaitymas, laiko intervalo skaitymas, sutankintų laiko intervalų skaitymas, QueryBuilder žymeklių ir ID paieškos, skaičiavimai, masinio įrašymo skaičiavimai, statistika, sutankinimas
- Queue įtraukimas į eilę, masinis įtraukimas, paėmimas, masinis paėmimas, užbaigimas, masinis užbaigimas, grąžinimas į eilę
- RecordQuery ir QueryCondition predikatų filtravimas atmintyje esančiuose įrašuose
- UUIDv7 monotoniškas generavimas, generavimas su išskaidytais laiko žymomis, tikrinimas ir laiko žymos išgavimas
- nutrūkusios paskutinės eilutės atkūrimas
- šaltos ir šiltos talpyklos skaitymai su maišos, stat, arba patikimu tikrinimu

Numatytasis išvesties kelias:

```text
build/bench-current.json
```

Intervalų bandymai kiekvienam duomenų rinkiniui ir varikliui įrašo po vieną JSON failą aplanke
`build/bench-ranges/`.

`bench:gate` palygina du lyginamųjų bandymų JSON failus ir grąžina ne nulinį kodą, jei bet kuris sekamas rodiklis yra lėtesnis už nustatytą ribą. Jei nepateikiamos `--metric` reikšmės, tikrinamas kiekvienas pradiniame faile esantis rodiklis.

`bench:ci` yra GitHub Actions greitoji regresijų patikra. Ji atlieka 1k visų variklių lyginamąjį bandymą, palygina pasirinktus įrašymo / skaitymo / talpyklos / UUID rodiklius su sekamu `bench/baselines/ci-1k-all.json` pradiniu lygiu ir taiko plačią numatytąją ribą, kad įprastas vykdymo aplinkos triukšmas nesukeltų klaidingos nesėkmės, bet dideli našumo nuosmukiai būtų aptikti.

`bench:jit` vykdo tą pačią bandymų sistemą su įjungtais CLI opcache ir sekimo JIT, o Xdebug išjungia lyginamojo bandymo procesui, kad PHP galėtų iš tiesų įjungti JIT.
Sugeneruotame JSON pateikiamos vykdymo aplinkos vėliavėlės, rodančios, ar šio bandymo metu veikė opcache ir JIT.
