Компиляторы
DSL компиляторы
PostgreSQL выполнял запрос за 185 секунд. DuckDB тот же запрос за 3 секунды. Разница - компиляция SQL в нативный код через LLVM вместо интерпретации плана. В играх - shader compilation stutter из-за компиляции GLSL в GPU ISA при первом рендере. В DevOps - Dhall компилирует типизированные конфигурации в JSON предотвращая ошибки до деплоя. DSL компиляторы - это специализированные решения которые меняют что вообще возможно в своём домене.
- **DuckDB** (in-process OLAP): компилирует SQL expressions через LLVM и генерирует SIMD-векторизованный код; 60x быстрее PostgreSQL для аналитических запросов на ноутбуке
- **Apple Metal**: шейдеры компилируются в AIR во время сборки Xcode проекта - не в рантайме. Это устраняет shader compilation stutter который есть в Vulkan/OpenGL играх
- **ClickHouse GROUP BY JIT**: первый запрос компилирует агрегационный код через LLVM; последующие запросы с тем же паттерном используют скомпилированный код с 5-10x speedup
Query Engines и compilation
Традиционные query engines (Volcano/Iterator model) интерпретируют план запроса: каждый оператор (Scan, Join, Aggregate) реализует `next()` метод, данные текут через цепочку операторов. Overhead на каждый кортеж: виртуальные вызовы, branch mispredictions, cache misses. Компилирующие движки (Hyper, DuckDB, LLVM-based) генерируют нативный код для всего pipeline запроса.
DuckDB использует Push-based execution с компиляцией через вставку кода операторов в общий pipeline. Velox (Meta, 2022) - векторизованный execution engine используемый в Presto и Spark, компилирует выражения через LLVM JIT. ClickHouse компилирует GROUP BY агрегации через LLVM в рантайме: первый запрос медленнее, последующие до 10x быстрее.
Почему компилирующий query engine быстрее Volcano-model?
SQL Компиляция: от AST до нативного кода
SQL компиляция: SQL строка -> лексер/парсер -> AST -> semantic analysis (типы, таблицы) -> logical plan -> optimizer (pushdown, join ordering) -> physical plan -> code generation (LLVM IR или code templates). Optimizer - самая сложная часть: поиск оптимального plana NP-hard для N join'ов.
PostgreSQL 11+ включает JIT компиляцию через LLVM для тяжёлых запросов: expressions, aggregation functions, tuple deforming. Включается автоматически при cost > jit_above_cost (100000). Apache Arrow Flight SQL - протокол для передачи скомпилированных query plans между движками. Calcite (Apache) - фреймворк для написания SQL оптимизаторов используемый в Hive, Flink, Drill.
Почему оптимизация JOIN ordering в SQL оптимизаторе является NP-hard задачей?
Shader Compilers
Shader compiler транслирует GLSL/HLSL/Metal Shading Language в GPU ISA (AMD GCN, NVIDIA SASS, Intel EU ISA). Pipeline: source -> frontend (Clang для Metal/HLSL) -> SPIR-V (стандартный промежуточный формат) -> vendor backend -> GPU binary. Шейдеры компилируются при первом использовании что вызывает stuttering.
Shader compilation stutter - известная проблема в играх: Cyberpunk 2077 при релизе компилировал шейдеры во время gameplay. Решения: Pipeline State Object cache (DirectX 12), Metal shader precompilation (Apple), Vulkan pipeline cache. Apple Metal через Xcode компилирует Metal шейдеры в AIR (Apple Intermediate Representation) при сборке приложения, избегая runtime компиляцию.
Зачем нужен промежуточный формат SPIR-V между GLSL и GPU ISA?
Конфигурационные языки и компиляция
Конфигурационные DSL (Dhall, CUE, Jsonnet, Nix) - языки с системами типов, компиляцией в JSON/YAML и guarantees корректности. Dhall полностью детерминирован и total: нет IO, нет бесконечных циклов, всегда завершается. Это делает возможным статическую верификацию конфигурации перед деплоем.
Dhall используется в Tweag (функциональное консалтинговое агентство) для генерации Kubernetes YAML: типовая система Dhall предотвращает ошибки в конфигурации до деплоя. Pulumi (Infrastructure as Code) использует TypeScript/Python как DSL с полноценным type checking. HashiCorp Sentinel - policy language компилируемый в bytecode для Terraform/Vault access policies.
DSL компиляторы всегда проще компиляторов общего назначения
DSL компиляторы часто содержат domain-специфическую сложность: SQL оптимизатор (NP-hard join ordering), shader compiler (vendor GPU ISA), конфигурационный язык (totality checking) - каждый требует глубокой domain expertise
SQL оптимизатор в PostgreSQL - ~100,000 строк кода. GLSL компилятор Mesa3D - ~200,000 строк. Nix evaluator сложнее многих general-purpose интерпретаторов. Domain constraints создают специфическую сложность которой нет в компиляторах общего назначения
Чем Dhall отличается от JSON/YAML как конфигурационный язык?
Итоги
- Query engines: компилированный pipeline (DuckDB, Hyper) устраняет virtual dispatch и даёт SIMD векторизацию - 10-100x быстрее Volcano model для аналитических запросов
- Shader compilers: GLSL/HLSL -> SPIR-V (vendor-neutral IR) -> GPU ISA; shader stutter из-за runtime компиляции решается через pipeline cache и precompilation
- Config DSL (Dhall, CUE): типовая система + totality гарантия позволяют верифицировать конфигурацию статически до деплоя
Связанные темы
DSL компиляторы применяют компиляторные техники в специализированных доменах:
- MLIR — MLIR используется в ML компиляторах как domain-specific IR; подход аналогичен SPIR-V для GPU
- JIT-компиляция основы — ClickHouse и DuckDB применяют JIT компиляцию SQL во время выполнения запроса
- LLVM инфраструктура — PostgreSQL JIT, DuckDB, ClickHouse используют LLVM как backend для SQL компиляции
Вопросы для размышления
- DuckDB компилирует SQL через LLVM. При каких размерах данных overhead на компиляцию (100ms) перестаёт окупаться выигрышем от нативного кода?
- Shader compilation stutter можно устранить precompilation. Но шейдеры часто параметризованы (материалы, освещение). Как игровые движки справляются с комбинаторным взрывом вариантов шейдеров?
- Dhall гарантирует завершение (totality). Какие вычисления это делает невозможными? Что не выразимо в Dhall что возможно в Turing-complete конфигурации?