Перейти к основному содержимому
Нормативная версия документации - английская

Эта страница переведена с английского языковой моделью. При любом расхождении верен английский оригинал.

Публикация

Как крейт публикует результаты бенчмарков: один документ JSON по стабильному пути, который читает страница бенчмарков.

Каждая адаптация библиотеки брокера измеряет себя сама. Она запускает just bench против брокера очереди из своего compose-файла и кладёт итог в свой репозиторий: страницу для человека и документ JSON для страницы бенчмарков.

Стабильный путь​

Файл хранится в репозитории адаптации: docs/benchmarks/results.json, рядом со страницей, которая его объясняет. Страница бенчмарков читает его из ветки main, поэтому новый замер виден сразу после слияния.

https://raw.githubusercontent.com/powersemmi/<crate>/main/docs/benchmarks/results.json

Документ​

Основные разделы документа:

  • schema - версия документа. Версия 3 сообщает по каждому циклу три круга (best, median, worst), версия 2 добавила раздел code, версия 1 содержала медиану с крайними значениями;
  • environment - машина (cpu, architecture, cpu_frequency, cores, memory, memory_speed) и сборка бенчмарков (profile, features);
  • scenarios - график сравнения, по записи на сценарий;
  • code - график стоимости кода, по записи на сценарий.

В записи scenarios поля raw, adapter и framework дают три круга каждого цикла. В таблице печатается best, в скобках median. worst читается, но не печатается: по расстоянию между лучшим и худшим кругом выносится вердикт. unit - короткая подпись рядом с каждым значением строки, а не предложение.

verdict - это measured или indistinguishable по правилу разброса. overhead_percent - разница между фреймворком и сырым клиентом от края до края. Её записывают всегда, а показывают только при вердикте measured.

adapter_overhead_percent - разница между сырым клиентом и собственными консьюмером и издателем адаптации, измеренными без рантайма. adapter_verdict применяет к ней то же правило разброса.

broker_bound помечает прогон, темп которого задавал брокер очереди, а не консьюмер. В environment может быть поле round_trip: проба, по которой считается broker_bound, чтобы читатель мог пересчитать сам.

В записи code поле framework дано на сообщение в установившемся режиме, а cold - полная стоимость запуска сервиса и первой доставки, ни на что не делённая. gated говорит, валит ли регрессия в сценарии прогон бенчмарков крейта.

Крейт, который измеряет код отдельно от сравнения с сырым клиентом, записывает дату и версии этого прогона в code_measured: поля measured_at, crate_version и core_version. Дату и версии для строки над графиком стоимости кода страница берёт оттуда. В документе без code_measured они берутся из полей верхнего уровня.

Документы старых схем и неполные документы страница читает так:

  • в документе схемы 3 без median в скобках печатается худший круг, как было до появления этого поля;
  • без adapter_verdict страница сама применяет правило к опубликованным разбросам, чтобы две колонки одной строки одинаково решали, что различимо. Без всех полей adapter средняя колонка остаётся пустой;
  • поле окружения, которого машина не сообщает, записывается как unknown, а не придумывается: скорость памяти берётся из таблиц DMI, а их на большинстве систем читает только root. Обязательны только cpu, os и rustc, поэтому документ схемы 1 остаётся читаемым;
  • крейт, который публикует только scenarios, объявляет schema 1 и показывает только сравнение. Крейт, который не измеряет собственный брокер очереди, не пишет scenarios вовсе (а не оставляет пустой список) и показывает только график стоимости кода;
  • если документ не загрузился или объявляет незнакомую версию schema, на его вкладке остаётся строка «результаты ещё не опубликованы». Так сломанная публикация видна, а не пропадает молча.
{
"schema": 3,
"crate": "ruststream-nats",
"crate_version": "0.7.0",
"core_version": "0.7.0",
"measured_at": "2026-08-20",
"environment": {
"cpu": "AMD Ryzen 9 5950X 16-Core Processor",
"architecture": "x86_64 (x86-64-v3)",
"cpu_frequency": "base 3400 MHz, max 4900 MHz",
"cores": "16 physical, 32 logical",
"memory": "62.7 GiB",
"memory_speed": "DDR4, 3600 MT/s",
"os": "Linux 6.16.7",
"broker": "nats:2.10-alpine in Docker on localhost",
"rustc": "1.90.0",
"valgrind": "3.25.1",
"profile": "bench, inheriting release (opt-level = 3, lto = false, codegen-units = 16)",
"features": "--no-default-features --features memory,macros,json",
"rustflags": "-C target-cpu=native"
},
"scenarios": [
{
"name": "core NATS, 512 B JSON, ack each",
"unit": "msg/s",
"messages": 200000,
"pairs": 3,
"raw": { "best": 129604, "median": 128470, "worst": 126980 },
"adapter": { "best": 129310, "median": 128040, "worst": 126700 },
"framework": { "best": 129020, "median": 127640, "worst": 126100 },
"overhead_percent": 0.4,
"adapter_overhead_percent": 0.3,
"adapter_verdict": "indistinguishable",
"verdict": "indistinguishable",
"broker_bound": true
}
],
"code": [
{
"name": "consume, JSON decode into a small struct",
"messages": 1000,
"framework": { "instructions": 2839.8, "allocations": 0.0 },
"cold": { "instructions": 19219, "allocations": 26 },
"gated": true
}
]
}