Към съдържанието

Бенчмаркове

Инструментът за сравнителни тестове записва стабилни JSON и четим за хората отчет. Намира се в bench/ в хранилището storh и не е част от пакета Composer от 0.5.2 насам, затова командите composer bench* по-долу се изпълняват само от клонирано хранилище след composer install:

Обвивка
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

Референтни резултати

Медиани от три пълни изпълнения на инструмента, по 50,000 записа за всеки механизъм, на Apple M1 Pro (16 GB, macOS 26.5, APFS) с PHP 8.5 CLI, при изключени opcache и JIT:

Обвивка
composer bench:repeat -- --dataset=50000 --engine=all --repeat=3 --memory-limit=512M

Всеки запис се flush-ва и fsync-ва, преди storh да отчете, че е съхранен, затова скоростта на запис зависи от файловата система. Четенията използват кеша на страниците на операционната система. Скоростите са изчислени от медианите; изпълнете composer bench от клонирано хранилище на проекта, за да измерите на собствения си хардуер.

DocStore, 50k записа медиана
put(), един траен файл за всеки запис 3.3k записа/сек
putStream(), групово зареждане 3.7k записа/сек
importJsonl() 3.6k записа/сек
get(), четене на запис, проверен чрез STAT 5.6 µs
повторно отваряне на съществуващо хранилище 0.26 ms
индексирана заявка за равенство, limit(100) 1.1 ms
индексирано count() в цялата колекция 41 µs
изграждане на индекс, 2 полета за равенство + 1 за диапазон 52k записа/сек
пълно stream() с повторна проверка чрез STAT 103k записа/сек
exportJsonl() 104k записа/сек
SegmentedLog, 50k записа, сегменти от 16 KB медиана
put(), fsync при всяко добавяне 16k добавяния/сек
appendStream(), групово зареждане 56k записа/сек
четене с курсор, 100 записа от средата 2.1 ms
четене на времеви диапазон 1.1 ms
count() за равенство 11 µs
compact() на всички запечатани сегменти 69k записа/сек
повторно отваряне с възстановяване на прекъснатия край 218k записа/сек

При сравнителния тест сегментът се запечатва на всеки 16 KB, за да се натоварят смяните на сегменти; размерът по подразбиране е 1 MiB.

Queue, 50k задачи медиана
enqueue(), fsync при всяко събитие 22k задачи/сек
claim() 23k задачи/сек
complete() 23k задачи/сек
enqueueMany() 209k задачи/сек
claimMany() 467k задачи/сек
completeMany() 512k задачи/сек
SQL Mirror, SQLite, 50k записа медиана
първоначално push() 61k реда/сек
push() без промени 86k записа/сек
flush(), 100 идентификатора 7.1 ms
индексирано SQL COUNT върху огледалото 6.9 ms
rebuild() 65k реда/сек
възстановяване на pull(), един траен файл за всеки запис 3.2k записа/сек
Micro медиана
кеширан get(), студен, после топъл (MemoryCache, STAT) 83 µs / 6.3 µs
UUIDv7 генериране 1.3 µs
UUIDv7 валидиране 0.30 µs
филтриране в паметта по предикат 4.4M реда/s

Обхванати цели:

  • DocStore put, streaming put, JSONL export/import, get, delete, stream и изграждане на индекс
  • заявки към DocStore с индекси за равенство, съставни индекси, индекси за диапазони, сортирани диапазони във възходящ и низходящ ред, преброяване по индекс, търсене по ID и без индекси
  • SegmentedLog append, streaming append, четене с курсор, четене по времеви диапазон, четене по компактиран времеви диапазон, търсения с курсор и по ID чрез QueryBuilder, преброявания, преброявания при групово добавяне, статистика, компактиране
  • Queue enqueue, bulk enqueue, claim, bulk claim, complete, bulk complete, requeue
  • филтриране по предикат с RecordQuery и QueryCondition върху редове в паметта
  • UUIDv7 монотонно генериране, генериране с разпределение на времевите отметки, валидиране и извличане на времеви отметки
  • възстановяване след прекъснат последен ред
  • четене от кеш при студен и топъл кеш с хеш, проверка със stat или доверено валидиране

Път по подразбиране за изход:

Text
build/bench-current.json

Изпълненията с диапазони записват по един файл JSON за всеки набор от данни и машина в build/bench-ranges/.

bench:gate сравнява два файла JSON с резултати от бенчмаркове и завършва с ненулев код, ако която и да е проследявана метрика е по-бавна от зададения праг. Ако не са подадени стойности --metric, проверява всички метрики във файла с базовите резултати.

bench:ci е проверката за регресии при тестване на дим с GitHub Actions. Тя изпълнява бенчмарк с 1k записа за всички машини, сравнява избрани метрики за запис/четене/кеширане/UUID с проследяваните базови резултати bench/baselines/ci-1k-all.json и използва широк праг по подразбиране, за да избегне обичайните отклонения при изпълнение, като същевременно засича сериозни регресии в производителността.

bench:jit изпълнява същия тестов набор с активирани CLI opcache и tracing JIT и изключва Xdebug за процеса на бенчмарка, за да може PHP действително да активира JIT. Генерираният JSON включва флагове на средата за изпълнение, които показват дали opcache и JIT са били активни при това изпълнение.