Repository navigation
Description
Context
The first published ESP32-S3 Blink comparison (run 36273077249, SHA 8cd955adc66cb8619faa50fbdc1b71fecccea3ca, latest.json) reports these medians from three trials on ubuntu-24.04 (nproc=4):
| Tool | Cold | Immediate no-change rebuild |
|---|---|---|
| PlatformIO | 6,560.617 ms | 1,294.221 ms |
| fbuild | 16,066.810 ms | 326.134 ms |
The cold fbuild build is 2.45× slower, while its no-change rebuild is 3.97× faster. The three cold fbuild trials are tightly grouped (16.01–16.35 s), and daemon_restarts is zero.
The benchmark log artifact shows where most of the cold time goes: after fbuild clean cache, fbuild reports a framework-core cache miss and recompiles 60 core files, reaching 20/40/60 at about 4.4/9.5/13.3 s, then compiles the sketch and finishes at about 16 s. The first PlatformIO cold trial logs 46 FrameworkArduino compile commands and finishes in about 6.4 s. Both compile the same Blink sketch, but they do not use the same ESP32 build inputs:
bench/blink/platformio.inipinsespressif32@6.13.0. PlatformIO resolvesframework-arduinoespressif32 @ 3.20017.241212+sha.dcc1105b(Arduino-ESP32 2.0.17 generation) andtoolchain-xtensa-esp32s3 @ 8.4.0+2021r2-patch5.- Every timed fbuild build warns that it ignores that registry version pin and uses its own pinned ESP32 packages. Its log reports
xtensa-esp-elf-gcc 14.2.0. In code,Esp32Platform::newdefaults to the pioarduinostablerelease, which resolves its framework/toolchain fromplatform.json. The benchmark does not record the actual fbuild framework version. - The workflow's
ARDUINO_ESP32_CORE_VERSION=3.3.7pins Arduino CLI only; it does not align PlatformIO and fbuild. See workflow, fixture, fbuild package resolution, and default platform.
This identifies the immediate reason the chart is misleading: it compares different framework generations, compilers, and core source sets. It also identifies the dominant fbuild time as cold framework-core compilation. The log alone cannot quantify how much of the 9.5 s gap comes from source count, compiler version, flags, cache overhead, or linking; a controlled same-stack run is required before attributing all of it to fbuild's implementation.
The current harness hides this ESP32 result in two ways: PERF_PHASE_LABELS contains only avr-orchestrator and pipeline, so the published ESP32 cold_phases_ms is empty; fbuild_vs_platformio_cold and fbuild_overhead_ms select the first board (Uno), so the top-level ratio is 0.470 even while ESP32-S3 is 2.449. The raw compiler floor is likewise collected only for Uno. See runner.
Proposal
Make the ESP32-S3 comparison reproducible and like-for-like: resolve the fixture's espressif32@6.13.0 PlatformIO alias through #1491, then build PlatformIO and fbuild against the same immutable Arduino core, ESP-IDF and Xtensa toolchain package set. Cross-version labeling is an interim safety measure, not the final fix for a valid alias. Record resolved package/compiler versions in the artifact. Add ESP32 phase timing and a per-board raw-compiler baseline, then run matched cold/warm trials to separate framework size, compiler work, cache overhead, and link/image time. Optimize the measured dominant fbuild phase if the same-stack cold result remains slower.
Make ratios and regression warnings board-specific so an ESP32-S3 cold regression cannot be masked by Uno's result.
Acceptance criteria
- RED: a focused benchmark-runner test demonstrates that mismatched resolved ESP32 packages can currently be published as directly comparable, and that the current top-level cold ratio selects Uno while ESP32-S3 is slower.
- GREEN: after the valid
espressif32@6.13.0alias is supported, the workflow runs PlatformIO and fbuild with the matching resolved ESP32 framework/toolchain/SDK inputs and records their identities. Until then, it labels or excludes cross-version results; labeling alone does not satisfy the final matched-stack benchmark. - ESP32-S3 has nonempty per-phase cold timings, a raw compile baseline for its actual source set, and a board-specific fbuild/PlatformIO cold ratio in
latest.jsonand history. Regression reporting evaluates that board-specific ratio. - A fresh three-trial run records the ESP32-S3 core source counts, compile flags/toolchain provenance and cold phase breakdown, then documents which phase accounts for the remaining cold gap under matched inputs. If a code change addresses that phase, the focused before/after repro is RED → GREEN and the no-change warm result does not regress.
- Unit tests: feed an offline
espressif32@6.13.0registry/platform-manifest fixture through the sharedfbuild-coreresolver and assert the exact framework/toolchain payload identities; separately assert the benchmark runner flags any requested-versus-resolved stack mismatch. Keep the three-trial build benchmark as an integration check.
PlatformIO alias dependency
- This benchmark must exercise actual
espressif32@6.13.0resolution, not a server-side alias to pioarduino stable or an early refusal of the valid pin. meta: resolve PlatformIO package aliases and build requested stacks #1491 owns the shared resolver; ESP32: provision per-MCU registry toolchains so pre-unified platform pins (pioarduino 51.x) actually build against their pin #1444 owns legacy per-MCU toolchain support needed by older ESP32 stacks.
Decisions
- Treat this as a benchmark-validity and ESP32 cold-build performance bug, priority P2: the published comparison currently implies a tool-performance conclusion that the differing package stacks cannot support.
- Keep the same Blink fixture and cold policy so the corrected run can be compared with the published one; change cache treatment only if applied consistently to both tools.
- Do not infer that GCC 14 alone explains the gap. The current evidence proves a stack mismatch and locates most fbuild time in its core compile, but does not isolate the relative contributions.
Related issues
- feat(bench): publish ESP32-S3 build timings alongside Arduino Uno #1488 added the ESP32-S3 benchmark; this issue investigates its first published result.
- meta: cold builds 50% faster than PlatformIO (performance audit) #1469 tracks the Uno cold-build performance audit and the broader benchmark fairness policy; it does not cover ESP32-S3's package mismatch.
Core generic-path testing gate
- RED → GREEN: resolve the benchmark fixture’s
platformio/platform/espressif32@6.13.0through the publicfbuild-corePlatformIO-path entry point, not through benchmark-only or ESP32-only lookup. Offline fixtures assert the exact platform payload URL/SHA-256, host selection, cache identity, and manifest-derived framework, SDK, and toolchain identities; no live registry or compiler download is required. - Include a synthetic valid platform path absent from native dispatch in the shared core matrix to prove generic payload resolution. Keep benchmark-runner tests separate: they must flag requested-versus-resolved stack mismatches and only publish matched-stack comparisons as like-for-like.
- The benchmark integration run then verifies that fbuild consumes the core-resolved stack and records its identities; merely labeling a mismatched stack is an interim safeguard, not completion.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTriage
Activity
zackees commentedon Sep 26, 2026
Testing-criteria clarification: this child’s representative platform fixture must pass through the public, platform-agnostic
fbuild-coreresolver specified in #1491, then through its native adapter. Assert the exact requested payload/source identities (including host-specific URL and checksum when published), manifest dependency and explicit override precedence, and no substitution by the family default. Core unit tests must also cover synthetic unknown-platform and generic PlatformIO package paths independently of native build support. Keep offline unit tests separate from the actual compile/build integration repro.zackees commentedon Sep 27, 2026
Local matched-stack repro in progress on a branch from main: PlatformIO
espressif32@6.13.0resolves platform 6.13.0, Arduino framework3.20017.241212+sha.dcc1105b, Xtensa S3 GCC8.4.0+2021r2-patch5, and esptool2.41100.260830; an isolated PlatformIO build passed. fbuild now fetches those same registry payloads with published SHA-256 values, but its modern ESP32 recipe still fails against the older SDK. Focused RED→GREEN tests identified two concrete include-search bugs: sorting displaced the SDK newlibplatform_includedirectory, and recursive scanning mixed ROM headers from other ESP32 chips. Both are fixed locally; the full fbuild build remains under active investigation. This is not yet a matched-stack benchmark or a completion claim.zackees commentedon Sep 27, 2026
Exact-head validation: three-trial benchmark run 36293685471 succeeded on PR #1505 commit
76a4d250(Linux x86_64). Both PlatformIO and fbuild resolvedespressif32@6.13.0,framework-arduinoespressif32@3.20017.241212+sha.dcc1105b(Arduino-ESP32 2.0.17),toolchain-xtensa-esp32s3@8.4.0+2021r2-patch5, and esptool2.41100.260830; each compiled 46 framework core sources. The artifact records representative full argv for each (including corrected quoted-DARDUINO_BOARD/-DIDF_VERmacros), and the raw replay successfully compiled 47 entries with four workers. The benchmark does not claim identical compile flags: the representative fbuild command contains 385-Ipaths versus 199 for PlatformIO.Median ESP32-S3 cold: PlatformIO 6,667.305 ms, fbuild 10,298.535 ms (1.545×); warm: PlatformIO 1,325.483 ms, fbuild 146.906 ms. The fbuild raw compiler floor was 5,619.994 ms, leaving 4,678.541 ms of full-build overhead above that floor. fbuild phase medians: core/variant compile 7,549.269 ms, sketch compile 587.635 ms, link/image/size 1,142.967 ms, platform resolution 131.106 ms, boot artifacts 108.873 ms. Thus the dominant measured phase is core/variant compilation; this run does not establish whether include-path breadth, zccache cold-miss work, or another compile-dispatch difference explains the entire gap. The benchmark now reports the actual board-specific ratio and excludes nonmatching Uno stacks from a cross-version ratio. No daemon restarts; all three cold and warm trials succeeded.
zackees commentedon Sep 27, 2026
Rebased-head confirmation: run 36294434302 succeeded on
9de7e46aafter rebasing onto currentmain. Same resolved ESP32 stack and 46 core sources on both sides; full representative argv and the 47-entry raw replay are present. Median cold PlatformIO 6,611.286 ms, fbuild 10,320.361 ms (1.561×); warm PlatformIO 1,302.581 ms, fbuild 143.344 ms. Raw floor 5,634.779 ms; fbuild core/variant compile 7,607.083 ms and link/image/size 1,137.631 ms. The measured conclusion and remaining gap are unchanged from the prior validated head.zackees commentedon Sep 27, 2026
Final reviewed-head benchmark: run 36295353769 succeeded on
303807e6(three trials, Linux x86_64). Both tools resolved platform6.13.0, framework3.20017.241212+sha.dcc1105b, Xtensa toolchain8.4.0+2021r2-patch5, and esptool2.41100.260830, and each compiled 46 core sources. The JSON retains full representative compiler argv and a successful 47-entry raw replay. Median cold PlatformIO 4,036.117 ms, fbuild 7,149.030 ms (1.771×); warm PlatformIO 778.479 ms, fbuild 90.833 ms. Raw compiler floor 3,766.257 ms; fbuild overhead over raw 3,382.773 ms; fbuild core/variant compile 5,247.232 ms and link/image/size 695.086 ms. No daemon restarts. This confirms the same-stack cold gap remains and that the core/variant phase is its largest measured component; it does not attribute the entire gap to a single unmeasured mechanism.