Skip to content

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/throughput 88574 vs 67757 (+30.7%)
  • RUST sync/sem_take_give 4759 vs 3925 (+21.2%)
  • RUST eventgroup/set_get_bits 1964 vs 1672 (+17.5%)
  • ZIG sync/sem_take_give 4473 vs 3925 (+14.0%)
  • ZIG eventgroup/set_get_bits 1887 vs 1672 (+12.9%)
  • CPP sync/mutex_contention_2t 5157 vs 4584 (+12.5%)
  • RUST sync/mutex_lock_unlock 5647 vs 5042 (+12.0%)
  • CPP sync/mutex_lock_unlock 5615 vs 5042 (+11.4%)
  • CPP native_nuttx/native_sem_create_destroy 3700 vs 3338 (+10.8%)
  • RUST thread/get_self 2830 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