#53116: perf: start the first sandboxed window in a pre-warmed renderer
Description of Change
The first BrowserWindow gets its renderer ~15 ms sooner on Linux (window creation to preload start 36 -> 21 ms) by taking a renderer that was started when the default session was created, instead of launching one. Larger on platforms where process creation is slower. The first commit stops deciding the service worker preload realm from a process-launch-time switch, which a renderer started ahead of time would otherwise bake in.
Chromium can keep a warm spare renderer so that a navigation needing a new process does not wait for a launch. Electron has force-disabled kSpareRendererForSitePerProcess since the process-model rework, because a renderer's command line here depends on the WebContents it is created for (WebContentsPreferences::AppendCommandLineSwitches). For a sandboxed WebContents whose webPreferences add no renderer switches (no additionalArguments, Blink feature toggles, experimentalFeatures, offscreen or scrollBounce) that command line is just --enable-sandbox, so those windows can use a process started ahead of time.
- Electron starts one such renderer when the default session is first created.
ShouldUseSpareRenderProcessHost()hands it only to a compatibleWebContents(the one whose process is being picked insideRegisterPendingSiteInstance(), or, whilecontent::WebContents::Create()gives the initial frame a process, thewebPreferencesbeing used to create it) and never to extension or WebUI frames; it is launched with--enable-sandbox: a two-line content patch registers the spare beforeInit()soIsSpare()already holds inAppendExtraCommandLineSwitches. - One-shot by default: the first process allocation that cannot use it makes content discard it and nothing re-warms it, so an app does not carry an idle renderer after its first window. An app whose first window is not sandboxed pays one renderer launch that is thrown away at that point.
- Apps that open windows regularly can opt into Chromium's keep-one-warm behaviour with
--enable-features=SpareRendererForSitePerProcess(documented under command-line switches); Electron no longer overrides that feature when the app asks for it. With it, second and later windows go 26.8 -> 14.6 ms to preload start (32.5 -> 18.5 ms to first page script) at the cost of one idle renderer (16 MB private / 67 MB RSS on Linux here, against 19 / 95 MB for a window's renderer). - The first-window gain needs the session to exist before the window: apps that touch
session.defaultSession(protocol handlers, permissions, webRequest) beforenew BrowserWindowget it in full; creating the window as the very first thing afterreadygets part of it.
Non-sandboxed windows, <webview> guests, offscreen contents and extension / WebUI frames keep today's behaviour and never take the spare.
Checklist
- PR description included and stakeholders cc'd
-
npm testpasses (BrowserWindow, webContents, webview, subframe, chromium window.opener/sandbox specs locally on Linux) - PR release notes describe the change in a way relevant to app developers, and are capitalized, punctuated, and past tense.
- I have reviewed and verified the changes
Release Notes
Notes: The first sandboxed BrowserWindow now starts in a renderer process launched ahead of time when the default session already exists, shortening the time from window creation to the page's first script; apps that open many windows can keep a spare renderer warm at all times with --enable-features=SpareRendererForSitePerProcess.
Backports
Semver Impact
Semantic Versioning helps users understand the impact of updates:
- Major (X.y.z): Breaking changes that may require code modifications
- Minor (x.Y.z): New features that maintain backward compatibility
- Patch (x.y.Z): Bug fixes that don't change the API
- None: Changes that don't affect using facing parts of Electron