Realisation v1
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
# Quick-checkpoint `20260811-213422`
|
||||
|
||||
Это итоговый engineering quick-checkpoint текущей итерации. Он фиксирует
|
||||
согласованную трёхпрофильную сборку, benchmark-матрицу и проверку адаптации, но не
|
||||
является full-size независимым holdout и не доказывает универсальное превосходство
|
||||
контейнера.
|
||||
|
||||
## Происхождение серии
|
||||
|
||||
- v14 (`20260811-hysteresis-smoke-v14`) проверил завершённый hysteresis на
|
||||
baseline smoke.
|
||||
- v15 (`20260811-policy-quick-v15-hysteresis`) проверил policy на baseline quick;
|
||||
`moderate deferred` стал лучшим из адаптивных вариантов этой серии.
|
||||
- этот run повторил полную quick-матрицу для `scalar`, `baseline` и `avx2` и
|
||||
является основной точкой текущего handoff.
|
||||
|
||||
## Среда и профили сборки
|
||||
|
||||
Среда сохранена в [`environment.json`](environment.json) и
|
||||
[`environment.txt`](environment.txt): AMD Ryzen 9 5900X, Windows 10 Pro 25H2,
|
||||
MSVC 19.51.36248.0 x64, CMake 4.3.1-msvc1, план питания Balanced. Во всех Release
|
||||
целях использованы `/O2`, статический runtime `/MT`, без IPO/LTO (`/GL` не
|
||||
использовался).
|
||||
|
||||
| Профиль | Существенные параметры |
|
||||
|---|---|
|
||||
| `scalar` | `/O2 /d2Qvec- /Qvec-report:1 /Oi-`, без `/arch:AVX*` |
|
||||
| `baseline` | `/O2`, автовекторизация разрешена, без `/arch:AVX*` |
|
||||
| `avx2` | `/O2 /arch:AVX2`, без vectorizer-disable флагов |
|
||||
|
||||
`/d2Qvec-` — внутренний, не документированный публичным контрактом MSVC ключ.
|
||||
Здесь он означает проверенный на зафиксированной версии компилятора
|
||||
project-novec-профиль, но не гарантирует отсутствие всех SIMD-инструкций: x64 ABI,
|
||||
compiler runtime и CRT могут использовать базовый SSE2 или собственный dispatch.
|
||||
|
||||
## Методика
|
||||
|
||||
`benchmark.bat quick` запускал профили последовательно в фиксированном порядке
|
||||
`scalar -> baseline -> avx2`. В каждом профиле suites выполнялись как
|
||||
`tune -> adapt -> compare -> index`:
|
||||
|
||||
- quick использует 5 повторов;
|
||||
- tuning: размеры 10 000, 100 000 и 1 000 000;
|
||||
- comparison: размеры 1 000, 10 000, 100 000 и 1 000 000;
|
||||
- кандидаты одного повтора получают один и тот же заранее материализованный
|
||||
trace; стартовый кандидат циклически меняется между повторами;
|
||||
- analyzer проверяет согласованность checksum для сопоставимых успешных строк;
|
||||
- слишком дорогие комбинации `deque`/`list` могут получить
|
||||
`skipped_cost_guard` и не входят в соответствующую aggregate-ячейку.
|
||||
|
||||
Process affinity/pinning не задавались. Порядок профилей не рандомизировался, а
|
||||
план питания оставался Balanced. Поэтому результаты следует читать как
|
||||
инженерный quick-checkpoint, подверженный drift температуры, частоты и фоновой
|
||||
нагрузки, а не как окончательную публикационную оценку.
|
||||
|
||||
`std::deque` и `std::list` здесь только внешние фиксированные baselines. Они
|
||||
никогда не являются внутренними режимами `AdaptiveSequence`; у `list` измеряется
|
||||
индексная семантика с линейным проходом.
|
||||
|
||||
## Проверка адаптации
|
||||
|
||||
Финальный запуск валидатора прошёл:
|
||||
|
||||
- 282 compare-ячейки;
|
||||
- 48 adapt-ячеек.
|
||||
|
||||
Текстовый итог повторной проверки сохранён в [`validation.txt`](validation.txt).
|
||||
Для всех suites дополнительно проверены результаты одинаковых трасс: расхождений
|
||||
checksum внутри профиля и между `scalar`/`baseline`/`avx2` нет. Полнота raw
|
||||
матрицы: по 1125 строк tune, 800 adapt, 4700 compare и 270 index на профиль;
|
||||
в compare по 225 строк на профиль имеют ожидаемый `skipped_cost_guard`, остальные
|
||||
статусы — `ok`.
|
||||
|
||||
Для короткого negative control допускаются ноль переключений и ноль
|
||||
leaf-rebuilds; для stationary default — не более одного. У явно двухфазной трассы
|
||||
`phase_10_uniform_10_local_80_read` есть две разные edit-фазы. Первоначальный
|
||||
лимит одной leaf-rebuild ошибочно трактовал их как одну фазу; лимит был исправлен
|
||||
до двух только для этой структуры. Измерительные CSV не менялись, и после
|
||||
исправления спецификации валидатор прошёл весь набор. Этот pass доказывает
|
||||
ограниченность transition churn на проверяемых трассах, но сам по себе не
|
||||
доказывает оптимальную производительность policy.
|
||||
|
||||
Проверка выполняется по медианам пяти повторов. В raw compare есть один
|
||||
seed-specific случай `phase_uniform_local_read`, N=1M с тремя leaf-rebuilds;
|
||||
медиана этой ячейки равна двум. Это не stationary churn, но показывает, что
|
||||
следующий holdout должен валидировать не только медианы, а каждый повтор.
|
||||
|
||||
## Основные результаты
|
||||
|
||||
В [`aggregate-compare.csv`](aggregate-compare.csv) score каждой ячейки нормирован
|
||||
по лучшему фиксированному baseline в этой ячейке; выше — лучше.
|
||||
|
||||
| Кандидат | Overall score | Eligible cells |
|
||||
|---|---:|---:|
|
||||
| forced tiered, leaf64 | 0.395052 | 282 |
|
||||
| forced tiered, leaf128 | 0.391598 | 282 |
|
||||
| adaptive deferred | 0.347315 | 282 |
|
||||
| adaptive eager | 0.326839 | 282 |
|
||||
| reserved vector | 0.146329 | 282 |
|
||||
| external deque | 0.080267 | 267 |
|
||||
| external list-index | 0.012763 | 162 |
|
||||
|
||||
`adaptive deferred` превосходит reserved vector в aggregate этой конкретной
|
||||
quick-матрицы, но проигрывает лучшим forced leaf-кандидатам. Победа над лучшим
|
||||
фиксированным oracle или над всеми структурами не доказана.
|
||||
|
||||
В терминах именно aggregate score adaptive выше reserved vector в 2.37 раза,
|
||||
но ниже leaf64 на 12.1% и leaf128 на 11.3%. Это отношения иерархически
|
||||
агрегированных нормированных score, а не прямые коэффициенты ускорения времени.
|
||||
Прямое парное агрегирование времени даёт ту же картину: adaptive быстрее vector
|
||||
примерно в 2.37 раза, но медленнее leaf64 на 13.74% и leaf128 на 12.75%; leaf256
|
||||
он уже опережает на 1.07%.
|
||||
После hysteresis stationary-ячейки имеют не более одного storage switch и одной
|
||||
leaf-rebuild; два переключения/две rebuild встречаются только там, где trace
|
||||
явно содержит burst или две разные edit-фазы. Directory-only rebuild в выбранной
|
||||
policy в этом run не потребовался.
|
||||
|
||||
Главный оставшийся regret — не повторные переключения, а cold adaptation. Для
|
||||
`blob64` и non-trivial string при N=100k policy делает один переход без rebuild,
|
||||
но до него успевает выполнить дорогие O(N) vector edits и затем платит за
|
||||
конвертацию; против заранее подготовленного leaf64 это в среднем примерно 2.45x
|
||||
и 4.03x медленнее соответственно. Есть и противоположная слепая зона:
|
||||
`read_99`, N=1M остаётся vector из-за 5% entry threshold, хотя редкие edits уже
|
||||
достаточно дороги, чтобы fixed tiered выиграл. Следующий вариант policy должен
|
||||
использовать накопленный regret/стоимость edit, а не только их долю.
|
||||
|
||||
В [`aggregate-adapt.csv`](aggregate-adapt.csv) лучшие fixed варианты — leaf128
|
||||
(`0.817859`) и leaf256 (`0.788496`); лучший адаптивный policy `moderate deferred`
|
||||
получил `0.216999`. Adapt-сценарии остаются главным источником regret.
|
||||
При этом на длинной exact phase moderate примерно в 11.1 раза быстрее vector,
|
||||
но всё ещё в 5.27 раза медленнее заранее tiered oracle; на коротком negative
|
||||
control ложных переходов нет, а цена сбора статистики составляет около 8.5%.
|
||||
|
||||
Tuning выбрал leaf128 как сильнейший quick-кандидат во всех трёх профилях:
|
||||
|
||||
| Профиль | Лучшие параметры | Score |
|
||||
|---|---|---:|
|
||||
| scalar | leaf128, levels4 | 0.878968 |
|
||||
| baseline | leaf128, levels3 | 0.873461 |
|
||||
| avx2 | leaf128, levels3 | 0.887906 |
|
||||
|
||||
Это выбор для измеренной матрицы, а не универсальная константа. Index-suite также
|
||||
показал большой выигрыш специализированного flat hash index над линейным lookup
|
||||
vector, но только в lookup-подзадаче и ценой дополнительной памяти; переносить
|
||||
этот вывод на контейнер целиком нельзя.
|
||||
|
||||
Лучший единый tuning-компромисс трёх профилей — `leaf=128, fanout=64,
|
||||
levels=3`; вариант с `levels=4` отстал по cross-profile score всего на 0.276%,
|
||||
поэтому точную глубину пока нельзя считать надёжно определённой. Leaf, напротив,
|
||||
устойчивее: 14 из 15 логических tuning-ячеек выбрали одинаковый leaf во всех
|
||||
профилях. Random access всегда предпочёл 1024, большинство edit/mixed-ячеек —
|
||||
64, а localized edit при N=1M — 128.
|
||||
|
||||
AVX2 не дал общего выигрыша для контейнерного mix: для tuning-конфига 128/64/3
|
||||
AVX2 и baseline различались лишь на 0.26% по cellwise geometric mean. На compare
|
||||
AVX2 ускорил reserved vector примерно на 8.9%, но fixed tiered — только на
|
||||
2–3%, а adaptive deferred оказался на 0.9% медленнее baseline. Порядок профилей
|
||||
не рандомизирован, поэтому проценты следует считать инженерным сигналом, а не
|
||||
изолированным доказательством эффекта SIMD.
|
||||
|
||||
Отдельно отмечен устойчивый codegen outlier: AVX2 adaptive-deferred sequential
|
||||
`uint32` во всех четырёх N оказался в 1.85–1.98 раза медленнее baseline во всех
|
||||
пяти повторах, при совпадающих checksums. До профилирования generated code это
|
||||
нельзя объяснять как общий недостаток AVX2 или как шум одной выборки.
|
||||
|
||||
Hash index выиграл у linear lookup во всех 27 проверенных index-ячейках, но его
|
||||
геометрическое среднее потребление памяти составило 9.26x от payload vector
|
||||
(диапазон 7.00x–17.49x). Экстремальные коэффициенты скорости неустойчивы: при
|
||||
N=1M выполнялось только 50 запросов, построение индекса не входило в таймер, а
|
||||
свежепостроенный hash был cache-hot. Поэтому этот suite подтверждает пользу
|
||||
опционального индекса качественно, но не является точной оценкой production
|
||||
ускорения.
|
||||
|
||||
## Артефакты и provenance
|
||||
|
||||
- `*-raw.csv` — отдельные измерения;
|
||||
- `*-summary.csv` — summary внутри профиля;
|
||||
- `aggregate-*.csv` и `cell-medians-*.csv` — объединённые результаты;
|
||||
- `environment.json` / `environment.txt` — машина, toolchain, флаги и порядок
|
||||
профилей;
|
||||
- [`source-manifest.sha256`](source-manifest.sha256) — 23 файла workspace на
|
||||
момент запуска;
|
||||
- [`binary-manifest.sha256`](binary-manifest.sha256) — 9 измерявшихся EXE
|
||||
(`uc_demo`, `uc_tests`, `uc_bench` для трёх профилей).
|
||||
|
||||
В metadata нет Git HEAD, а workspace на момент запуска имел 12 dirty entries,
|
||||
поэтому manifests — основной источник provenance. Они являются неизменяемым
|
||||
снимком именно момента измерения. После run были дополнены `docs/findings.md` и
|
||||
исправлена только спецификация лимита в `tools/validate_adaptation.ps1`; это два
|
||||
текущих расхождения с source manifest. C++-исходники и все девять Release EXE
|
||||
по-прежнему совпадают со снимком. Манифесты намеренно не пересоздаются задним
|
||||
числом.
|
||||
|
||||
## Ограничения
|
||||
|
||||
- это quick с пятью повторами, не full и не независимый multi-seed holdout;
|
||||
- нет pinning/affinity, фиксированного high-performance power plan и
|
||||
рандомизированного порядка профилей;
|
||||
- segmented backend пока одноуровневый prototype, а не завершённая
|
||||
многоуровневая структура;
|
||||
- policy всё ещё заметно уступает лучшему fixed leaf oracle на adapt workloads;
|
||||
- память учитывается в benchmark, но для окончательного вывода нужен отдельный
|
||||
контролируемый memory-budget experiment;
|
||||
- `deque`/`list` — внешние baselines с cost-guard пропусками, а не альтернативные
|
||||
режимы адаптивного контейнера.
|
||||
Reference in New Issue
Block a user