#51812: build: generate Electron-specific PGO profiles in CI
Description of Change
Adds a manually-triggered (workflow_dispatch) pipeline that builds PGO-instrumented Electron for every published platform/arch combo, collects optimization profiles by running benchmark and app-style workloads against each build, and publishes merged profiles to https://dev-cdn.electronjs.org/pgo/.
Why Electron needs its own profiles
Electron release builds apply Chrome's published PGO profile (chrome_pgo_phase = 2). PGO profiles match functions by symbol name + control-flow hash, so every function that differs from Chrome — all of Node.js, patched Chromium code, V8 built with Node's flags, and the shell/ code itself — silently gets no optimization guidance and is laid out as cold. The same applies to V8's builtins profile: Chrome's published profiles reject Electron's promise/async builtins (RunMicrotasks, AsyncFunctionAwait, FulfillPromise, …) because Node's integration changes their codegen.
Measured impact of replacing Chrome's profile with an Electron-collected one (Linux x64, otherwise identical builds):
| Workload | Improvement |
|---|---|
| Speedometer 3.1 | +9.5% |
| contextBridge calls | +44–51% |
ipcRenderer.invoke (5 MB payloads) |
+10% |
renderer fetch() round-trips |
+31–35% |
Node crypto.randomBytes |
+13% (recovers a 2× regression vs Electron 42 caused by Chrome-profile mismatch on patched BoringSSL) |
| Geomean of 22 app-operation benchmarks | +16% |
What the pipeline does
8x instrumented builds 1x instrumented d8
(chrome_pgo_phase = 1) (v8_enable_builtins_profiling)
| |
v v
8x profile collection JetStream 2 -> get_hints.py
(benchmarks + app workloads) |
| |
v v
merge (llvm-profdata) electron-v8-x64.profile
| |
+----------------+---------------+
v
OIDC upload -> dev-cdn.electronjs.org/pgo/
- Platforms: linux x64/arm/arm64, win x64/x86/arm64, macos x64/arm64 — each combo collects on hardware/containers that can run its own binaries (matching how Chrome generates per-arch profiles)
- Collection workloads: Speedometer 3 (×3), JetStream 2, MotionMark — the same set Chromium's PGO recipe uses — plus Electron-specific phases that browser benchmarks can't cover: main-process Node.js (Buffer/crypto/fs/JSON), contextBridge +
ipcRenderer.invokemarshaling, and renderer/Node networking over HTTPS + HTTP/2 with real certificate verification (an ephemeral CA is installed in the collection host's trust store) - V8 builtins profile: generated from an instrumented d8 built with Electron's exact V8 configuration; one x64 profile covers x64 + arm64 (block graphs are arch-independent, mirroring upstream)
- Upload: gated behind the
pgo-uploadGitHub environment (manual approval) and authenticated via OIDC — no long-lived credentials. Infra side: electron/infra#287 (merged)
Build-system changes
build/args/pgo-instrument.gn/pgo-builtins-instrument.gn— instrumented build configurations- New Chromium patch fixing profile-runtime resolution for instrumented builds on Linux arm32 and Windows cross-compiles (upstreamable; Chrome never builds these configurations)
generate-chromedriver/generate-test-artifactsflags on the build segment (defaulttrue, no behavior change for existing callers) — instrumented builds skip artifacts only consumed by test jobs, saving ~10–20 min and ~700–950 MB per platform
What this PR does not do
Release builds do not consume these profiles yet — that's a follow-up PR (download profile + set pgo_data_path / v8_builtins_profiling_log_file). This PR only adds the generation side.
The pipeline was validated end-to-end on this branch's history: 13 full runs, with the final runs producing all 8 platform profiles + the builtins profile and uploading them to dev-cdn through the OIDC environment.
Checklist
- I have built and tested this change
- I have filled out the PR description
- I have reviewed and verified the changes
-
npm testpasses - PR release notes describe the change in a way relevant to app developers
Release Notes
Notes: none
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