Профилирование компиляции
## Метрики компиляции
Профилирование компиляции в 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 — близкая к линейной зависимости времени от объёма входных данных при корректной настройке кеша и параллелизма.