# Сборка и benchmark-методика ## Активная focused-постановка Текущий benchmark отвечает на один практический вопрос: при каком `N` для фиксированной малой доли правок становится выгодно переходить от contiguous vector к tiered storage. Старую широкую матрицу типов, SIMD-профилей, leaf и workload для этой калибровки не используют. Все три кандидата имеют один и тот же тип данных и один и тот же flat hash: | Имя в CSV | Реализация | Режим | |---|---|---| | `forced_vector_hash` | `AdaptiveSequence` | принудительно vector | | `forced_tiered_hash` | `AdaptiveSequence` | принудительно tiered | | `adaptive_hash` | `AdaptiveSequence` | текущая 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\-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 до старой матрицы без отдельной задачи.