kdsl — техническое описание
1. Назначение и идея
kdsl — компилятор-DSL уровня Halide для генерации высокопроизводительных числовых ядер из ОДНОГО декларативного описания в несколько бэкендов (ISPC / CUDA / SPIR-V) с проверкой числовой эквивалентности результата (diff=0 на целочисленных входах, относительный допуск на fp).
Ключевая идея — реификация: и алгоритм, и расписание
(schedule), и стратегия переписывания — это ОДНИ И ТЕ ЖЕ данные,
«green-AST» (по аналогии с green-tree из Roslyn: неизменяемые узлы
Rc<Node> с тегом, типизированными атрибутами и
детьми; сериализуются 1:1 в JSON).
«Green-AST» здесь — это: - неизменяемое дерево; любое переписывание
создаёт НОВЫЕ узлы со свежим stamp; - неизменённые
поддеревья делятся по Rc и сохраняют свой
stamp → occurrence-identity: один и тот же
вход в дереве остаётся «тем же» после fuse/lower (демо показывает
Input 41->41 PASS, stamp 66 на обоих
операндах x·x).
Конвейер: текст (гомоиконный фронт) → reader → green-AST →
стратегические rewrites (apply, rules-as-data: правило fuse
само ПАРСИТСЯ из текста и переписывает дерево) → mid-IR (функциональный
тензор-операторный IR, «талия песочных часов») → пер-бэкендная
кодогенерация (демо «FUNCTOR-AS-DATA closed»).
Зачем своё, а не Halide/TVM: декларируется как суверенный субстрат под Eidos — паритет research↔︎live (одно дерево гоняется и в бэктесте на десктопе через CUDA, и в проде на CX53 через ISPC), и бэкенды как взаимные оракулы корректности (числовой баг должен одновременно обмануть все пути). Это ДЕКЛАРИРУЕМАЯ цель/амбиция, а не достигнутый продакшн — см. §5.
2. Архитектура
Компоненты (модули основного крейта, ~8200 строк Rust):
- Reader — рукописный парсер гомоиконного текстового фронта в green-AST (матрицы, диапазоны, типы; интернинг тегов; присвоение stamp).
- Ядро (~2800 строк) — тип
Node/Attr, IR-bridge, три бэкенда (IspcBackend,CudaBackend,SpirvBackend), Rust-оракулы, и большойmain()с ~13 демо, которые реально компилируют и запускают ядра. - Mid-IR: операторный словарь (Elementwise / Reduce /
RollingReduce / Stencil / Contraction / Ewma / Quantile),
lower_to_ir, dtype + accum_dtype как атрибуты первого класса. Это «талия»: бэкенды единообразно ОБХОДЯТ один IR, а не матчат теги ядер. - Система типов/форм — локальная синтезируемая
атрибутная грамматика (demand-eval overlay по stamp), shape inference
БЕЗ Хиндли-Милнера. Работает в демо:
shape(Elementwise): [1000] PASS, dtype carriage f32/f64. - Гигиена идентификаторов — пер-таргетная
(reserved-word таблицы ISPC/CUDA/Rust/SPIR-V + идемпотентный
sanitize). Data-driven. 19 тестов. - Импортёр — втягивание чужой поверхности имён (Rust-крейт через rustdoc-JSON) в green-AST как биндинг-манифест; рукописный zero-dep JSON-парсер (чтобы дефолтная сборка не тянула serde). Реально импортирует поверхность datafusion 53.1.0 + arrow/parquet 58.3.0, валидирует версии. 19 тестов.
- Program-tier — experiment-IR (scan/filter/ project/groupby/window/sweep) → генерация ЦЕЛОГО Rust-крейта, который обвязывает DataFusion (data-plane) и зовёт kdsl-ядра через C-ABI.
- Крейт SPIR-V (~930 строк Rust) — отдельный крейт:
эмиссия SPIR-V через
rspirv(строитVec<u32>) + запуск черезash(Vulkan compute). Подключён ОПЦИОНАЛЬНО через--features spirv; дефолтная сборка остаётся zero-dep.
Зависимости: дефолтная сборка имеет НОЛЬ внешних крейтов — фронт это просто типизированные данные, «монстры» (ispc/gcc/nvcc) вызываются через shell внизу. SPIR-V (ash/rspirv) и program-tier (datafusion/arrow) — опциональны.
3. Уровень реализации по бэкендам
ISPC (процессор, AVX2/AVX-512)
Статус: рабочий, самый глубокий.
Компилит через ispc+gcc, запускает.
Покрывает ВЕСЬ первичный семейный фронт D2: sum-of-squares, rolling-sum,
variance (single-pass, f64 accum), EWMA (рекурсивный, runtime α),
z-score (two-pass), quantile (sort+type-7), стенсил, контракция. Все
diff=0 / в пределах fp-допуска.
CUDA (видеокарта NVIDIA)
Статус: рабочий, подмножество.
Самодостаточный .cu → nvcc sm_89 → запуск
на RTX 4060 Ti. fp32-baseline для sum-sq, rolling-sum, стенсил,
контракция; WMMA-тензор (fp16/f32 + fp64 m8n8k4) с runtime-выбором
точности. Все diff=0. НЕ покрывает variance/EWMA/z-score/quantile (это
пока только ISPC).
SPIR-V (Vulkan compute)
Статус: двойственный — текстовый стаб по умолчанию + рабочий путь под feature-флагом.
В дефолтной сборке SpirvBackend в списке бэкендов —
ТЕКСТОВЫЙ СТАБ (runnable:false, печатает
«stub (in tree, not yet wired)»). Реальный путь под
--features spirv — отдельный шов
spirv_seam::emit_run_ir через ash/rspirv (параллельный
in-process, не через текстовый trait). Запущен на RTX 4060 Ti — diff=0
PASS на Reduce∘Stencil и Reduce∘Contraction. Покрывает ТОЛЬКО эти два
(sum-reduce), не весь D2-фронт.
Граница готовности (gap-анализ, дословно): «backend parity — SPIR-V only does sum-reduce; WMMA dims fixed; not every kernel on every backend» — это НЕЗАВЕРШЁННая дорожка. То есть полного паритета «каждое ядро на каждом бэкенде» ПОКА НЕТ.
Заглушки/границы (по panic!/stub): -
SpirvBackend::emit_ir (текстовый trait) — стаб,
runnable:false. - Расписания (schedule axis) — НЕ
реализованы (только спроектированы как rules-as-data). Это и есть
главная заявленная цель Halide-класса — её ещё нет. - Program-tier
Split (purged-CV) — намеренно panic!-арм
(demand-driven hold). - Множество panic! — это не TODO, а
fail-fast на неподдержанных узлах IR / нарушении контрактов (например
«v0 kernel contract: input column must be non-null»). - НЕ найдено ни
одного todo!()/unimplemented!().
4. Тесты и diff=0
- Юнит-тесты: 56 passed, 0 failed
(
cargo test --release, дефолтная сборка zero-dep, ~0.00s). Распределение: main 30, importer 19, idents 19, expir 9 (часть дублируется в счётчике), reader/emit_program по 2. Тесты проверяют IR/оракулы, форму/типы, гигиену имён, round-trip JSON, импортёр и дрейф версий. - Кросс-бэкендный diff=0 — это НЕ юнит-тесты, а демо в
main(): они реально shell-ят ispc/nvcc, компилируют и запускают, сверяя с Rust-оракулом. Бинарь запущен на хосте с ispc, nvcc и RTX 4060 Ti — все ISPC и CUDA демо PASS, diff=0 (целочисленные), variance/EWMA/z-score в пределах fp-допуска (rel ~1e-8…1e-16). - При отсутствии тулчейна демо gracefully skip («toolchain unavailable — skipped»), а не падают — честный паттерн.
- SPIR-V diff=0: в ДЕФОЛТНОЙ сборке SPIR-V-демо
skipped (текстовый стаб). Но при пересборке с
--features spirvреальный путь (ash+rspirv, Vulkan compute на RTX 4060 Ti) ОТРАБОТАЛ diff=0:spirv backend compiled in: true,spirv(stencil) got=-162 PASS,spirv(contract) got=16 PASS. - Program-tier реально собирался и гонялся на РЕАЛЬНЫХ данных: IC-sweep над HL buckets_5s (1 день, 20 монет), сверка с polars/L2 до 6 знаков, max abs err = 0.0 на 169k строк.
5. Зрелость — честный вердикт
Это продвинутый research-прототип / частично рабочий компилятор, НЕ зрелый продакшн.
Где проходит граница: - «Идея есть» — реификация algorithm/schedule/strategy как green-AST: РЕАЛИЗОВАНА для algorithm и strategy (rules-as-data, occurrence-identity, mid-IR). Schedule как данные — только спроектирован, НЕ построен. - «Работает на демо» — ДА, и убедительно: ISPC покрывает весь D2-фронт, CUDA — подмножество + тензор-ядра, кросс-бэкенд diff=0 реально исполняется, program-tier генерит собираемый крейт и прогнан на реальных данных. - «Production» — НЕТ. Нет: schedule-оси (главной Halide-фишки), полного паритета бэкендов (SPIR-V = sum-reduce only, текстовый стаб в дефолте; WMMA фикс-размеры), бенчмарков/cost-данных (Phase B не начата — корректность есть, скорости нет), artifact-кэша, LSP/диагностик, round-trip lens. Сам проект декларирует амбицию «production only», но это ЦЕЛЬ, а текущее состояние — фундамент (Phase A).
Объём (tokei, без target): - Основной крейт: 25 .rs файлов, 8233 строки кода Rust (+452 коммент, +468 пустых). - Крейт SPIR-V: 4 .rs, 933 строки кода. - Сгенерированные демо-крейты: по 170–350 строк каждый — это ВЫХОД компилятора, не ручной код. - Документация: 10 .md, ~1700 строк проектных решений/планов (необычно подробный ADR-лог).
Замечание для собеседования: проектный манифест написан очень амбициозно (рефлексивные башни, проекции Футамуры, «язык, на котором числовая работа сказана однажды, проверена четырежды, развёрнута везде»). Это roadmap, НЕ описание готового. Реальный код существенно скромнее и аккуратнее заявлений — на это стоит указать самому.
6. Навыки, которые проект демонстрирует
- Компиляторы / кодогенерация: проектирование mid-IR (функциональный тензор-операторный, hourglass-waist), nanopass-lowering, генерация исходников под 3 целевых языка, гигиена идентификаторов под reserved-words таргета.
- GPU / параллелизм: CUDA (fp32 + WMMA тензор-ядра, atomicAdd-редукции, sm_89), SPIR-V/Vulkan compute через ash+rspirv (ручная сборка SPIR-V байткода), ISPC (SPMD/AVX векторизация).
- Идеи Halide / полиэдральной оптимизации: явное разделение algorithm ⟂ schedule, rules-as-data rewriting (ELEVATE/Stratego-подобный субстрат), осознанный отказ от loop-nest/полиэдрального IR в пользу операторного (с обоснованием в ADR).
- Системы типов: атрибутные грамматики (JastAdd/Knuth-стиль), demand-eval + мемоизация по stable-identity, shape/dtype inference без unification.
- Перформанс-инжиниринг численного кода: f32-данные + f64-аккумуляторы, single-pass variance, рекурсивный EWMA, exact-quantile, контроль точности fp.
- Дисциплина корректности: дифференциальное тестирование (бэкенды как взаимные оракулы), bitwise-diff=0 на целых, occurrence-identity для отслеживания общих подвыражений, graceful-degradation при отсутствии тулчейна.
- Гомоиконность / метапрограммирование: код-как-данные, правила переписывания, парсящиеся из текста; импорт чужого API как данных (rustdoc-JSON → green-AST).
- Инженерная гигиена: zero-dependency дефолтная сборка, feature-gating тяжёлых зависимостей, подробный ADR-лог решений.
Контакты
- Email: splinter.rat.pro@gmail.com
- Телефон: +7 (999) 815-22-92
- Telegram: @Splinter_Rat