Repository navigation
chore(desktop): add a packaged startup benchmark - #49758
Merged
Merged
Conversation
bench:startup launches a packaged build in an isolated home (own appData, XDG directories, database, config and service registration) against a warm or cold bundled service, and records milestones from process spawn: main log events, renderer paint timing, shell / composer / timeline readiness polled over CDP, and renderer idle. Optional main-process CPU profile from the first statement and a Chromium startup trace. The devex benchmark covers the dev server; this covers what users launch.
This was referenced Sep 18, 2026
longtask entries are not buffered, so idle was detected against the probe time. Poll Performance.getMetrics TaskDuration alongside DOM readiness instead: idle is the start of the first 500 ms window with under 10 % task time that stays quiet for --settle-ms, and the total task and script time are reported as the renderer's CPU cost. Also keep the app alive until Chromium has written the startup trace.
This was referenced Sep 18, 2026
…ained - --service cold gives the spawned service a private port through the isolated config directory instead of requiring no other service - kill only the process tree the run spawned; a prod-channel build shares its executable name with an installed app - optional renderer CPU profile (--profile-renderer) from the moment the page target appears - wait for Chromium to write the startup trace before quitting
…p bench - read process creation and Node bootstrap timing from the main process after each run over --inspect, so the time before the first log line splits into Electron native init, Node bootstrap, and Electron JS init plus our bundle - strip the developer's OPENCODE_* / OTEL_* environment: an inherited OTLP endpoint added a Sentry round trip to every CLI exit inside the measured app - --compare alternates two builds so machine drift hits both equally; --warmup discards the first launch of each binary (antivirus scan) - --fresh wipes the profile per launch for the first-launch experience - --offline (implicit for beta/prod) keeps the updater's first check off the network
Each sample now carries the merged main-process log timeline (main plus the scoped crash/onboarding/window/renderer logs, as ms since spawn), the renderer's main-thread breakdown from Performance.getMetrics (script, layout, style, counts, DOM nodes, JS heap), navigation, resource and paint timing plus any performance marks, the working set of every process in the app's tree once idle, and the main process's CPU time. The summary adds median phase durations between consecutive checkpoints.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The devex benchmark measures
bun dev:desktopto Home. Nothing measured what users launch: a packaged build restoring its tabs against an already-running service. This addsbun run bench:startup.What it isolates. Own
%APPDATA%/XDG/DB/config/service registration (the desktop deletesXDG_STATE_HOMEon Windows, so isolation goes through the home directory), the developer'sOPENCODE_*/OTEL_*environment stripped (an inherited OTLP endpoint added a Sentry round trip to every CLI exit inside the measured app), a private service port for cold mode, and it only ever kills the process tree it spawned (a prod-channel build shares its executable name with the installed app).What it measures. Main-log milestones, renderer paint timing and DOM readiness over CDP, renderer idle (first 500 ms window under 10 % main-thread task time that stays quiet for
--settle-ms) and total renderer task time. After each run it readsprocess.getCreationTime()andperformance.nodeTimingfrom the main process over--inspect(nothing attaches until the run is over), which splits the time before our first log line into Electron native init, Node bootstrap, and Electron JS init + our bundle — so a fat main bundle can't hide inside a "Chromium boot" number.Per-run detail (in every sample of the JSON report): the merged main-process log timeline — main plus the scoped
crash/onboarding/window/rendererlogs as[ms, file, message]— the renderer's main-thread breakdown (script, layout, style, counts, DOM nodes, JS heap), navigation/resource/paint timing and anyperformance.marks, the working set of every process in the app's tree once idle, and the main process's CPU time. The summary adds median phase durations between consecutive checkpoints: