Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions docs/tuning/2026-08-11-cmake-build-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Where the C++ optimisation flags come from, 2026-08-11

**Verdict: `pixi run build` passes `-DCMAKE_BUILD_TYPE=Release`, and it changes
nothing measurable.** An empty `CMAKE_BUILD_TYPE` in `build/*/CMakeCache.txt`
looks like an unoptimised robot and is not one — which is the thing worth
recording here.

Empty means CMake appends no `CMAKE_CXX_FLAGS_<CONFIG>`; it does not mean `-O0`,
because `CMAKE_CXX_FLAGS` is seeded from the environment's `CXXFLAGS` and the
conda compiler packages export one — `-O2` on linux-64, **`-O3` on
linux-aarch64**. mote-01's real compile lines carried `-O3` before this change.
`kinematic_icp` was never in question either: its own CMakeLists does
`set(CMAKE_BUILD_TYPE Release)` (`ros/CMakeLists.txt:26`), shadowing the cache,
so its objects already had `-O3 -DNDEBUG`.

So the flag adds `-DNDEBUG` on the robot and takes linux-64 from `-O2` to `-O3`.
Its point is that the level is now stated by the repo rather than inherited from
whichever toolchain the solve picked, and survives a build outside pixi.
**Not `RelWithDebInfo`**: config flags are appended *after* `CXXFLAGS`, so its
`-O2` would beat the Pi's `-O3` and lower optimisation.

## Measured

Replaying mapping bag `20260729_160009` into `localization_launch.py`
(`use_sim_time:=true`) drives the real ICP at the recorded 10.0 Hz, identical
input each run, so only the binary differs. Container `utime + stime` over a
120 s window, 3 reps a side, rebuild between:

| | mean CPU-s / 120 s | mean ms per scan |
| --- | --- | --- |
| before | 2.207 | 1.837 |
| after | 2.200 | 1.831 |

−0.3% against a ±0.7% within-group spread: no effect, as expected from flags
that barely moved. Also worth knowing: the whole container costs **1.8% of one
core**, so it is not where a nav mission's load goes.

## `-ffp-contract=off` survives Release

`odom_tf_relay`'s bit-identity against the Python it replaced depends on that
flag (`mote_nav/CMakeLists.txt:60`), and Release now stacks `-O3` over it.
Target options are emitted last, so it still wins — counted in the shipped
aarch64 objects, not inferred: `libodom_tf_relay_component.so` holds **0** fused
multiply-adds before and after, while `libicp_odom_gate_component.so` (same
`-O3`, no flag) holds **11** both times, so the zero is the flag and not a
target without FMA. `test_odom_tf_relay.cpp` cannot catch this — it compares the
relay against reference arithmetic in the same TU, under the same flag.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,4 @@ nav:
- Camera layer decay: tuning/2026-07-29-camera-layer-decay.md
- Monitor-node CPU: tuning/2026-08-11-monitor-cpu.md
- Orientation picking: tuning/2026-08-11-orientation-picking.md
- C++ build type: tuning/2026-08-11-cmake-build-type.md
5 changes: 4 additions & 1 deletion pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ version = "0.1.0"

[tasks]
submodules = "git submodule update --init"
build = { cmd = "colcon build --symlink-install --cmake-args -G Ninja -DCMAKE_POLICY_VERSION_MINIMUM=3.5", depends-on = [
# Release, so optimisation is stated here rather than inherited from whatever the
# conda activation puts in CXXFLAGS. NOT RelWithDebInfo: config flags land after
# CXXFLAGS, so its -O2 would lower the Pi's -O3. See docs/tuning/2026-08-11.
build = { cmd = "colcon build --symlink-install --cmake-args -G Ninja -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_BUILD_TYPE=Release", depends-on = [
"submodules",
] }
test = { cmd = "colcon test --packages-select mote_hardware mote_bringup mote_nav mote_perception mote_tasks mote_arm mote_fleet --event-handlers console_direct+ && colcon test-result --verbose", depends-on = [
Expand Down