
# Výkonnostné testy

Testovací rámec na porovnávanie výkonu zapisuje stabilné výsledky JSON a čitateľnú správu. Nachádza sa v `bench/` v repozitári [storh](https://github.com/inline0/storh) a od verzie 0.5.2 už nie je súčasťou balíka Composer, takže nasledujúce príkazy `composer bench*` možno spustiť iba z klonu po vykonaní `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
```

## Referenčné výsledky

Mediány z troch úplných behov testovacieho rámca, 50,000 záznamov na každý modul, na zariadení Apple M1 Pro (16 GB, macOS 26.5, APFS) s PHP 8.5 CLI, vypnutými opcache a JIT:

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

Každý zápis sa pred nahlásením uloženia storh vyprázdni a fsyncuje, preto rýchlosť zápisu obmedzuje súborový systém. Čítanie využíva vyrovnávaciu pamäť stránok operačného systému. Rýchlosti sú odvodené z mediánov; vlastný hardvér otestujte spustením `composer bench` z klonu repozitára.

| DocStore, 50k záznamov                       | medián          |
| ---------------------------------------------- | --------------- |
| `put()`, jeden trvalý súbor na záznam           | 3.3k záznamov/s  |
| `putStream()` hromadné načítanie                      | 3.7k záznamov/s  |
| `importJsonl()`                                | 3.6k záznamov/s  |
| `get()` čítanie podľa ID, overené pomocou STAT  | 5.6 µs          |
| opätovné otvorenie existujúceho úložiska       | 0.26 ms         |
| indexovaný dopyt na rovnosť, `limit(100)`           | 1.1 ms          |
| indexované `count()` naprieč kolekciou           | 41 µs           |
| zostavenie indexu, 2 polia rovnosti + 1 rozsahové pole | 52k záznamov/s |
| úplné `stream()` s opätovným overením pomocou STAT | 103k záznamov/s |
| `exportJsonl()`                                | 104k záznamov/s  |

| SegmentedLog, 50k záznamov, segmenty s veľkosťou 16 KB | medián          |
| ---------------------------------------------- | --------------- |
| `put()`, fsync pri každom pridaní               | 16k pridaní/s   |
| `appendStream()` hromadné načítanie                      | 56k záznamov/s  |
| čítanie kurzorom, 100 záznamov od stredu    | 2.1 ms          |
| čítanie podľa časového rozsahu                 | 1.1 ms          |
| `count()` na rovnosť                              | 11 µs           |
| `compact()` všetkých uzavretých segmentov           | 69k záznamov/s  |
| opätovné otvorenie s obnovou odrezaného konca  | 218k záznamov/s |

Test výkonu uzatvára segment každých 16 KB, aby zaťažil prechody medzi segmentmi; predvolená veľkosť segmentu je 1 MiB.

| Queue, 50k úloh                              | medián          |
| ---------------------------------------------- | --------------- |
| `enqueue()`, fsync pri každej udalosti              | 22k úloh/s      |
| `claim()`                                      | 23k úloh/s      |
| `complete()`                                      | 23k úloh/s      |
| `enqueueMany()`                                      | 209k úloh/s     |
| `claimMany()`                                      | 467k úloh/s     |
| `completeMany()`                                      | 512k úloh/s     |

| SQL Mirror, SQLite, 50k záznamov          | medián          |
| ---------------------------------------------- | --------------- |
| počiatočné `push()`                              | 61k riadkov/s   |
| `push()` bez zmien                               | 86k záznamov/s  |
| `flush()`, ID 100                              | 7.1 ms          |
| indexované SQL `COUNT` nad zrkadlom          | 6.9 ms          |
| `rebuild()`                                      | 65k riadkov/s   |
| obnovenie `pull()`, jeden trvalý súbor na záznam | 3.2k záznamov/s |

| Micro                                          | medián          |
| ---------------------------------------------- | --------------- |
| uložené v cache `get()`, najprv studené, potom teplé (MemoryCache, STAT) | 83 µs / 6.3 µs |
| generovanie UUIDv7                             | 1.3 µs          |
| overovanie UUIDv7                              | 0.30 µs         |
| filtrovanie predikátom v pamäti                 | 4.4M riadkov/s  |

Pokryté ciele:

- DocStore put, streaming put, export/import JSONL, get, delete, stream a zostavenie indexu
- dopyty DocStore indexované podľa rovnosti, zloženého indexu a rozsahu, usporiadané rozsahy vzostupne a zostupne, počet cez index, vyhľadávanie podľa ID a dopyty bez indexu
- SegmentedLog append, streaming append, čítanie kurzorom, čítanie podľa časového rozsahu, čítanie podľa kompaktného časového rozsahu, vyhľadávanie kurzorom a podľa ID cez QueryBuilder, počty, počty hromadného pridávania, štatistiky, kompakcia
- Queue enqueue, hromadné enqueue, claim, hromadné claim, complete, hromadné complete, requeue
- filtrovanie predikátom RecordQuery a QueryCondition nad riadkami v pamäti
- generovanie monotónnych hodnôt UUIDv7, generovanie s rozptýlenými časovými značkami, overovanie a extrakcia časovej značky
- obnova po odrezanom koncovom riadku
- čítanie studenej a teplej cache s overením pomocou hash, stat alebo dôveryhodného režimu

Predvolená výstupná cesta:

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

Spustenia rozsahových testov zapisujú jeden súbor JSON pre každú množinu údajov a nástroj v priečinku
`build/bench-ranges/`.

`bench:gate` porovnáva dva súbory JSON testov výkonu a skončí s nenulovým kódom, ak je niektorá sledovaná metrika pomalšia než nakonfigurovaný limit. Ak nie sú zadané žiadne hodnoty `--metric`, kontroluje všetky metriky v základnom súbore.

`bench:ci` je brána na kontrolu regresií výkonu GitHub Actions. Spustí test výkonu všetkých nástrojov s 1k záznamami, porovná vybrané metriky zápisu/čítania/cache/UUID so sledovanou základnou hodnotou `bench/baselines/ci-1k-all.json` a použije široký predvolený limit, aby zabránila bežnému kolísaniu výkonu runnera a zároveň zachytila veľké regresie výkonu.

`bench:jit` spúšťa rovnaký testovací rámec so zapnutými CLI opcache a trasovacím JIT a pre proces testu vypína Xdebug, aby PHP mohol skutočne zapnúť JIT.
Vygenerovaný JSON obsahuje príznaky behu, ktoré ukazujú, či boli opcache a JIT počas daného spustenia aktívne.
