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 и сохраняют свой stampoccurrence-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):

Зависимости: дефолтная сборка имеет НОЛЬ внешних крейтов — фронт это просто типизированные данные, «монстры» (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)

Статус: рабочий, подмножество.

Самодостаточный .cunvcc 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


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. Навыки, которые проект демонстрирует


Контакты

Гура Денис

Приложения