ellip{100.0, Vec{0.0, 0.0}};
ProfitOracle omega{unit_price, scale, limit, elasticities, price_out};
double gamma = 0.0;
auto result = cutting_plane_optim(omega, ellip, gamma);
ankerl::nanobench::doNotOptimizeAway(result);
});
```
---
### The Challenge: Slow Benchmarks π’
.pull-left[
The original conversion had a **critical bug**:
.mermaid[
graph TD
Problem["Problem: All benchmarks used\nepochs=50, warmup=100"] --> LP["Lowpass benchmarks\nmax_iters=50000\n~250ms per run"]
Problem --> SC["Scaling benchmarks\nmax_iters=4000\n~50ms per run"]
LP --> Result["Result: BM_ell_compare\nwould take >5 minutes β°"]
SC --> Result
style Problem fill:#f44336,color:#fff
style LP fill:#ff9800
style SC fill:#ff9800
style Result fill:#f44336,color:#fff
]
]
.pull-right[
**Fix**: Split into two bench configs:
```cpp
// Fast benchmarks β 50 epochs
ankerl::nanobench::Bench fast_bench;
fast_bench.warmup(100).epochs(50);
// Slow benchmarks β 3 epochs (minimal repetition)
ankerl::nanobench::Bench slow_bench;
slow_bench.warmup(1).epochs(3).minEpochIterations(1);
```
]
---
### Benchmark Runtime Before vs After β±οΈ
.mermaid[
graph LR
subgraph Before["Before (nanobench default config)"]
B1["BM_ell_compare\n>5 minutes β°"]
B2["BM_lowpass\n>5 minutes β°"]
end
subgraph After["After (epochs tuned)"]
A1["BM_ell_compare\n30 seconds β
"]
A2["BM_lowpass\n2.5 seconds β
"]
end
style Before fill:#ffcdd2
style After fill:#c8e6c9
style B1 fill:#f44336,color:#fff
style B2 fill:#f44336,color:#fff
style A1 fill:#4caf50,color:#fff
style A2 fill:#4caf50,color:#fff
]
**Lesson**: nanobench's automatic iteration estimation multiplies runtime for expensive benchmarks. Always tune `epochs` and `minEpochIterations` for your use case. π
---
### Build System Changes π οΈ
**xmake.lua** β Before vs After:
```lua
-- Before
add_requires("benchmark", { alias = "benchmark" })
target("test_ell")
add_packages("benchmark")
-- After
add_requires("nanobench", { alias = "nanobench" })
target("test_ell")
add_packages("nanobench")
```
**CMake** β `bench/CMakeLists.txt`:
```cmake
# Before
CPMAddPackage(NAME benchmark GITHUB_REPOSITORY google/benchmark ...)
target_link_libraries(${TARGET} benchmark::benchmark ...)
# After
CPMAddPackage(NAME nanobench GITHUB_REPOSITORY martinus/nanobench ...)
target_link_libraries(${TARGET} nanobench ...)
```
Clean, simple, one-for-one replacement. β
---
### What Changed: File-by-File π
.font-sm[
| File | Lines Changed | Type |
|------|:------------:|------|
| `bench/BM_ell.cpp` | 82 β 48 (β34) | Source migration |
| `bench/BM_ell_compare.cpp` | 387 β 331 (β56) | Source migration + fix |
| `bench/BM_lmi.cpp` | 218 β 86 (β132) | Source migration |
| `bench/BM_lowpass.cpp` | 70 β 50 (β20) | Source migration + fix |
| `bench/CMakeLists.txt` | 57 β 50 (β7) | Build system |
| `xmake.lua` | 157 β 150 (β7) | Build system |
| **Total** | **β256 lines** | |
]
**Result**: Cleaner code, fewer dependencies, simpler build. π―
---
class: nord-light, middle, center
## π Part 3: Results & Lessons
---
### Before: All Tests Passing β
```bash
$ xmake run test_ellalgo
[doctest] test cases: 125 | 125 passed | 0 failed | 0 skipped
[doctest] assertions: 414 | 414 passed | 0 failed |
[doctest] Status: SUCCESS!
```
**125 test cases, 414 assertions β all passing** before and after the migration. π§ͺ
The nanobench migration was **purely a build-system and benchmarking change** β zero behavioral changes to the library code.
---
### After: Benchmark Results π
```bash
$ xmake run test_ell
| ns/op | op/s | Ell vs EllStable (profit oracle)
|-------:|-------:|:--------------------------------
| 141,420 | 7,071 | `ELL_normal` β Ell
| 129,830 | 7,702 | `ELL_stable` β EllStable
$ ctest --test-dir build -C Release
1/5 EllAlgoTests .............. 0.68s β
2/5 BM_ell .................... 0.44s β
3/5 BM_ell_compare ............ 30.13s β
4/5 BM_lmi .................... 0.32s β
5/5 BM_lowpass ................ 2.56s β
```
All benchmarks pass via both **xmake** and **CMake** build systems. π
---
### Verification: Ell vs EllStable β
`BM_ell_compare` includes a **correctness verification** step before benchmarking:
```text
Profit normal PASS | iters: Ell=83 Stable=83
Profit robust PASS | iters: Ell=90 Stable=90
LP-32 par PASS | iters: Ell=26027 Stable=26125
LP-32 ser PASS | iters: Ell=40740 Stable=40621
LP-48 par PASS | iters: Ell=35014 Stable=35098
LP-64 par PASS | iters: Ell=27805 Stable=27926
Rand-16 PASS | iters: Ell=2067 Stable=2067
Rand-32 PASS | iters: Ell=4000 Stable=4000
Rand-64 PASS | iters: Ell=2000 Stable=2000
Result: 9/9 passed. β
```
Ell and EllStable produce **identical results** β the stable variant is truly equivalent. π―
---
### What We Learned π
.mermaid[
graph TD
subgraph Technical["Technical Lessons"]
T1["nanobench needs epoch\ntuning for expensive\nbenchmarks"]
T2["CMake + xmake dual build\nmeans updating both\nbuild systems"]
end
subgraph Process["Process Lessons"]
P1["Simpler APIs reduce\nAI hallucination risk"]
P2["Always verify correctness\nbefore comparing perf"]
P3["Dead and redundant\ncode should be removed"]
end
style Technical fill:#e3f2fd
style Process fill:#e8f5e9
style T1 fill:#2196f3
style T2 fill:#ff9800
style P1 fill:#9c27b0,color:#fff
style P2 fill:#4caf50,color:#fff
style P3 fill:#f44336,color:#fff
]
---
### The AI-Assisted Development Angle π€
How does this experience relate to AI-assisted coding?
| Dimension | Impact |
|-----------|--------|
| **Tool choice matters** | Simpler APIs β fewer AI errors |
| **Build system duplication** | 2Γ work for AI agent (xmake + CMake) |
| **Dead code detection** | AI should flag unused/unnecessary targets |
| **Epoch tuning** | AI should recognize when benchmarks are too expensive |
| **Verification first** | AI should validate correctness before measuring performance |
The simplest code is the code the AI doesn't have to touch. π―
---
### Git History π
The migration in **2 clean commits**:
```text
d6e63f9 migrate: replace Google Benchmark with nanobench in benchmark sources
79f8ecd migrate: update build system to use nanobench
```
- **4 source files** converted (BM_ell, BM_ell_compare, BM_lmi, BM_lowpass)
- **2 build system files** updated (xmake.lua, bench/CMakeLists.txt)
- **β256 lines** of code overall π
Clean, atomic, reviewable commits. π§Ή
---
### Summary π
| Metric | Before | After | Delta |
|--------|:------:|:-----:|:-----:|
| **Benchmark framework** | Google Benchmark | nanobench | π’ Simpler |
| **Test suite** | 125/125 passing | 125/125 passing | β
|
| **CMake build** | β
| β
| β
|
| **Xmake build** | β
| β
| β
|
| **Dependencies** | `benchmark` + transitive | `nanobench` (header-only) | π’ Lighter |
| **Lines of code** | More | β256 | π’ Less |
---
### Key Takeaway πΌοΈ
.mermaid[
graph TD
Q["What was achieved\nin this session?"] --> R1["π¦ Migrated benchmarking\nframework"]
Q --> R2["π§ Tuned epochs for\npractical runtime"]
Q --> R3["β
Verified all\n125 tests pass"]
Q --> R4["π Confirmed Ell == EllStable\nin correctness"]
R1 --> F["β
Cleaner codebase\nSimpler builds\nSame correctness"]
R2 --> F
R3 --> F
R4 --> F
style Q fill:#ff9800,stroke:#e65100,stroke-width:3px
style R1 fill:#2196f3,color:#fff
style R2 fill:#f44336,color:#fff
style R3 fill:#4caf50,color:#fff
style R4 fill:#9c27b0,color:#fff
style F fill:#4caf50,color:#fff,stroke:#2e7d32,stroke-width:3px
]
> **TL;DR**: Replaced Google Benchmark with nanobench across 6 files, tuned epoch configs for fast CI, verified 125 tests pass, Ell == EllStable. π―
---
count: false
class: nord-dark, middle, center
## π Q&A
**Google Benchmark vs nanobench**
*Any questions?* π€
---
count: false
class: nord-dark, middle, center
# π Thank You!
## Benchmark Smarter with Simpler Tools! π β‘ π