Files
UniversalContainer/docs/benchmarking.md
T
2026-08-13 23:42:26 +03:00

138 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Сборка и benchmark-методика
## Активная focused-постановка
Текущий benchmark отвечает на один практический вопрос: при каком `N` для
фиксированной малой доли правок становится выгодно переходить от contiguous
vector к tiered storage. Старую широкую матрицу типов, SIMD-профилей, leaf и
workload для этой калибровки не используют.
Все три кандидата имеют один и тот же тип данных и один и тот же flat hash:
| Имя в CSV | Реализация | Режим |
|---|---|---|
| `forced_vector_hash` | `AdaptiveSequence<uint32_t, true>` | принудительно vector |
| `forced_tiered_hash` | `AdaptiveSequence<uint32_t, true>` | принудительно tiered |
| `adaptive_hash` | `AdaptiveSequence<uint32_t, true>` | текущая resize-bound auto-policy |
Таким образом, поиск по значению не даёт одному кандидату скрытого преимущества:
стоимость хранения и обновления hash index присутствует у vector, tiered и
adaptive. Для forced tiered начальный leaf равен `ceil(sqrt(N))`. Auto-mode
выбирает mode и leaf только при capacity-boundary.
## Трасса
Mixed trace содержит ровно 100000 операций в default-запуске:
| Операция | Доля | Default count | Детали |
|---|---:|---:|---|
| индексное чтение | 97% | 97000 | случайный существующий индекс |
| hash find по значению | 1% | 1000 | `find_one`, 50% hit / 50% miss |
| вставка | 1% | 1000 | случайная позиция |
| удаление | 1% | 1000 | случайная существующая позиция |
Виды операций перемешиваются детерминированным seed. Вставки и удаления
сбалансированы, поэтому benchmark измеряет steady-size workload, но любая
реально достигнутая capacity-boundary и стоимость перехода остаются внутри
mixed timer. Построение исходного контейнера находится вне timer.
Кроме общей `mixed ops/s`, runner измеряет отдельные homogeneous batches и
выводит `read ops/s`, `find ops/s`, `insert ops/s`, `erase ops/s`. Быстрые read
и find batches содержат не менее 100000 вызовов для устойчивости таймера;
фактические batch counts записываются в CSV. Поэтому отдельные колонки — это
пропускная способность соответствующего типа операции, а не время его 1%-доли
в mixed trace.
Один и тот же материализованный trace и seed применяются к трём кандидатам.
Порядок кандидатов циклически меняется между paired repeats, чтобы фиксированная
первая или последняя позиция не принадлежала всегда одному представлению.
Checksum проверяет совпадение состояния и результатов операций.
## Capacity, leaf и hash во время измерения
Focused benchmark проверяет текущий контракт контейнера, а не внешнюю
эмуляцию:
- capacity увеличивается `x2`, когда очередная вставка не помещается;
- при `size <= capacity / 8` выполняется один shrink-шаг `capacity / 2`;
- mode и `leaf = ceil(sqrt(size))` пересчитываются только внутри этой
capacity-перестройки;
- focused cutoff auto-mode равен 4096;
- hash buckets рассчитываются из новой логической capacity с worst-case load
не выше 70% и не меняются независимо между capacity-boundaries.
Raw CSV сохраняет initial/final mode, leaf и logical capacity mixed-контейнера,
что позволяет увидеть включённый в mixed throughput переход `vector -> tiered`
или обратный переход. Для четырёх отдельных homogeneous batches поля
`read_mode`, `find_mode`, `insert_mode`, `erase_mode` и соответствующие
`*_leaf` отдельно фиксируют их фактический режим/геометрию; эти batches
стартуют с новых контейнеров и потому не обязаны повторять final mode/leaf
mixed-трассы.
## Воспроизводимый default-run
Из обычной командной строки Windows:
```bat
benchmark.bat
```
Скрипт выполняет ровно один focused-run:
1. `build.bat baseline test` — Release x64 `/O2`, `/MT`, без `/arch:AVX*` и
без IPO/LTO, затем correctness-тесты.
2. Создаёт `results\benchmarks\<timestamp>-focused\` и записывает metadata и
source/binary manifests.
3. Запускает `uc_focused_bench` для степеней двойки `N=256...65536`, 100000
mixed operations и 7 paired repeats.
4. Печатает таблицу медиан operations/second, сохраняет её в `summary.md`, а
raw repeat data — в `baseline-focused.csv`.
Эквивалентный вызов runner после сборки:
```bat
out\bin\baseline\Release\uc_focused_bench.exe --min-n 256 --max-n 65536 --operations 100000 --repeats 7 --output results\benchmarks\focused.csv
```
`--operations` должен быть положительным числом, кратным 100. Доступны также
`--seed`, `--min-n` и `--max-n`; границы диапазона округляются до степеней
двойки.
Финальную таблицу следует публиковать в каталоге соответствующего запуска в
`results/benchmarks/`. Документация хранит только постановку и подтверждённые
выводы, а не копию ещё незавершённой серии.
## CSV
Каждая raw-строка содержит:
- `profile`, `n`, `container`, `repeat`, `seed`;
- initial/final mixed `mode`, `leaf`, `logical_capacity` и отдельные mode/leaf
поля read/find/insert/erase batches;
- mixed counts, включая hit/miss hash find;
- реальные размеры отдельных read/find/insert/erase batches;
- `mixed_ops_per_sec`, `read_ops_per_sec`, `find_ops_per_sec`,
`insert_ops_per_sec`, `erase_ops_per_sec`;
- оценку allocated bytes и checksum.
Публикуемая таблица использует медиану семи повторов по каждой паре
`(N, container)`. Значения отдельных повторов не отбрасываются и остаются в
raw CSV.
## Historical / retired benchmark matrix
Старый `uc_bench`, вызовы `benchmark.bat smoke|quick|full`, multi-profile
сравнение `scalar/baseline/avx2`, типы от `uint32_t` до blob/string wrapper,
fixed leaf 64...1024, `std::deque`, `std::list`, phase traces и
`large_benchmark.bat` до N=100M относятся к **historical / retired** методике.
Их CSV сохранены для аудита истории проекта, но не участвуют в выборе текущего
cutoff: набор кандидатов, mix операций и наличие hash index отличаются от
focused постановки. Старые aggregate scores и speedup нельзя смешивать с новой
таблицей operations/second.
Профили `scalar` и `avx2` по-прежнему можно собирать для отдельных инженерных
экспериментов. `scalar` использует внутренний MSVC `/d2Qvec-` и не является
универсальной гарантией отсутствия SIMD в CRT/ABI; это ещё одна причина не
расширять текущий baseline-run до старой матрицы без отдельной задачи.