
# Prestandatester

Benchmarkverktyget skriver stabila JSON och en rapport som är lätt att läsa. Det finns
under `bench/` i [storh-arkivet](https://github.com/inline0/storh) och har
inte ingått i paketet Composer sedan 0.5.2, så kommandona `composer bench*`
nedan körs bara från en klon, efter `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
```

## Referensresultat

Medianvärden från tre fullständiga körningar av verktyget, 50,000 poster per motor, på en
Apple M1 Pro (16 GB, macOS 26.5, APFS) med PHP 8.5 CLI, opcache och JIT avstängda:

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

Varje skrivning töms och synkroniseras med fsync innan storh rapporterar den som lagrad, så skrivhastigheten begränsas av filsystemet. Läsningar körs mot operativsystemets sidcache. Hastigheterna
beräknas från medianvärdena; kör `composer bench` från en klon av arkivet
på din egen maskinvara.

| DocStore, 50k poster                       | median          |
| ---------------------------------------------- | --------------- |
| `put()`, en beständig fil per post           | 3.3k poster/s  |
| `putStream()` massinläsning                      | 3.7k poster/s  |
| `importJsonl()`                                | 3.6k poster/s  |
| `get()` punktläsning, STAT-validerad             | 5.6 µs          |
| öppna en befintlig butik                       | 0.26 ms         |
| indexerad likhetsfråga, `limit(100)`           | 1.1 ms          |
| indexerad `count()` i samlingen        | 41 µs           |
| indexbygge, 2 likhetsfält + 1 intervallfält        | 52k poster/s   |
| fullständig `stream()` med STAT-omvalidering        | 103k poster/s  |
| `exportJsonl()`                                | 104k poster/s  |

| SegmentedLog, 50k poster, 16 KB-segment      | median          |
| ---------------------------------------------- | --------------- |
| `put()`, fsync vid varje tillägg                      | 16k tillägg/s   |
| `appendStream()` massinläsning                   | 56k poster/s   |
| markörläsning, 100 poster från mitten     | 2.1 ms          |
| läsning inom tidsintervall                                | 1.1 ms          |
| likhets`count()`                             | 11 µs           |
| `compact()` alla förseglade segment                | 69k poster/s   |
| öppning med återställning av ofullständig avslutning                 | 218k poster/s  |

Benchmarken förseglar ett segment var 16 KB för att belasta segmentväxlingarna; standardstorleken för segment är 1 MiB.

| Kö, 50k jobb                                | median          |
| ---------------------------------------------- | --------------- |
| `enqueue()`, fsync vid varje händelse                   | 22k jobb/s      |
| `claim()`                                      | 23k jobb/s      |
| `complete()`                                   | 23k jobb/s      |
| `enqueueMany()`                                | 209k jobb/s     |
| `claimMany()`                                  | 467k jobb/s     |
| `completeMany()`                               | 512k jobb/s     |

| SQL Mirror, SQLite, 50k poster                | median          |
| ---------------------------------------------- | --------------- |
| initial `push()`                               | 61k rader/s      |
| `push()` utan ändringar                  | 86k poster/s   |
| `flush()`, 100 id:n                             | 7.1 ms          |
| indexerad SQL `COUNT` över spegeln            | 6.9 ms          |
| `rebuild()`                                    | 65k rader/s      |
| `pull()` återställning, en beständig fil per post  | 3.2k poster/s  |

| Mikro                                          | median          |
| ---------------------------------------------- | --------------- |
| cachad `get()`, kall och sedan varm (MemoryCache, STAT) | 83 µs / 6.3 µs |
| UUIDv7 generering                                | 1.3 µs          |
| UUIDv7 validering                                | 0.30 µs         |
| filtrering med predikat i minnet                  | 4.4M rader/s     |

Testade mål:

- DocStore put, streaming put, JSONL export/import, get, delete, stream och index build
- jämlikhetsindexerade, sammansatta index, intervallindexerade, stigande och fallande ordnade intervall, indexerade antal, ID-sökning och icke-indexerade DocStore-frågor
- SegmentedLog append, streaming append, markörläsningar, tidsintervalläsningar, komprimerade tidsintervalläsningar, QueryBuilder-markör- och ID-sökningar, antal, antal vid massappend, statistik, komprimering
- Queue enqueue, mass-enqueue, claim, mass-claim, complete, mass-complete, requeue
- predikatfiltrering med RecordQuery och QueryCondition över rader i minnet
- UUIDv7 monoton generering, generering med spridda tidsstämplar, validering och extrahering av tidsstämplar
- återställning av trasig avslutande rad
- kalla respektive varma cacheläsningar med hash-, stat- eller betrodd validering

Standardsökväg för utdata:

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

Intervallkörningar skriver en JSON-fil per datamängd och motor under
`build/bench-ranges/`.

`bench:gate` jämför två benchmarkfiler JSON och avslutas med en felkod om något
spårat mätvärde är långsammare än det konfigurerade tröskelvärdet. Om inga värden
för `--metric` anges, kontrolleras varje mätvärde i baslinjefilen.

`bench:ci` är röktestets regressionsgrind för GitHub Actions. Den kör ett benchmark på 1k för alla motorer,
jämför utvalda mått för skrivning/läsning/cache/UUID med den spårade
baslinjen `bench/baselines/ci-1k-all.json` och använder ett brett standardtröskelvärde för att
undvika normalt brus från körmiljön och ändå fånga stora prestandaregressioner.

`bench:jit` kör samma test med CLI opcache och spårnings-JIT aktiverade
och inaktiverar Xdebug för benchmarkprocessen så att PHP faktiskt kan aktivera JIT.
Den genererade JSON innehåller körningsflaggor som visar om opcache och JIT
var aktiva under körningen.
