Přejít k obsahu

Výkonnostní testy

Benchmarkový nástroj vytváří stabilní JSON a čitelný report. Nachází se v bench/ v repozitáři storh a od 0.5.2 není součástí balíčku Composer, takže níže uvedené příkazy composer bench* lze spustit pouze z klonu, po provedení composer install:

Shell
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 tří úplných běhů sady nástrojů, 50,000 záznamů na engine, na zařízení Apple M1 Pro (16 GB, macOS 26.5, APFS) s PHP 8.5 CLI; opcache a JIT jsou vypnuté:

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

Každý zápis se před nahlášením uložení v storh flushne a synchronizuje pomocí fsync, takže rychlost zápisu omezuje souborový systém. Čtení probíhá z mezipaměti stránek operačního systému. Rychlosti jsou vypočtené z mediánů; vlastní hardware si ověřte spuštěním composer bench z klonu repozitáře.

DocStore, 50k záznamů medián
put(), jeden trvalý soubor na záznam 3.3k záznamů/s
hromadné vložení putStream() 3.7k záznamů/s
importJsonl() 3.6k záznamů/s
bodové čtení get() s ověřením STAT 5.6 µs
opětovné otevření existujícího úložiště 0.26 ms
indexovaný dotaz na rovnost, limit(100) 1.1 ms
indexované count() napříč kolekcí 41 µs
sestavení indexu, 2 pole pro rovnost + 1 rozsah 52k záznamů/s
úplné stream() s opětovným ověřením STAT 103k záznamů/s
exportJsonl() 104k záznamů/s
SegmentedLog, 50k záznamů, segmenty 16 KB medián
put(), fsync po každém připojení 16k připojení/s
hromadné vložení appendStream() 56k záznamů/s
čtení kurzorem, 100 záznamů od poloviny 2.1 ms
čtení v časovém rozsahu 1.1 ms
dotaz na rovnost count() 11 µs
compact() všech uzavřených segmentů 69k záznamů/s
opětovné otevření s obnovou neúplného konce 218k záznamů/s

Benchmark uzavírá segment každých 16 KB, aby zatížil střídání segmentů; výchozí velikost segmentu je 1 MiB.

Fronta, 50k úloh medián
enqueue(), fsync po každé události 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áznamů medián
počáteční push() 61k řádků/s
push() beze změn 86k záznamů/s
flush(), ID 100 7.1 ms
indexované SQL COUNT nad zrcadlem 6.9 ms
rebuild() 65k řádků/s
obnova pull(), jeden trvalý soubor na záznam 3.2k záznamů/s
Micro medián
cached get(), cold then warm (MemoryCache, STAT) 83 µs / 6.3 µs
UUIDv7 generate 1.3 µs
UUIDv7 validate 0.30 µs
filtrování predikátů v paměti 4.4M řádků/s

Pokryté cíle:

  • DocStore put, streamovací put, export/import JSONL, get, delete, stream a vytvoření indexu
  • dotazy DocStore s indexem rovnosti, složeným indexem, rozsahovým indexem, seřazeným rozsahem vzestupně i sestupně, počtem podle indexu, hledáním podle ID i bez indexu
  • SegmentedLog append, streamovací append, čtení pomocí kurzoru, čtení časového rozsahu, čtení zkomprimovaného časového rozsahu, hledání kurzorem a ID pomocí QueryBuilder, počty, počty hromadného přidání, statistiky, kompakce
  • Queue enqueue, hromadné enqueue, claim, hromadné claim, complete, hromadné complete, requeue
  • filtrování predikátů RecordQuery a QueryCondition nad řádky v paměti
  • monotónní generování UUIDv7, generování s rozptylem časových razítek, validace a extrakce časových razítek
  • obnova po poškozeném posledním řádku
  • čtení z chladné a zahřáté mezipaměti s ověřením hashe, stavu nebo důvěryhodným ověřením

Výchozí výstupní cesta:

Text
build/bench-current.json

Testy rozsahu zapisují jeden soubor JSON pro každou datovou sadu a engine do build/bench-ranges/.

bench:gate porovnává dva soubory JSON s výsledky benchmarku a vrací nenulový kód, pokud je některá sledovaná metrika pomalejší než nakonfigurovaný limit. Pokud nejsou předány žádné hodnoty --metric, kontroluje všechny metriky obsažené v základním souboru.

bench:ci je kontrola regresí GitHub Actions. Spustí benchmark všech enginů s 1k záznamy, porovná vybrané metriky zápisu, čtení, mezipaměti a UUID se sledovanou základní hodnotou bench/baselines/ci-1k-all.json a používá velký výchozí limit, který omezuje běžné odchylky běhového prostředí a přitom zachytí výrazné zpomalení.

bench:jit spustí stejný testovací nástroj se zapnutou mezipamětí opcache a trasovacím JIT CLI a pro proces benchmarku vypne Xdebug, aby PHP mohl JIT skutečně zapnout. Vygenerovaný soubor JSON obsahuje běhové příznaky, které ukazují, zda byly při daném běhu aktivní opcache a JIT.