
# Suorituskykytestit

Vertailutestien suoritusympäristö kirjoittaa vakaat JSON-tulokset ja ihmisen luettavan raportin. Se sijaitsee kohteessa
`bench/` [storh-repositoriossa](https://github.com/inline0/storh), eikä se ole ollut mukana Composer-paketissa sitten 0.5.2, joten alla olevat `composer bench*`-komennot suoritetaan vain kloonista, kun `composer install` on tehty:

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

## Vertailutulokset

Kolmen täydellisen suoritusajon mediaanit, 50,000 tietuetta moottoria kohti, laitteella Apple M1 Pro (16 GB, macOS 26.5, APFS), PHP 8.5 CLI, opcache ja JIT pois käytöstä:

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

Jokainen kirjoitus tyhjennetään ja synkronoidaan levylle ennen kuin storh ilmoittaa sen tallennetuksi, joten kirjoitusnopeudet riippuvat tiedostojärjestelmästä. Luvut luetaan käyttöjärjestelmän sivuvälimuistista. Nopeudet on laskettu mediaaneista; suorita `composer bench` repositorion kloonista omalla laitteistollasi.

| DocStore, 50k tietuetta                       | mediaani        |
| ---------------------------------------------- | --------------- |
| `put()`, yksi pysyvä tiedosto tietuetta kohti   | 3.3k tietuetta/s |
| `putStream()` joukkosyöttö                             | 3.7k tietuetta/s |
| `importJsonl()`                                         | 3.6k tietuetta/s |
| `get()` yksittäisluku, STAT-tarkistettu          | 5.6 µs          |
| olemassa olevan tallennuksen uudelleenavaus     | 0.26 ms         |
| indeksoitu yhtäsuuruushaku, `limit(100)`             | 1.1 ms          |
| indeksoitu `count()` koko kokoelmasta              | 41 µs           |
| indeksin luonti, 2 yhtäsuuruus- + 1 aluekenttä  | 52k tietuetta/s |
| kaikkien `stream()`-tietueiden STAT-uudelleentarkistus | 103k tietuetta/s |
| `exportJsonl()`                                         | 104k tietuetta/s |

| SegmentedLog, 50k tietuetta, 16 KB:n segmentit | mediaani         |
| ---------------------------------------------- | ---------------- |
| `put()`, fsync jokaisen lisäyksen jälkeen       | 16k lisäystä/s   |
| `appendStream()` joukkosyöttö                             | 56k tietuetta/s  |
| kohdistinluku, 100 tietuetta keskikohdasta  | 2.1 ms           |
| aikaväliluku                                    | 1.1 ms           |
| yhtäsuuruus`count()`                              | 11 µs            |
| `compact()` kaikki suljetut segmentit                | 69k tietuetta/s  |
| uudelleenavaus katkenneen lopun palautuksella  | 218k tietuetta/s |

Vertailutesti sulkee segmentin aina 16 KB:n jälkeen testatakseen segmenttien vaihtumista; oletuskoko on 1 MiB.

| Queue, 50k työtä                              | mediaani       |
| ---------------------------------------------- | -------------- |
| `enqueue()`, fsync jokaisen tapahtuman jälkeen       | 22k työtä/s    |
| `claim()`                                         | 23k työtä/s    |
| `complete()`                                         | 23k työtä/s    |
| `enqueueMany()`                                         | 209k työtä/s   |
| `claimMany()`                                         | 467k työtä/s   |
| `completeMany()`                                         | 512k työtä/s   |

| SQL Mirror, SQLite, 50k tietuetta          | mediaani       |
| ---------------------------------------------- | -------------- |
| alkuperäinen `push()`                            | 61k riviä/s    |
| `push()`, kun mitään ei ole muuttunut            | 86k tietuetta/s |
| `flush()`, 100 tunnistetta                     | 7.1 ms         |
| indeksoitu SQL `COUNT` peilistä               | 6.9 ms         |
| `rebuild()`                                         | 65k riviä/s    |
| `pull()`-palautus, yksi pysyvä tiedosto tietuetta kohti | 3.2k tietuetta/s |

| Mikro                                           | mediaani        |
| ----------------------------------------------- | --------------- |
| välimuistissa `get()`, kylmästä lämpimäksi (MemoryCache, STAT) | 83 µs / 6.3 µs |
| UUIDv7 luonti                                    | 1.3 µs          |
| UUIDv7 tarkistus                                 | 0.30 µs         |
| suodatus muistissa predikaatin perusteella       | 4.4M riviä/s    |

Testatut kohteet:

- DocStore put, suoratoistava put, JSONL-vienti/tuonti, get, delete, stream ja indeksin luonti
- yhtäsuuruusindeksoidut, yhdistelmäindeksoidut ja alueindeksoidut kyselyt, nousevassa ja laskevassa järjestyksessä tehdyt alueva haut, indeksoitu lukumäärä, tunnistehaku sekä indeksoimattomat DocStore-kyselyt
- SegmentedLog append, suoratoistava append, kohdistinluvut, aikaväliluvut, tiivistetyt aikaväliluvut, QueryBuilder-kohdistin- ja tunnistehaut, lukumäärät, joukkolisäysten lukumäärät, tilastot ja tiivistys
- Queue enqueue, joukkolisäys, claim, joukkovaraus, complete, joukkovalmistus ja requeue
- RecordQuery- ja QueryCondition-predikaattisuodatus muistissa oleville riveille
- UUIDv7 monotoninen luonti, aikaleimojen jakaumaan perustuva luonti, validointi ja aikaleiman poiminta
- katkenneen loppurivin palautus
- kylmät ja lämpimät välimuistiluvut hash-, stat- tai luotetulla validoinnilla

Tulosteen oletuspolku:

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

Alueajot kirjoittavat yhden JSON-tiedoston kutakin tietojoukkoa ja moottoria kohti kohteeseen
`build/bench-ranges/`.

`bench:gate` vertaa kahta vertailutesti-JSON-tiedostoa ja palauttaa nollasta poikkeavan poistumiskoodin, jos jokin seurattu mittari on määritettyä raja-arvoa hitaampi. Jos `--metric`-arvoja ei anneta, se asettaa portin kaikille lähtötiedostossa oleville mittareille.

`bench:ci` on GitHub Actions-smoke-regressioportti. Se suorittaa kaikkien moottorien 1k-vertailutestin, vertaa valittuja kirjoitus-, luku-, välimuisti- ja UUID-mittareita seurattuun `bench/baselines/ci-1k-all.json`-lähtötasoon ja käyttää korkeaa oletusrajaa tavallisen suoritusympäristön vaihtelun huomioimiseksi, mutta hylkää silti suuret suorituskyvyn heikkenemiset.

`bench:jit` suorittaa saman testikehyksen, kun CLI opcache ja jäljittävä JIT ovat käytössä. Se poistaa Xdebug-asetuksen käytöstä vertailuprosessissa, jotta PHP voi todella ottaa JIT:n käyttöön. Luotu JSON sisältää ajonaikaiset liput, joista näkee, olivatko opcache ja JIT käytössä kyseisessä ajossa.
