Skip to content

Commit

Permalink
chore(builder): support RSPACK_PROFILE (#4772)
Browse files Browse the repository at this point in the history
  • Loading branch information
9aoy authored Oct 11, 2023
1 parent d11870b commit 73dcace
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .changeset/late-timers-repair.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@modern-js/builder-rspack-provider': patch
---

chore(builder): support the use of the RSPACK_PROFILE environment variable for Rspack build performance profile

chore(builder):支持使用 RSPACK_PROFILE 环境变量来进行 Rspack 构建性能分析
103 changes: 103 additions & 0 deletions packages/builder/builder-rspack-provider/src/plugins/rspack-profile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import type { BuilderPlugin } from '../types';
import path from 'path';
import {
experimental_registerGlobalTrace as registerGlobalTrace,
experimental_cleanupGlobalTrace as cleanupGlobalTrace,
} from '@rspack/core';
// eslint-disable-next-line node/no-unsupported-features/node-builtins
import inspector from 'inspector';
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
import { fs } from '@modern-js/utils';
import { logger } from '@modern-js/builder-shared';

export const stopProfiler = (
output: string,
profileSession?: inspector.Session,
) => {
if (!profileSession) {
return;
}
profileSession.post('Profiler.stop', (error, param) => {
if (error) {
logger.error('Failed to generate JS CPU profile:', error);
return;
}
fs.writeFileSync(output, JSON.stringify(param.profile));
});
};

// Reference rspack-cli
// https://github.com/modern-js-dev/rspack/blob/509abcfc523bc20125459f5d428dc1645751700c/packages/rspack-cli/src/utils/profile.ts
export const builderPluginRspackProfile = (): BuilderPlugin => ({
name: 'builder-plugin-rspack-profile',

setup(api) {
/**
* RSPACK_PROFILE=ALL
* RSPACK_PROFILE=TRACE|CPU|LOGGING
*/
const RSPACK_PROFILE = process.env.RSPACK_PROFILE?.toUpperCase();

if (!RSPACK_PROFILE) {
return;
}

const timestamp = Date.now();
const profileDir = path.join(
api.context.distPath,
`rspack-profile-${timestamp}`,
);

let profileSession: inspector.Session | undefined;

const enableProfileTrace =
RSPACK_PROFILE === 'ALL' || RSPACK_PROFILE.includes('TRACE');

const enableCPUProfile =
RSPACK_PROFILE === 'ALL' || RSPACK_PROFILE.includes('CPU');

const enableLogging =
RSPACK_PROFILE === 'ALL' || RSPACK_PROFILE.includes('LOGGING');

const traceFilePath = path.join(profileDir, 'trace.json');
const cpuProfilePath = path.join(profileDir, 'jscpuprofile.json');
const loggingFilePath = path.join(profileDir, 'logging.json');

const onStart = () => {
fs.ensureDirSync(profileDir);

if (enableProfileTrace) {
registerGlobalTrace('trace', 'chrome', traceFilePath);
}

if (enableCPUProfile) {
profileSession = new inspector.Session();
profileSession.connect();
profileSession.post('Profiler.enable');
profileSession.post('Profiler.start');
}
};

api.onBeforeBuild(onStart);
api.onBeforeStartDevServer(onStart);

api.onAfterBuild(async ({ stats }) => {
if (enableLogging && stats) {
const logging = stats.toJson({
all: false,
logging: 'verbose',
loggingTrace: true,
});
fs.writeFileSync(loggingFilePath, JSON.stringify(logging));
}
});

api.onExit(() => {
enableProfileTrace && cleanupGlobalTrace();

stopProfiler(cpuProfilePath, profileSession);

logger.info(`Saved Rspack profile file to ${profileDir}`);
});
},
});
3 changes: 3 additions & 0 deletions packages/builder/builder-rspack-provider/src/shared/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,8 @@ export const applyDefaultPlugins = (plugins: Plugins) =>
plugins.networkPerformance(),
plugins.preloadOrPrefetch(),
plugins.performance(),
import('../plugins/rspack-profile').then(m =>
m.builderPluginRspackProfile(),
),
import('../plugins/fallback').then(m => m.builderPluginFallback()), // fallback should be the last plugin
]);
2 changes: 2 additions & 0 deletions packages/builder/builder-shared/src/types/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ interface StatsOptionsObj {
errors?: boolean;
errorsCount?: boolean;
colors?: boolean;
logging?: boolean | 'none' | 'error' | 'warn' | 'info' | 'log' | 'verbose';
loggingTrace?: boolean;

/** Rspack not support below opts */
cachedAssets?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,20 @@ export default {
};
```

## Build performance profile

Builder supports the use of the `RSPACK_PROFILE` environment variable for build performance profile.

```bash
$ RSPACK_PROFILE=ALL pnpm build
```

This command will generate a `rspack-profile-${timestamp}` folder in the dist folder, and it will contain `logging.json`, `trace.json` and `jscpuprofile.json` files.

- `trace.json`: The time spent on each phase of the Rust side is recorded at a granular level using tracing and can be viewed using [ui.perfetto.dev](https://ui.perfetto.dev/)
- `jscpuprofile.json`: The time spent at each stage on the JavaScript side is recorded at a granular level using [Node.js inspector](https://nodejs.org/dist/latest-v18.x/docs/api/inspector.html) and can be viewed using [speedscope.app](https://www.speedscope.app/)
- `logging.json`: Includes some logging information that keeps a coarse-grained record of how long each phase of the build took

## Compare with Rspack CLI

Builder Rspack build mode comparison [Rspack CLI](https://www.rspack.dev/guide/quick-start.html#using-the-rspack-cli) adds a lot of out-of-the-box capabilities. At the same time, these capabilities will bring a certain degree of performance overhead and behavioral differences:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,20 @@ export default {
};
```

## Rspack 性能分析

Builder 支持使用 `RSPACK_PROFILE` 环境变量来进行构建性能分析。

```bash
$ RSPACK_PROFILE=ALL pnpm build
```

执行该命令后会在当前产物目录下生成一个 `rspack-profile-${timestamp}` 文件夹,该文件夹下会包含 `logging.json``trace.json``jscpuprofile.json` 三个文件

- `trace.json`:使用 tracing 细粒度地记录了 Rust 侧各个阶段的耗时,可以使用 [ui.perfetto.dev](https://ui.perfetto.dev/) 进行查看
- `jscpuprofile.json`:使用 [Node.js inspector](https://nodejs.org/dist/latest-v18.x/docs/api/inspector.html) 细粒度地记录了 JavaScript 侧的各个阶段的耗时,可以使用 [speedscope.app](https://www.speedscope.app/) 进行查看
- `logging.json`:包含一些日志信息,粗粒度地记录了构建的各个阶段耗时

## 对比 Rspack CLI

Builder Rspack 构建模式对比 [Rspack CLI](https://www.rspack.dev/zh/guide/quick-start.html#%E4%BD%BF%E7%94%A8-rspack-cli) 添加了很多开箱即用的能力,同时,这些能力的封装会带来一定程度上的性能开销和行为表现上的差异:
Expand Down

0 comments on commit 73dcace

Please sign in to comment.