fbuild recognises there is no work to do, says so, and then takes three minutes to finish
saying it. Its own timer reports it, and nothing is written to disk during that time — no
object file, no archive, no .elf, no .bin.
$ fbuild build -e esp32_esp32_esp32s3_opi -v --no-timestamp
Board: Espressif ESP32-S3-DevKitC-1-N8 / ESP32S3 @ 240MHz
No-op fingerprint matched; reusing existing ESP32 artifacts.
Flash: 732.27KB / 16.00MB (4.5%)
RAM: 79.40KB / 320.00KB (24.8%)
build succeeded in 181.5s (flash: 749848 bytes, ram: 81308 bytes)
Minimal reproduction — it needs no project at all
A throwaway directory with an empty lib/, no libraries of any kind, and a three-line
sketch:
[env:esp32_esp32_esp32s3_opi]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
build_flags = -DCORE_DEBUG_LEVEL=0 -DBOARD_HAS_PSRAM
board_build.memory_type = dio_opi
board_upload.flash_size = 16MB
board_build.partitions = default_16MB.csv
#include <Arduino.h>
void setup() { pinMode(2, OUTPUT); }
void loop() { digitalWrite(2, HIGH); delay(500); digitalWrite(2, LOW); delay(500); }
Build it once, then again:
No-op fingerprint matched; reusing existing ESP32 artifacts.
Flash: 361.84KB / 16.00MB (2.2%)
RAM: 72.76KB / 320.00KB (22.7%)
build succeeded in 161.2s (flash: 370527 bytes, ram: 74507 bytes)
161.2s to confirm that a blink sketch with no libraries has not changed.
It is specific to the ESP32 orchestrator
Same project, same host, same 2.5.21, same vendored lib/; only the environment differs:
| Environment |
Objects in the build tree |
Populate |
No-op |
fbuild's own line |
arduino_avr_uno |
56 |
26.2s |
0.4s |
reusing existing AVR artifacts |
esp8266_nodemcuv2 |
113 |
39.0s |
0.4s |
reusing existing ESP8266 artifacts |
stm32_blackpill_f411ce |
232 |
71.3s |
0.4s |
reusing existing STM32 artifacts |
esp32-s3-devkitc-1 (opi PSRAM) |
255 |
~6m |
181.5s |
reusing existing ESP32 artifacts |
The STM32 row is the size-matched control: 232 objects against ESP32's 255, within 10%,
and 450x faster. Populate time meanwhile tracks object count across all four (26.2 / 39.0
/ 71.3s for 56 / 113 / 232), so the compile path looks healthy everywhere — it is only the
reuse path, and only on one platform.
The project's own content is nearly irrelevant to the cost
| Project |
Files in lib/ |
No-op |
| Our scaffold, vendored FastLED |
4,506 |
181.5s |
Same, with ci/examples/tests/docs/.git pruned |
3,158 |
163.7s |
| Bare blink, no libraries at all |
0 |
161.2s |
Everything a project can contribute is that ~20s spread. The remaining ~161s is a floor an
empty ESP32 project pays, and the other three platforms do not pay at all.
What it is not
Not Windows file I/O, not the size of the vendored library tree, not translation-unit
count, not framework download or install — each is held constant or beaten outright by one
of the rows above.
A possible lead, offered as a lead and not a diagnosis
#214 describes the pre-cache behaviour as "the orchestrator still invoked the uncached
resolver, causing every build to repeat the entire directory walk", and wires the
library-selection cache into teensy and stm32 — two of the fast controls above. ESP32 is
named in neither that issue nor any follow-up we could find.
The bare-project floor rules out the project's libraries as the load, but not the
framework's: the ESP32 Arduino framework tree is 10,059 files here, and it is identical for
every ESP32 project, which would fit a fixed cost that no amount of emptying the project
reduces. We have not read the source; this is only where we would look first.
Impact
It is the dominant cost of an fbuild upload for us and does not shrink with the size of the
change. Re-flashing an unchanged design is 3m 40s through fbuild against 26.8s through
arduino-cli, and 181.5s of that difference is this.
Environment
fbuild 2.5.21, Windows 11. Measured through
Design Studio for FastLED.
fbuild recognises there is no work to do, says so, and then takes three minutes to finish
saying it. Its own timer reports it, and nothing is written to disk during that time — no
object file, no archive, no
.elf, no.bin.Minimal reproduction — it needs no project at all
A throwaway directory with an empty
lib/, no libraries of any kind, and a three-linesketch:
Build it once, then again:
161.2s to confirm that a blink sketch with no libraries has not changed.
It is specific to the ESP32 orchestrator
Same project, same host, same 2.5.21, same vendored
lib/; only the environment differs:arduino_avr_unoreusing existing AVR artifactsesp8266_nodemcuv2reusing existing ESP8266 artifactsstm32_blackpill_f411cereusing existing STM32 artifactsesp32-s3-devkitc-1(opi PSRAM)reusing existing ESP32 artifactsThe STM32 row is the size-matched control: 232 objects against ESP32's 255, within 10%,
and 450x faster. Populate time meanwhile tracks object count across all four (26.2 / 39.0
/ 71.3s for 56 / 113 / 232), so the compile path looks healthy everywhere — it is only the
reuse path, and only on one platform.
The project's own content is nearly irrelevant to the cost
lib/ci/examples/tests/docs/.gitprunedEverything a project can contribute is that ~20s spread. The remaining ~161s is a floor an
empty ESP32 project pays, and the other three platforms do not pay at all.
What it is not
Not Windows file I/O, not the size of the vendored library tree, not translation-unit
count, not framework download or install — each is held constant or beaten outright by one
of the rows above.
A possible lead, offered as a lead and not a diagnosis
#214 describes the pre-cache behaviour as "the orchestrator still invoked the uncached
resolver, causing every build to repeat the entire directory walk", and wires the
library-selection cache into teensy and stm32 — two of the fast controls above. ESP32 is
named in neither that issue nor any follow-up we could find.
The bare-project floor rules out the project's libraries as the load, but not the
framework's: the ESP32 Arduino framework tree is 10,059 files here, and it is identical for
every ESP32 project, which would fit a fixed cost that no amount of emptying the project
reduces. We have not read the source; this is only where we would look first.
Impact
It is the dominant cost of an fbuild upload for us and does not shrink with the size of the
change. Re-flashing an unchanged design is 3m 40s through fbuild against 26.8s through
arduino-cli, and 181.5s of that difference is this.
Environment
fbuild 2.5.21, Windows 11. Measured through
Design Studio for FastLED.