
# Veiktspējas testi

Etalonuzdevumu ietvars veido stabilu JSON un cilvēkam lasāmu pārskatu. Tas atrodas
`bench/` repozitorijā [storh](https://github.com/inline0/storh) un nav bijis daļa no Composer pakotnes kopš 0.5.2, tāpēc tālāk norādītās `composer bench*` komandas palaižamas tikai no klona, pēc `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
```

## Etalonrezultāti

Trīs pilnu etalonuzdevumu ietvara izpildes reižu mediānas, 50,000 ieraksti katram dzinējam, uz Apple M1 Pro (16 GB, macOS 26.5, APFS) ar PHP 8.5 CLI, opcache un JIT izslēgti:

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

Katrs ieraksts tiek iztukšots un fsync sinhronizēts, pirms storh ziņo par tā saglabāšanu, tāpēc rakstīšanas ātrumu ierobežo failu sistēma. Lasīšana notiek no operētājsistēmas lapu kešatmiņas. Ātrumi aprēķināti no mediānām; palaidiet `composer bench` no repozitorija klona, lai pārbaudītu savu aparatūru.

| DocStore, 50k ieraksti                     | mediāna         |
| ---------------------------------------------- | --------------- |
| `put()`, viens noturīgs fails katram ierakstam | 3.3k ieraksti/s |
| `putStream()` lielapjoma ievade                    | 3.7k ieraksti/s |
| `importJsonl()`                                      | 3.6k ieraksti/s |
| `get()` atsevišķa nolasīšana, STAT pārbaudīta | 5.6 µs          |
| esošas krātuves atkārtota atvēršana           | 0.26 ms         |
| indeksēts vienādības vaicājums, `limit(100)`      | 1.1 ms          |
| indeksēta `count()` visā kolekcijā               | 41 µs           |
| indeksa izveide, 2 vienādības + 1 diapazona lauks | 52k ieraksti/s |
| pilna `stream()` ar atkārtotu STAT pārbaudi       | 103k ieraksti/s |
| `exportJsonl()`                                      | 104k ieraksti/s |

| SegmentedLog, 50k ieraksti, 16 KB segmenti       | mediāna         |
| ---------------------------------------------- | --------------- |
| `put()`, fsync pēc katras pievienošanas          | 16k pievienošanas/s |
| `appendStream()` lielapjoma ievade                       | 56k ieraksti/s  |
| kursora nolasīšana, 100 ieraksti no viduspunkta | 2.1 ms          |
| laika diapazona nolasīšana                     | 1.1 ms          |
| vienādības `count()`                              | 11 µs           |
| `compact()` visi noslēgtie segmenti                 | 69k ieraksti/s  |
| atkārtota atvēršana pēc nepilnīgu beigu datu atkopšanas | 218k ieraksti/s |

Etalonuzdevumā ik pēc 16 KB tiek noslēgts segments, lai pārbaudītu segmentu maiņu; noklusētais segmenta izmērs ir 1 MiB.

| Rinda, 50k uzdevumi                          | mediāna         |
| ---------------------------------------------- | --------------- |
| `enqueue()`, fsync pēc katra notikuma              | 22k uzdevumi/s  |
| `claim()`                                      | 23k uzdevumi/s  |
| `complete()`                                      | 23k uzdevumi/s  |
| `enqueueMany()`                                      | 209k uzdevumi/s |
| `claimMany()`                                      | 467k uzdevumi/s |
| `completeMany()`                                      | 512k uzdevumi/s |

| SQL Mirror, SQLite, 50k ieraksti          | mediāna         |
| ---------------------------------------------- | --------------- |
| sākotnējā `push()`                              | 61k rindas/s    |
| `push()` bez izmaiņām                            | 86k ieraksti/s  |
| `flush()`, 100 ID                              | 7.1 ms          |
| indeksēta SQL `COUNT` spoguļa kopā            | 6.9 ms          |
| `rebuild()`                                      | 65k rindas/s    |
| `pull()` atjaunošana, viens noturīgs fails katram ierakstam | 3.2k ieraksti/s |

| Mikro                                           | mediāna         |
| ---------------------------------------------- | --------------- |
| kešota `get()`, auksta, tad silta (MemoryCache, STAT) | 83 µs / 6.3 µs |
| UUIDv7 ģenerēšana                               | 1.3 µs          |
| UUIDv7 pārbaude                                 | 0.30 µs         |
| predikātu filtrēšana atmiņā                     | 4.4M rindas/s   |

Aptvertie mērķi:

- DocStore put, straumēšanas put, JSONL eksportēšana/importēšana, get, delete, stream un indeksa izveide
- vienādības, saliktā un diapazona indeksa vaicājumi, sakārtoti diapazoni augošā un dilstošā secībā, indeksēšana pēc skaita, ID meklēšana un neindeksēti DocStore vaicājumi
- SegmentedLog append, straumēšanas append, kursora nolasīšana, laika diapazona nolasīšana, saspiesta laika diapazona nolasīšana, QueryBuilder kursora un ID meklēšana, skaits, lielapjoma append skaits, statistika, saspiešana
- Queue enqueue, lielapjoma enqueue, claim, lielapjoma claim, complete, lielapjoma complete, requeue
- RecordQuery un QueryCondition predikātu filtrēšana atmiņā esošajās rindās
- UUIDv7 monotonā ģenerēšana, ģenerēšana ar izkliedētiem laika zīmogiem, pārbaude un laika zīmoga izgūšana
- nepilnīgas beigu rindas atkopšana
- aukstas un siltas kešatmiņas nolasīšana ar jaukšanas, stat vai uzticamu pārbaudi

Noklusētais izvades ceļš:

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

Diapazona etalonuzdevumi raksta vienu JSON failu katrai datu kopai un dzinējam mapē
`build/bench-ranges/`.

`bench:gate` salīdzina divus etalonuzdevumu JSON failus un izvada statusu, kas nav nulle, ja kāda izsekojamā metrika ir lēnāka par konfigurēto slieksni. Ja netiek norādītas `--metric` vērtības, tiek pārbaudīta katra bāzes failā esošā metrika.

`bench:ci` ir GitHub Actions regresiju pārbaudei. Tā palaiž visu dzinēju 1k etalonuzdevumu, salīdzina atlasītās rakstīšanas, lasīšanas, kešatmiņas un UUID metrikas ar izsekoto `bench/baselines/ci-1k-all.json` bāzes vērtību un izmanto plašu noklusēto slieksni, lai izvairītos no parastajām izpildvides svārstībām, vienlaikus atklājot būtiskas veiktspējas regresijas.

`bench:jit` palaiž to pašu etalonuzdevumu ietvaru ar iespējotu CLI opcache un izsekošanas JIT, kā arī atspējo Xdebug etalonuzdevuma procesam, lai PHP tiešām varētu ieslēgt JIT.
Izveidotajā JSON ir iekļauti izpildvides karodziņi, kas parāda, vai šajā izpildē opcache un JIT bija aktīvi.
