Energy & Power · Study deck
Software Optimization Techniques
Picture a battery sensor that wakes every second to ask whether anything happened.
Battery Bruno is your guide for this deck.

After studying this chapter
Learning objectives
You will be able to:
- Choose compiler and linker settings from evidence instead of habit.
- Identify when code size, memory traffic, active time, or wakeups dominate firmware cost.
- Apply data-layout and buffering changes that reduce copies and memory stalls.
- Decide when code-level changes such as inlining, lookup tables, or loop restructuring are worth the risk.
Major section
Start With Firmware That Wakes Too Often · In 60 Seconds
Most wake-ups do no useful work, yet each one starts clocks and code.
- Firmware means the software stored on the device.
- Duty cycle means the share of time a device spends active instead of asleep.
- This runway does not prove that every software change saves energy.
Major section
Firmware Optimization Loop
It follows one polling example through profiling, one change, a same-workload check, and a written keep-or-rollback decision.
- The final card therefore asks for the full-cycle trace, correct results, and memory and build-size checks before keeping the change.
- Bruno sets a battery target, measures wake, work, radio, and sleep, then spots the tall energy bar.
Major section
Code-Level Changes · Compiler And Build Choices
Compiler flags are a starting point, not an optimization strategy by themselves.
- You need readable stepping, assertions, and source-level diagnosis.
- The product needs stable speed without aggressive code growth.
- Flash, update size, or instruction fetch is the limit.
- A measured hot path blocks a deadline or keeps the device awake.
Major section
Data, Memory, And Copies · Event-Driven Sleep
Data movement can dominate firmware cost.
- A clean algorithm can still waste energy if it copies buffers, parses verbose payloads, or wakes the CPU for every small transfer.
- Busy waiting is one of the easiest ways to waste energy.
- Replacing a polling loop is only useful if firmware has a complete route back to sleep.
Major section
Polling Keeps The Core Awake; Events Let It Sleep
The processor saves state, runs a deliberately short handler, restores state, and resumes at the interrupted point.
- That order separates detection from expensive application work: the peripheral can wake the core, but the handler should capture the event and defer longer processing.
Major section
Phoebe's Field Notes: Why "More Than 8000 Days" Is A Ceiling, Not A Forecast · A Busy-Waiting delay() Does Not Sleep, And You Must Offload The Watching
The mathematical gist: A 2,000 mAh, 3.7 V pack stores 7.40 Wh at nameplate conditions.
- At 2% monthly self-discharge, 29.8% remains after five years and 8.85% after ten, so an ideal 8,000-day current-draw ceiling is not a field-life promise.
Major section
Compiler Optimization Modes
Optimization flags express a preference to a particular toolchain; they do not guarantee a fixed list of transformations.
- In common GCC- and Clang-style workflows, a speed-focused -O3 build may inline more aggressively, unroll or vectorize loops, reorder instructions, and create separate fast paths for alignment or aliasing cases.
- A size-focused -Os build usually discourages growth, favors shorter encodings, and may keep branches or calls that a speed build removes.
- A size build can reduce fetch energy, yet keep the core awake longer.
- The winning flag is the one that lowers measured charge per useful task while preserving timing, stack, numerical, and update-slot requirements.
Major section
Code Density and Instruction-Level Parallelism
Code occupies silicon and consumes energy every time it is fetched.
- A memory large enough to hold software can dwarf a small processor core, so instruction density can affect area, fetch bandwidth, leakage, and update time.
- Compressed instruction sets commonly provide short 16-bit encodings alongside wider 32-bit encodings.
Major section
Code Density and Instruction-Level Parallelism (continued)
VLIW therefore exchanges dynamic scheduling hardware for compiler scheduling and can waste code space when parallelism is sparse.
- Short forms save bytes but have fewer encoding bits, so they may expose only a subset of registers, smaller immediate ranges, fewer addressing modes, or an explicit mode/history constraint on older designs.
- The assembler expands to a wider form when operands do not fit.
- None is a reliable proxy for the other two.
Major section
Vectorization and Tail Handling
The: TAIL [8 9] then branches to masked lanes or scalar cleanup, so the speedup boundary includes setup and remainder work and never reads beyond x[9] merely to fill a vector.
- The vector loop executes q times over qW elements; a tail path handles the remaining r elements.
Major section
Vectorization and Tail Handling (continued)
For N=18 and W=4, there are four vector iterations covering 16 elements and two scalar tail iterations.
- Omitting the tail silently leaves c[16] and c[17] wrong.
- Some instruction sets provide masked loads and stores, allowing one final vector operation with only the first r lanes enabled.
- so short arrays, tails, alignment repair, alias checks, and memory bandwidth reduce the gain.
Major section
Predication and Function Inlining · Summary
The lower comparison changes currency from cycles to bytes.
- A shared call keeps one 12 B body plus call and return boundaries; inlining it at three sites removes those boundaries but copies the body, adding 24 B relative to one copy.
- If its direction is hard to predict, a misprediction flushes useful pipeline work.
Deck summary
Key takeaways
Most wake-ups do no useful work, yet each one starts clocks and code.
- It follows one polling example through profiling, one change, a same-workload check, and a written keep-or-rollback decision.
- Compiler flags are a starting point, not an optimization strategy by themselves.
- Data movement can dominate firmware cost.
- The processor saves state, runs a deliberately short handler, restores state, and resumes at the interrupted point.
Retrieval practice
Recall check 1 of 6

