perf(dev): −1.2 GB idle RSS per pnpm dev instance (Rolldown threads + mimalloc purge) (#33836)

* perf(dev): size the dev server's Rolldown runtime for many parallel instances

~93% of idle electron-vite RSS is Rolldown's native mimalloc arenas. The dev
wrapper now gives electron-vite MIMALLOC_PURGE_DELAY=0 and 4 Rolldown/Rayon
threads; a serve-only renderer plugin strips exactly those keys before
Electron spawns, so dev Orca's terminals never inherit them.

* fix(dev): add the runtime-env plugin only when the dev wrapper set its keys

Keeps createDevServeConfig returning the renderer config unchanged when there
is no port and nothing to strip, as electron-vite-output-contract pins.

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
OrcaWin
2026-10-26 01:39:36 -07:00
committed by GitHub
co-authored by OrcaWin
parent bf496c6e40
commit 7324dada30
5 changed files with 96 additions and 3 deletions
@@ -0,0 +1,13 @@
import type { Plugin } from 'vite'
import { removeDevRolldownRuntimeEnv } from '../scripts/dev-rolldown-runtime-env.mjs'
/** electron-vite starts Electron after the renderer server, so this runs once Rolldown has sized its pools. */
export function createDevRolldownRuntimeEnvPlugin(): Plugin {
return {
name: 'orca-dev-rolldown-runtime-env',
apply: 'serve',
config() {
removeDevRolldownRuntimeEnv(process.env)
}
}
}
+17 -2
View File
@@ -1,4 +1,6 @@
import type { UserConfig } from 'electron-vite'
import { DEV_RUNTIME_ENV_KEYS } from '../scripts/dev-rolldown-runtime-env.mjs'
import { createDevRolldownRuntimeEnvPlugin } from './dev-rolldown-runtime-env'
import { withBundledRendererDev } from './renderer-bundled-dev'
/** Development-server overrides; Electron Vite also uses Vite's build command for the dev main process. */
@@ -8,14 +10,27 @@ export function createDevServeConfig(
): UserConfig {
// run-electron-vite-dev.mjs probes a per-worktree port and reports it; strict keeps that report true.
const rendererPort = Number.parseInt(env.ORCA_DEV_RENDERER_PORT ?? '', 10)
const hasPort = Number.isInteger(rendererPort)
// Only the dev wrapper sets runtime keys; without them there is nothing to strip.
const stripsRuntimeEnv = Boolean(env[DEV_RUNTIME_ENV_KEYS])
return withBundledRendererDev(
{
...config,
renderer:
Number.isInteger(rendererPort) && config.renderer
config.renderer && (hasPort || stripsRuntimeEnv)
? {
...config.renderer,
server: { ...config.renderer.server, port: rendererPort, strictPort: true }
...(hasPort
? { server: { ...config.renderer.server, port: rendererPort, strictPort: true } }
: {}),
...(stripsRuntimeEnv
? {
plugins: [
...(config.renderer.plugins ?? []),
createDevRolldownRuntimeEnvPlugin()
]
}
: {})
}
: config.renderer,
main: {
@@ -0,0 +1,39 @@
import os from 'node:os'
export const DEV_RUNTIME_ENV_KEYS = 'ORCA_DEV_RUNTIME_ENV_KEYS'
// Measured idle electron-vite RSS 4.6GB -> 3.0GB with no HMR or startup regression.
const DEV_THREADS = '4'
const DEV_RUNTIME_DEFAULTS = {
// mimalloc otherwise keeps freed Rolldown arenas resident for the whole dev session.
MIMALLOC_PURGE_DELAY: '0',
ROLLDOWN_WORKER_THREADS: DEV_THREADS,
RAYON_NUM_THREADS: DEV_THREADS
}
/** Sizes the dev server's Rolldown runtime; records added keys so Electron's environment can drop them. */
export function withDevRolldownRuntimeEnv(env, availableParallelism = os.availableParallelism()) {
const added = Object.entries(DEV_RUNTIME_DEFAULTS).filter(
([key]) =>
env[key] === undefined &&
(key === 'MIMALLOC_PURGE_DELAY' || availableParallelism > Number(DEV_THREADS))
)
if (added.length === 0) {
return env
}
return {
...env,
...Object.fromEntries(added),
[DEV_RUNTIME_ENV_KEYS]: added.map(([key]) => key).join(',')
}
}
/** Rolldown has read these before the renderer server starts; dev Electron's terminals must not inherit them. */
export function removeDevRolldownRuntimeEnv(env) {
for (const key of (env[DEV_RUNTIME_ENV_KEYS] ?? '').split(',')) {
if (key) {
delete env[key]
}
}
delete env[DEV_RUNTIME_ENV_KEYS]
}
@@ -0,0 +1,25 @@
import { describe, expect, it } from 'vitest'
import {
removeDevRolldownRuntimeEnv,
withDevRolldownRuntimeEnv
} from './dev-rolldown-runtime-env.mjs'
describe('dev Rolldown runtime env', () => {
it('removes only the keys it added, keeping caller choices', () => {
const env = withDevRolldownRuntimeEnv({ RAYON_NUM_THREADS: '2', PATH: '/bin' }, 24)
expect(env).toMatchObject({
MIMALLOC_PURGE_DELAY: '0',
ROLLDOWN_WORKER_THREADS: '4',
RAYON_NUM_THREADS: '2'
})
removeDevRolldownRuntimeEnv(env)
expect(env).toEqual({ RAYON_NUM_THREADS: '2', PATH: '/bin' })
})
it('keeps Rolldown thread defaults on small hosts', () => {
expect(withDevRolldownRuntimeEnv({}, 4)).toEqual({
MIMALLOC_PURGE_DELAY: '0',
ORCA_DEV_RUNTIME_ENV_KEYS: 'MIMALLOC_PURGE_DELAY'
})
})
})
+2 -1
View File
@@ -39,6 +39,7 @@ import {
recordDevWebClientInputs
} from './dev-web-client-freshness.mjs'
import { withRolldownThreadLimit } from './rolldown-thread-limit.mjs'
import { withDevRolldownRuntimeEnv } from './dev-rolldown-runtime-env.mjs'
import { copyPrivateTree } from './space-sharing-copy.mjs'
import {
DEV_BUNDLE_ID,
@@ -584,7 +585,7 @@ if (!isHelpOrVersion) {
const forwardedArgs = ['dev', ...forwardedRaw, ...forwardedExtras]
const child = spawn(process.execPath, [electronViteCli, ...forwardedArgs], {
stdio: 'inherit',
env: process.env,
env: withDevRolldownRuntimeEnv(process.env),
// Own process group so Ctrl+C terminates electron-vite’s Electron descendants on macOS too.
detached: process.platform !== 'win32'
})