NuttX — zero-heap mode
Raw cross-binding benchmark results measured on STM32F746G-DISCOVERY (Cortex-M7 @ 216 MHz) running Apache NuttX with CONFIG_OVE_ZERO_HEAP=y (_init() / _deinit() API, caller-supplied static storage, heap locked at ove_run()) and CONFIG_OVE_BENCHMARK_WORST_CASE_TIMING=y — caches and flash accelerators disabled to approximate cacheless ARM-MCU timing. See benchmarks overview for the worst-case-timing methodology.
Under zero-heap, *_create_destroy and *_memory cases are gated out — the create/destroy API isn't generated.
Methodology and reproduction steps: benchmarks overview. Heap-mode counterpart: NuttX heap mode. Interpretation: heap vs zero-heap, per-binding analysis, wrapper-vs-native notes.
Generated by
scripts/bench_compare.py. Trimmed-mean (top 1% dropped) when available, else avg. Delta column is(binding − C) / C— values within ±10.0% are within typical measurement noise.
native_* rows. bench_native_nuttx.c is C code calling raw NuttX APIs (nxsem_*, pthread_*), compiled identically into every binary; the CPP/RUST/ZIG columns for those rows are the same C code measured in three different processes.
NuttX
| Suite | Case | C | CPP | Δ CPP | RUST | Δ RUST | ZIG | Δ ZIG |
|---|---|---|---|---|---|---|---|---|
| time | time_get_us_overhead | 3.1 µs | 3.3 µs | +6.2% | 3.2 µs | +0.4% | 3.1 µs | -0.4% |
| time | delay_1ms | 1.99 ms | 1.98 ms | -0.0% | 1.98 ms | -0.0% | 1.98 ms | -0.1% |
| thread | yield | 3.7 µs | 4.0 µs | +7.0% | 4.0 µs | +5.9% | 3.7 µs | +0.1% |
| thread | get_self | 2.6 µs | 2.6 µs | +2.0% | 2.8 µs | +10.0% | 2.5 µs | -3.2% |
| thread | sleep_1ms | 1.99 ms | 1.99 ms | -0.0% | 1.98 ms | -0.0% | 1.98 ms | -0.1% |
| thread | context_switch | 43.7 µs | 43.9 µs | +0.6% | — | — | 43.8 µs | +0.3% |
| sync | mutex_lock_unlock | 5.0 µs | 5.6 µs | +11.4% | 5.6 µs | +12.0% | 5.5 µs | +8.8% |
| sync | mutex_contention_2t | 4.6 µs | 5.2 µs | +12.5% | 4.9 µs | +7.7% | 4.9 µs | +5.9% |
| sync | sem_take_give | 3.9 µs | 4.3 µs | +9.0% | 4.8 µs | +21.2% | 4.5 µs | +14.0% |
| sync | event_signal_wait | 44.0 µs | 43.9 µs | -0.3% | 44.1 µs | +0.2% | 44.3 µs | +0.6% |
| sync | condvar_signal_wait | 61.7 µs | 61.6 µs | -0.3% | 62.2 µs | +0.7% | 62.0 µs | +0.3% |
| sync | recursive_mutex_lock_unlock | 8.0 µs | 8.2 µs | +2.8% | 8.5 µs | +6.9% | 7.8 µs | -1.6% |
| queue | send_receive | 11.6 µs | 11.6 µs | +0.1% | 12.0 µs | +3.6% | 11.9 µs | +3.0% |
| queue | throughput_2t | 7.9 µs | 8.1 µs | +2.6% | 8.4 µs | +6.0% | 8.1 µs | +1.6% |
| timer | start_stop | 29.5 µs | 28.7 µs | -2.6% | 30.7 µs | +4.3% | 28.5 µs | -3.2% |
| eventgroup | set_get_bits | 1.7 µs | 1.7 µs | -1.0% | 2.0 µs | +17.5% | 1.9 µs | +12.9% |
| workqueue | submit_execute | 69.2 µs | 69.0 µs | -0.3% | 70.4 µs | +1.8% | 68.4 µs | -1.2% |
| stream | send_recv_64B | 52.8 µs | 53.7 µs | +1.7% | 54.7 µs | +3.6% | 52.3 µs | -0.9% |
| stream | throughput | 67.8 µs | 67.0 µs | -1.1% | 88.6 µs | +30.7% | 72.7 µs | +7.3% |
| native_nuttx | native_mutex_lock_unlock | 14.8 µs | 15.3 µs | +2.8% | 15.5 µs | +4.7% | 14.9 µs | +0.3% |
| native_nuttx | native_mutex_create_destroy | 5.7 µs | 5.5 µs | -3.7% | 5.4 µs | -5.7% | 5.9 µs | +3.6% |
| native_nuttx | native_mutex_contention_2t | 13.8 µs | 14.4 µs | +4.5% | 14.4 µs | +4.8% | 13.7 µs | -0.4% |
| native_nuttx | native_recursive_mutex_lock_unlock | 13.6 µs | 14.3 µs | +5.2% | 14.5 µs | +7.1% | 13.9 µs | +2.4% |
| native_nuttx | native_sem_take_give | 4.5 µs | 4.6 µs | +1.1% | 4.5 µs | -1.4% | 4.6 µs | +0.6% |
| native_nuttx | native_sem_create_destroy | 3.3 µs | 3.7 µs | +10.8% | 3.4 µs | +3.0% | 3.5 µs | +4.5% |
| native_nuttx | native_condvar_signal_wait | 97.1 µs | 96.7 µs | -0.4% | 97.4 µs | +0.3% | 96.2 µs | -0.9% |
| native_nuttx | native_event_signal_wait | 97.4 µs | 96.7 µs | -0.7% | 97.1 µs | -0.2% | 96.3 µs | -1.1% |
| native_nuttx | native_thread_yield | 3.3 µs | 3.3 µs | +2.0% | 3.3 µs | +1.2% | 3.3 µs | +1.3% |
| native_nuttx | native_thread_sleep_1ms | 1.99 ms | 1.99 ms | -0.0% | 1.98 ms | -0.0% | 1.98 ms | -0.1% |
| native_nuttx | native_thread_create_destroy | 489.3 µs | 495.6 µs | +1.3% | 487.9 µs | -0.3% | 495.4 µs | +1.2% |
| native_nuttx | native_thread_context_switch | 43.8 µs | 43.5 µs | -0.7% | 43.6 µs | -0.6% | 43.6 µs | -0.5% |
| native_nuttx | native_queue_send_receive | 33.1 µs | 33.1 µs | +0.0% | 33.6 µs | +1.3% | 35.5 µs | +7.1% |
| native_nuttx | native_queue_create_destroy | 398.9 µs | 404.7 µs | +1.4% | 398.6 µs | -0.1% | 396.0 µs | -0.7% |
| thread | ctx_switch | — | — | — | 44.1 µs | — | — | — |
Cases with |Δ| > 10.0% vs C:
- RUST
stream/throughput88574 vs 67757 (+30.7%) - RUST
sync/sem_take_give4759 vs 3925 (+21.2%) - RUST
eventgroup/set_get_bits1964 vs 1672 (+17.5%) - ZIG
sync/sem_take_give4473 vs 3925 (+14.0%) - ZIG
eventgroup/set_get_bits1887 vs 1672 (+12.9%) - CPP
sync/mutex_contention_2t5157 vs 4584 (+12.5%) - RUST
sync/mutex_lock_unlock5647 vs 5042 (+12.0%) - CPP
sync/mutex_lock_unlock5615 vs 5042 (+11.4%) - CPP
native_nuttx/native_sem_create_destroy3700 vs 3338 (+10.8%) - RUST
thread/get_self2830 vs 2572 (+10.0%)
Wrapper vs native NuttX API (within-run delta)
Each row pairs one binding's wrapper measurement against the raw NuttX API baseline measured in the same process. See wrapper-vs-native notes for IPC caveats, lifecycle/intrinsic-cost interpretation, and notes on cross-process baseline variance.
| Operation | Binding | Wrapper called | Wrapper ns | Native ns | Δ |
|---|---|---|---|---|---|
| Thread yield | C | ove_thread_yield | 3732 ns | 3258 ns | +474 ns |
| Thread yield | CPP | ove::Thread::yield | 3994 ns | 3322 ns | +672 ns |
| Thread yield | RUST | ove::Thread::yield | 3953 ns | 3296 ns | +657 ns |
| Thread yield | ZIG | ove.Thread.yield | 3735 ns | 3299 ns | +436 ns |
| Thread sleep 1ms | C | ove_thread_sleep_ms(1) | 1985088 ns | 1985114 ns | -26 ns |
| Thread sleep 1ms | CPP | ove::Thread::sleep_ms(1) | 1985016 ns | 1985058 ns | -42 ns |
| Thread sleep 1ms | RUST | ove::Thread::sleep_ms(1) | 1984733 ns | 1984743 ns | -10 ns |
| Thread sleep 1ms | ZIG | ove.Thread.sleepMs(1) | 1983370 ns | 1983388 ns | -18 ns |
| Thread context_switch (2t) | C | ove ping-pong (2t) | 43696 ns | 43831 ns | -135 ns |
| Thread context_switch (2t) | CPP | ove ping-pong (2t) | 43947 ns | 43544 ns | +403 ns |
| Thread context_switch (2t) | ZIG | ove ping-pong (2t) | 43834 ns | 43596 ns | +238 ns |
| Mutex lock+unlock | C | ove_mutex_lock+unlock | 5042 ns | 14830 ns | -9788 ns |
| Mutex lock+unlock | CPP | ove::Mutex::lock+unlock | 5615 ns | 15251 ns | -9636 ns |
| Mutex lock+unlock | RUST | ove::Mutex::lock+unlock | 5647 ns | 15520 ns | -9873 ns |
| Mutex lock+unlock | ZIG | ove.Mutex.lock+unlock | 5487 ns | 14878 ns | -9391 ns |
| Mutex contention (2t) | C | ove_mutex_lock+unlock (×2t) | 4584 ns | 13778 ns | -9194 ns |
| Mutex contention (2t) | CPP | ove::Mutex::lock+unlock (×2t) | 5157 ns | 14395 ns | -9238 ns |
| Mutex contention (2t) | RUST | ove::Mutex::lock+unlock (×2t) | 4937 ns | 14434 ns | -9497 ns |
| Mutex contention (2t) | ZIG | ove.Mutex.lock+unlock (×2t) | 4853 ns | 13717 ns | -8864 ns |
| Recursive mutex lock+unlock | C | ove_rmtx_lock+unlock | 7969 ns | 13563 ns | -5594 ns |
| Recursive mutex lock+unlock | CPP | ove::RMutex::lock+unlock | 8191 ns | 14271 ns | -6080 ns |
| Recursive mutex lock+unlock | RUST | ove::RMutex::lock+unlock | 8518 ns | 14521 ns | -6003 ns |
| Recursive mutex lock+unlock | ZIG | ove.RMutex.lock+unlock | 7844 ns | 13893 ns | -6049 ns |
| Sem take+give | C | ove_sem_take+give | 3925 ns | 4525 ns | -600 ns |
| Sem take+give | CPP | ove::Sem::take+give | 4278 ns | 4575 ns | -297 ns |
| Sem take+give | RUST | ove::Sem::take+give | 4759 ns | 4460 ns | +299 ns |
| Sem take+give | ZIG | ove.Sem.take+give | 4473 ns | 4554 ns | -81 ns |
| Condvar signal+wait | C | ove_condvar_signal+wait | 61748 ns | 97088 ns | -35340 ns |
| Condvar signal+wait | CPP | ove::Condvar::signal+wait | 61559 ns | 96737 ns | -35178 ns |
| Condvar signal+wait | RUST | ove::Condvar::signal+wait | 62210 ns | 97370 ns | -35160 ns |
| Condvar signal+wait | ZIG | ove.Condvar.signal+wait | 61954 ns | 96232 ns | -34278 ns |
| Event signal+wait | C | ove_event_signal+wait | 44004 ns | 97386 ns | -53382 ns |
| Event signal+wait | CPP | ove::Event::signal+wait | 43853 ns | 96739 ns | -52886 ns |
| Event signal+wait | RUST | ove::Event::signal+wait | 44107 ns | 97147 ns | -53040 ns |
| Event signal+wait | ZIG | ove.Event.signal+wait | 44266 ns | 96325 ns | -52059 ns |
| Queue send+receive | C | ove_queue_send+receive | 11591 ns | 33132 ns | -21541 ns |
| Queue send+receive | CPP | ove::Queue::send+recv | 11604 ns | 33144 ns | -21540 ns |
| Queue send+receive | RUST | ove::Queue::send+recv | 12005 ns | 33572 ns | -21567 ns |
| Queue send+receive | ZIG | ove.Queue.send+recv | 11935 ns | 35494 ns | -23559 ns |