One problem with -O3 is that it disregards any effects of the cache (and yes, ESP32s have a bit of cache memory). I recommend using -Os as the default optimization level, as it often has the same or almost the same performance benefits as -O3. Less cache pressure is beneficial, especially for bigger applications, and the smaller code size is of course nice on embedded systems that have limited amounts of flash storage. If you know some specific functions or source files are performance sensitive, you can use pragmas to change optimization for those:
Remember that -Os is much much more aggressive in GCC than it is in LLVM, with LLVM you need to use -Oz to get the same result.
GCC has historically been a bit of a pig about -Os, my favorite example is on x86 where it will emit a runtime divide for a division by a compile time constant power of two because it saves a byte of text!
The arduino framework is optimised for ease of use. Battery powered devices were not the target back then when it was created. This benchmark should have used one of the many techniques that optimise for power consumption.
Yes, TFA article says they never activated any power-saving, so the idle loop is more or less just staying in active mode, which has the same power consumption as doing calculations.
But one thing the article didn't point out is what hardware peripherals each firmware activated by default. Eg, activating UART might use default pins and activate an UART RX on a pin, which might incur a mA-order penalty. Hence, a useful first step in optimizing power is to identify what functionality you need and ensure all else is always powered down (eg uart rx, clocks and timers, radio peripherals.
Hmm, those are some worrying news for Zephyr, but also for Linux. For reasons that escape my full understanding, a lot of embedded hardware needs Linux to work. If Zephyr, which I bet has been carefully crafted for microcontrollers, leaves some unnecessary things on, who knows what even an extremely trimmed down Linux running in, say, the beagle board, gets away with.
As an off-topic remark, I've used the qoitech arc power analyzer quite a bit and it's quite nice and easy to use, when your DUT is <5V and low amps. There's also the Nordic PPK2 kit, which is cheaper but I haven't tried it. Both are aiming at the crowd that prefers a simple, handles-most-use-cases, little USB-connected box that runs the client on your computer, rather than a separate bulky thing with screen and whatnot. Trade-offs of course though.
I did something similar, but less scientific, comparing ESP-IDF and esp-hal (Rust). Unfortunately I learned that the optimizations that are already in ESP-IDF (most of all automatic light sleep between BLE advertisments) are hard to replicate in Rust/esp-hal/embassy and so for battery powered devices you might want to stick to C++/ESP-IDF
While the ESP32 does have a high inrush current, its ULP coprocessor is quite capable, drawing only 12µA@3.3V during Deep Sleep. I have a fleet of AA-powered ESP32 devices at home that last 6–12 months, plus some solar-powered ones that run indefinitely.
> execute instructions faster (via -O3)
One problem with -O3 is that it disregards any effects of the cache (and yes, ESP32s have a bit of cache memory). I recommend using -Os as the default optimization level, as it often has the same or almost the same performance benefits as -O3. Less cache pressure is beneficial, especially for bigger applications, and the smaller code size is of course nice on embedded systems that have limited amounts of flash storage. If you know some specific functions or source files are performance sensitive, you can use pragmas to change optimization for those:
See https://gcc.gnu.org/onlinedocs/gcc/Function-Specific-Option-.... Clang has a similar pragma, see https://clang.llvm.org/docs/LanguageExtensions.html#extensio....
This is how all the now defunct Symbian code was compiled.
Remember that -Os is much much more aggressive in GCC than it is in LLVM, with LLVM you need to use -Oz to get the same result.
GCC has historically been a bit of a pig about -Os, my favorite example is on x86 where it will emit a runtime divide for a division by a compile time constant power of two because it saves a byte of text!
..becomes:
..versus:
That's not particularly uncommon. Many compilers or OSes default to wait loops when there's nothing to do, and they can be pretty power hungry.
The arduino framework is optimised for ease of use. Battery powered devices were not the target back then when it was created. This benchmark should have used one of the many techniques that optimise for power consumption.
Yes, TFA article says they never activated any power-saving, so the idle loop is more or less just staying in active mode, which has the same power consumption as doing calculations.
But one thing the article didn't point out is what hardware peripherals each firmware activated by default. Eg, activating UART might use default pins and activate an UART RX on a pin, which might incur a mA-order penalty. Hence, a useful first step in optimizing power is to identify what functionality you need and ensure all else is always powered down (eg uart rx, clocks and timers, radio peripherals.
Hmm, those are some worrying news for Zephyr, but also for Linux. For reasons that escape my full understanding, a lot of embedded hardware needs Linux to work. If Zephyr, which I bet has been carefully crafted for microcontrollers, leaves some unnecessary things on, who knows what even an extremely trimmed down Linux running in, say, the beagle board, gets away with.
As an off-topic remark, I've used the qoitech arc power analyzer quite a bit and it's quite nice and easy to use, when your DUT is <5V and low amps. There's also the Nordic PPK2 kit, which is cheaper but I haven't tried it. Both are aiming at the crowd that prefers a simple, handles-most-use-cases, little USB-connected box that runs the client on your computer, rather than a separate bulky thing with screen and whatnot. Trade-offs of course though.
I did something similar, but less scientific, comparing ESP-IDF and esp-hal (Rust). Unfortunately I learned that the optimizations that are already in ESP-IDF (most of all automatic light sleep between BLE advertisments) are hard to replicate in Rust/esp-hal/embassy and so for battery powered devices you might want to stick to C++/ESP-IDF
Do you have some more background information why it is hard to replicate?
ESP32 never was good for any powersaving applications.
While the ESP32 does have a high inrush current, its ULP coprocessor is quite capable, drawing only 12µA@3.3V during Deep Sleep. I have a fleet of AA-powered ESP32 devices at home that last 6–12 months, plus some solar-powered ones that run indefinitely.
... but then if you really need to save power you don't use a dev board, or at least disable the parts you don't need on boot and desolder some leds?
As of the recent launch of the ESP32-S31, all the ESP32 product lines have been migrated to RISC-V.
Unsurprisingly, the old, non-standard, encumbered architecture is not missed.