Battery Bruno says: answer from memory, then check your reasoning.
Q1A developer wants to inline a large function that rarely runs. What should the review require?
Show answer
Answer: D Code changes need a measured bottleneck and regression gate.
Retrieval practice
Recall check 2 of 6

Battery Bruno says: answer from memory, then check your reasoning.
Q2A profile shows firmware spends much of its active window waiting for a peripheral transfer to complete. Which software optimization should be evaluated first?
Show answer
Answer: D Optimization follows the measured bottleneck.
Retrieval practice
Recall check 3 of 6

Battery Bruno says: answer from memory, then check your reasoning.
Q3How should the team compare the two firmware builds before choosing one?
Show answer
Answer: D Software optimization is multidimensional.
Retrieval practice
Recall check 4 of 6

Battery Bruno says: answer from memory, then check your reasoning.
Q4Why does an event-driven firmware structure usually beat a polling loop on battery life by a large margin?
Show answer
Answer: C Polling keeps the core active at milliamps while event-driven firmware sleeps at microamps and wakes only on real events.
Retrieval practice
Recall check 5 of 6

Battery Bruno says: answer from memory, then check your reasoning.
Q5A node handles about 10 events per hour, each 5 ms at 8 mA, and can sleep at 10 uA. What is the approximate average current if it is event-driven rather than polling at 8 mA?
Show answer
Answer: B The bursts contribute 0.4 mA-s per hour, or about 0.11 uA averaged. Add the 10 uA sleep floor for roughly 10.1 uA total, about 800x below 8 mA polling.
Retrieval practice
Recall check 6 of 6

Battery Bruno says: answer from memory, then check your reasoning.
Q6A firmware author changes fixed-interval reporting to use delay(1000) between reports expecting big energy savings, but the average current barely drops. A trace shows the processor stays active during the one-second delay on this platform. Why?
Show answer
Answer: A In this scenario, delay() uses a busy-wait implementation, so the core stays active for the whole second.
Print reference
Answers 1 of 2
Answer key.
- D · Code changes need a measured bottleneck and regression gate.
- D · Optimization follows the measured bottleneck.
- D · Software optimization is multidimensional.
- C · Polling keeps the core active at milliamps while event-driven firmware sleeps at microamps and wakes only on real events.
- B · The bursts contribute 0.4 mA-s per hour, or about 0.11 uA averaged. Add the 10 uA sleep floor for roughly 10.1 uA total, about 800x below 8 mA polling.
Print reference
Answers 2 of 2
Answer key.
- A · In this scenario, delay() uses a busy-wait implementation, so the core stays active for the whole second.