Эта страница переведена с английского языковой моделью. При любом расхождении верен английский оригинал.
Методология
Как ruststream-gcp-pubsub измеряет себя: три цикла, прогон на эмуляторе, арифметика упора в
брокер и подсчёт кода. Процедура принадлежит самому фреймворку
(методология RustStream),
а эта страница говорит, какой она получается на Pub/Sub.
Три цикла
Один процесс выполняет каждый сценарий тремя циклами, и различаются они ровно одним: тем, что несёт сообщения.
- Сырой клиент. Цикл, написанный руками, работает прямо с
google-cloud-pubsub. - Крейт брокера. Этот крейт и ничего выше: его подписка, доставки, которые она отдаёт, и его издатель, а читает и подтверждает их цикл, вокруг которого нет никакого сервиса.
- RustStream. Сервис, который пишет пользователь: обработчик
#[subscriber], приложение и рантайм.
Всё остальное у трёх циклов одинаково: адрес и учётные данные, топология, параметры streaming pull, место подтверждения (ack), декодирование в тот же тип, байты тела, рантайм tokio и сборка.
Все числа сняты на локальном эмуляторе, который поднимает docker-compose.test.yml, и ни одно из
них - на облачном сервисе.
Прогон
- Окно открывается на первой доставке и закрывается, когда подтверждена последняя, одинаково у всех циклов.
- Число сообщений подбирает пробный прогон, так чтобы каждый измеряемый прогон длился не меньше пяти секунд на той машине, где его снимают.
- Циклы чередуются, три круга. Каждый цикл сообщает лучший, медианный и худший круг.
Строка получает отметку «упирается в брокер», когда её темп задавал эмулятор. Отметка выводится арифметикой: проба вне кругов замеряет один круговой путь до эмулятора, доставке засчитывается один такой путь на подтверждение, и строка помечается, когда это произведение покрывает хотя бы половину времени одного сообщения. Круговой путь опубликован вместе с машиной, так что арифметику можно проверить.
Подсчёт кода
Каждый сценарий графика стоимости - сервис в том виде, в каком его
пишет пользователь: он построен на PubSubBroker и запущен против эмулятора того же стенда.
Сервис работает в одном потоке, и в счёт идёт всё, что в этом потоке делается: диспетчеризация
фреймворка, код этого крейта и клиент google-cloud-pubsub, у которого там же работают streaming
pull, подтверждения, продление сроков подтверждения и запросы на публикацию. Эмулятор - отдельный
процесс, и в число он не входит. Сообщения публикуются из другого потока до начала разбора
очереди, и эта работа в число тоже не входит.
Инструкции считает callgrind, выделения памяти - DHAT. И те и другие даны на сообщение в установившемся режиме: это наклон между прогоном на 1000 доставок и прогоном на 2000. Холодный старт - то, во что один раз обошлись запуск сервиса и первая доставка.
Клиент подтверждает сообщения пакетами и продлевает сроки подтверждения по таймерам, поэтому от
прогона к прогону подсчёт немного плавает: за пять прогонов инструкции на сообщение совпали с
точностью до 5 процентов, а выделения памяти в самом длинном прогоне - с точностью до 3500 в строке
ответа и до 440 в двух других. just bench-code падает, если выделений больше порога, объявленного
сценарием: это наибольший увиденный подсчёт плюс запас не меньше этого разброса и не меньше
десятой доли процента. С --baseline=main он падает ещё и на приросте инструкций больше двух
процентов. Запрос на слияние, который меняет цену, приводит свои числа.
Как запустить самому
just bench
Рецепт поднимает эмулятор из docker-compose.test.yml, прогоняет оба сценария, гасит его и
переписывает docs/benchmarks/results.json тем, что намерил. Это занимает несколько минут и
требует машину целиком. Рецепт очищает RUSTFLAGS, поэтому бинарник не привязан к процессору, на
котором его собрали. Оба рецепта собирают замеры так же, как собирается выпуск: с полной
оптимизацией при компоновке через границы крейтов. Поэтому числа описывают тот код, который
получает сервис.
just bench-code
Рецепт поднимает эмулятор, подсчитывает график кода под valgrind, снова гасит эмулятор и
переписывает раздел code того же документа. Это занимает несколько минут. Кроме Docker, ему нужен
valgrind. Исполнитель бенчмарков должен быть того же выпуска gungraun, что закреплён в
Cargo.lock: рецепт сам ставит его в target/ при первом запуске и снова, когда выпуск меняется.
Число после имени рецепта задаёт, сколько доставок в измеряемом прогоне (just bench-code 500).
Опубликованные числа сняты при значении по умолчанию, 1000. Остальные аргументы уходят
исполнителю бенчмарков, например --save-baseline=main или --baseline=main. Прогон, который
превысил предел, всё равно проходит все сценарии и печатает таблицу. Под ней он перечисляет каждый
превышенный предел: значение, с которым сравнивали, и рядом новое. После этого прогон завершается
ошибкой.