Профилирование компиляции

## Метрики компиляции Профилирование компиляции в SWC начинается с определения набора метрик, отражающих поведение трансформации исходного кода. Основные показатели включают: * общее время компиляции проекта; * время обработки одного файла; * пропускная способность (файлов/сек); * использование памяти во время трансформации; * накладные расходы конкретных трансформеров; * влияние кеширования на повторные сборки. SWC как компилятор на Rust отличается высокой скоростью выполнения, однако в реальных проектах производительность определяется не только ядром трансформации, но и интеграцией с инструментами сборки, конфигурацией и набором включённых плагинов. ## Базовое измерение времени компиляции Наиболее прямой способ профилирования — измерение времени выполнения CLI-команды. Пример базовой конфигурации: ```bash time swc src -d dist ``` Результат фиксирует: * `real` — фактическое время выполнения; * `user` — процессорное время пользовательского кода; * `sys` — системные вызовы. При повторных запусках можно выявить влияние файлового кеша операционной системы и внутренних оптимизаций SWC. Более точное измерение выполняется через многократный прогон: ```bash for i in {1..10}; do time swc src -d dist > /dev/null done ``` Стабилизация результатов после первых запусков часто связана с прогревом дискового кеша и JIT-оптимизациями окружения Node.js, если SWC используется через обёртки. ## Профилирование через Node.js API При использовании SWC как библиотеки измерение времени компиляции выполняется на уровне кода: ```javascript import { transformFile } from "@swc/core"; console.time("swc"); await transformFile("input.js", { jsc: { parser: { syntax: "ecmascript" }, transform: {} } }); console.timeEnd("swc"); ``` Дополнительная детализация достигается разбиением на этапы: ```javascript console.time("parse"); console.time("transform"); console.time("print"); await transformFile("input.js", config); console.timeEnd("parse"); console.timeEnd("transform"); console.timeEnd("print"); ``` Хотя SWC не предоставляет прямых хуков для раздельного измерения фаз, подобная декомпозиция возможна через собственные обёртки или кастомные плагины. ## Анализ производительности трансформеров SWC использует модульную систему трансформаций, где каждый `jsc.transform` влияет на итоговое время сборки. Профилирование выполняется через изоляцию отдельных трансформеров. Пример конфигурации: ```javascript { jsc: { transform: { react: { runtime: "automatic" }, optimizer: {}, legacyDecorator: true } } } ``` Методика измерения: 1. Базовая компиляция без трансформаций. 2. Постепенное включение отдельных модулей. 3. Сравнение разницы во времени. Разница между конфигурациями позволяет определить стоимость каждого этапа трансформации AST. Особенно затратными являются: * преобразование JSX в сложных компонентах; * работа с декораторами; * оптимизации на уровне AST; * inline-преобразования и minify-проходы. ## Профилирование памяти Память становится критическим фактором при больших монорепозиториях. SWC, работая через нативный код, снижает нагрузку на GC, однако Node.js-обвязка может вносить дополнительные затраты. Для измерения используется: ```javascript import { transform } from "@swc/core"; const before = process.memoryUsage(); await transform(code, config); const after = process.memoryUsage(); console.log({ heapDiff: after.heapUsed - before.heapUsed, rssDiff: after.rss - before.rss }); ``` Ключевые метрики: * `heapUsed` — активная куча Node.js; * `rss` — реальное потребление памяти процессом; * `external` — память нативных модулей (важно для SWC). Рост `external` памяти часто связан с буферами, используемыми Rust-слоем для обработки файлов. ## Профилирование через инструменты Node.js Для глубокого анализа применяется встроенный инспектор: ```bash node --inspect-brk build.js ``` Далее используется Chrome DevTools → вкладка Performance. В профиле можно наблюдать: * время вызова нативных биндингов SWC; * блокировки event loop при массовой обработке файлов; * распределение CPU между I/O и трансформацией. Дополнительно используется CPU-профилирование: ```bash node --prof build.js node --prof-process isolate-*.log > report.txt ``` Хотя значительная часть работы SWC выполняется вне V8, обвязка и сериализация данных становятся заметными в профиле. ## Профилирование SWC в сборщиках ### Webpack и swc-loader При интеграции через `swc-loader` появляется дополнительный слой, влияющий на итоговую скорость. Пример конфигурации: ```javascript module.exports = { module: { rules: [ { test: /\.js$/, use: { loader: "swc-loader", options: { jsc: { transform: { react: { runtime: "automatic" } } } } } } ] } }; ``` Профилирование выполняется через: ```bash webpack --profile --json > stats.json ``` Анализ `stats.json` позволяет выделить: * время loader-этапа; * влияние параллелизма; * стоимость пересборки модулей. SWC обычно снижает время loader-фазы по сравнению с Babel, но bottleneck часто смещается в сторону resolution модулей и I/O. ### Turbopack и аналогичные сборщики В современных сборщиках SWC используется как встроенный трансформер. Профилирование в этом случае опирается на tracing сборщика, где SWC-этап выделяется как отдельный task node. ## Инкрементальные сборки и кеширование Кеширование является ключевым фактором производительности SWC в реальных проектах. Типы кеша: * файловый кеш трансформаций; * кеш AST-представлений; * кеш хешей входных файлов; * in-memory кеш в сборщике. Пример включения кеширования в `swc-loader`: ```javascript options: { cacheDirectory: true, jsc: { transform: { react: { runtime: "automatic" } } } } ``` Профилирование кеша включает сравнение: * cold build (без кеша); * warm build (с прогретым кешем); * incremental rebuild (изменение одного модуля). Типичная картина: * cold build: максимальное время компиляции; * warm build: значительное снижение времени; * incremental: время стремится к O(изменённые файлы), а не O(проекта). ## Трассировка трансформаций AST Глубокое профилирование SWC включает анализ AST-проходов. Несмотря на отсутствие нативного трассировщика в базовом API, поведение можно оценивать через кастомные плагины. Идея заключается в измерении времени на уровне visitor-паттернов: ```javascript export default function profiler() { return { visitor: { Program(node) { const start = performance.now(); return () => { const end = performance.now(); console.log("Program transform:", end - start); }; } } }; } ``` Такая модель позволяет выявить: * узкие места конкретных трансформаций; * влияние сторонних плагинов; * деградацию при сложных AST-структурах. ## Сравнительное профилирование конфигураций SWC чувствителен к конфигурации `jsc.target`, `minify`, `sourceMaps`. Пример влияния: * включение `sourceMaps` увеличивает время генерации; * `minify` добавляет дополнительные проходы AST; * снижение `target` может уменьшить количество преобразований. Методика оценки: 1. фиксируется базовая конфигурация; 2. изменяется один параметр; 3. фиксируется delta времени. Такой подход позволяет построить карту стоимости каждого флага. ## Параллелизм и многопоточность SWC использует многопоточную модель выполнения через Rust runtime. Однако в Node.js интеграции параллелизм может ограничиваться: * количеством worker threads; * стратегией сборщика; * файловой системой. При профилировании важно учитывать: * CPU utilization; * распределение потоков; * блокировки на уровне I/O. Типичный признак неэффективного параллелизма — низкая загрузка CPU при высокой длительности сборки. ## Выявление узких мест в больших проектах В монорепозиториях ключевым аспектом становится не скорость SWC, а распределение нагрузки. Основные источники деградации: * избыточные трансформации в node_modules; * отсутствие include/exclude фильтров; * повторная трансформация неизменённых файлов; * отсутствие кеширования между пакетами. Анализ включает: * трассировку входных графов модулей; * измерение времени по пакетам; * сегментацию сборки. ## Метрики стабильности компиляции Помимо скорости важна стабильность: * вариативность времени между запусками; * деградация при росте количества файлов; * линейность масштабирования. Идеальная характеристика SWC — близкая к линейной зависимости времени от объёма входных данных при корректной настройке кеша и параллелизма.