NuttX — heap mode
Raw cross-binding benchmark results measured on STM32F746G-DISCOVERY (Cortex-M7 @ 216 MHz) running Apache NuttX in default heap-allocation mode (_create() / _destroy() API), with 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.
Methodology and reproduction steps: benchmarks overview. Same numbers under CONFIG_OVE_ZERO_HEAP=y: NuttX zero-heap. 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.0 µs | 3.1 µs | +4.8% | 3.1 µs | +3.9% | 3.0 µs | +1.5% |
| time | delay_1ms | 1.98 ms | 1.98 ms | +0.0% | 1.98 ms | +0.0% | 1.98 ms | +0.0% |
| thread | create_destroy | 617.0 µs | 623.0 µs | +1.0% | 591.4 µs | -4.1% | 591.2 µs | -4.2% |
| thread | yield | 3.6 µs | 3.8 µs | +6.3% | 3.7 µs | +3.0% | 3.5 µs | -2.5% |
| thread | get_self | 2.6 µs | 2.6 µs | -1.1% | 2.8 µs | +8.0% | 2.5 µs | -5.8% |
| thread | sleep_1ms | 1.98 ms | 1.98 ms | +0.0% | 1.98 ms | +0.0% | 1.98 ms | +0.0% |
| thread | context_switch | 45.8 µs | 45.6 µs | -0.4% | — | — | 45.8 µs | +0.1% |
| sync | mutex_memory | 24 B | 24 B | — | 24 B | — | 24 B | — |
| sync | sem_memory | 24 B | 24 B | — | 24 B | — | 24 B | — |
| sync | event_memory | 24 B | 24 B | — | 24 B | — | 24 B | — |
| sync | condvar_memory | 40 B | 40 B | — | 40 B | — | 40 B | — |
| sync | mutex_lock_unlock | 5.4 µs | 5.4 µs | +0.9% | 5.3 µs | -1.0% | 5.5 µs | +2.2% |
| sync | mutex_create_destroy | 29.0 µs | 29.3 µs | +0.9% | 30.4 µs | +4.6% | 29.2 µs | +0.6% |
| sync | mutex_contention_2t | 4.7 µs | 5.0 µs | +6.5% | 4.8 µs | +2.6% | 4.8 µs | +2.6% |
| sync | sem_take_give | 4.3 µs | 4.2 µs | -2.1% | 4.8 µs | +12.5% | 4.2 µs | -1.8% |
| sync | sem_create_destroy | 27.7 µs | 28.1 µs | +1.3% | 28.9 µs | +4.3% | 28.0 µs | +0.9% |
| sync | event_signal_wait | 45.3 µs | 45.5 µs | +0.4% | 46.6 µs | +2.8% | 45.8 µs | +1.0% |
| sync | condvar_signal_wait | 62.8 µs | 63.0 µs | +0.4% | 63.9 µs | +1.8% | 63.6 µs | +1.4% |
| sync | recursive_mutex_lock_unlock | 8.5 µs | 8.2 µs | -2.7% | 8.4 µs | -0.7% | 8.2 µs | -2.9% |
| queue | memory | 96 B | 96 B | — | 96 B | — | 96 B | — |
| queue | send_receive | 11.8 µs | 11.6 µs | -1.5% | 11.9 µs | +1.6% | 12.5 µs | +6.4% |
| queue | create_destroy | 57.4 µs | 57.7 µs | +0.5% | 57.7 µs | +0.4% | 59.4 µs | +3.4% |
| queue | throughput_2t | 8.2 µs | 7.5 µs | -8.6% | 8.2 µs | -0.4% | 8.4 µs | +2.6% |
| timer | memory | 24 B | — | — | 24 B | — | 24 B | — |
| timer | create_destroy | 70.5 µs | — | — | 66.7 µs | -5.4% | 67.0 µs | -5.0% |
| timer | start_stop | 27.7 µs | — | — | 27.2 µs | -2.0% | 26.9 µs | -3.0% |
| eventgroup | memory | 32 B | — | — | 32 B | — | 32 B | — |
| eventgroup | set_get_bits | 1.7 µs | — | — | 1.9 µs | +7.7% | 1.7 µs | -3.4% |
| eventgroup | create_destroy | 27.8 µs | — | — | 28.3 µs | +1.8% | 28.0 µs | +0.7% |
| workqueue | memory | 3168 B | 3200 B | — | 3168 B | — | 3168 B | — |
| workqueue | create_destroy | 526.5 µs | 528.8 µs | +0.4% | 535.5 µs | +1.7% | 533.3 µs | +1.3% |
| workqueue | submit_execute | 67.0 µs | 67.7 µs | +1.1% | 69.1 µs | +3.1% | 68.1 µs | +1.5% |
| stream | memory | 360 B | 360 B | — | 360 B | — | 360 B | — |
| stream | send_recv_64B | 54.0 µs | 53.2 µs | -1.4% | 53.4 µs | -1.0% | 53.2 µs | -1.3% |
| stream | create_destroy | 63.8 µs | 63.4 µs | -0.7% | 64.0 µs | +0.2% | 63.2 µs | -1.0% |
| stream | throughput | 69.3 µs | 68.2 µs | -1.6% | 90.7 µs | +30.9% | 67.5 µs | -2.6% |
| native_nuttx | native_mutex_lock_unlock | 15.0 µs | 15.0 µs | -0.3% | 14.9 µs | -1.1% | 15.0 µs | -0.3% |
| native_nuttx | native_mutex_create_destroy | 5.6 µs | 5.7 µs | +3.1% | 5.2 µs | -6.6% | 5.3 µs | -4.6% |
| native_nuttx | native_mutex_contention_2t | 14.0 µs | 14.0 µs | +0.2% | 14.1 µs | +1.0% | 14.2 µs | +1.0% |
| native_nuttx | native_recursive_mutex_lock_unlock | 14.0 µs | 14.0 µs | +0.3% | 14.2 µs | +1.4% | 14.1 µs | +1.0% |
| native_nuttx | native_sem_take_give | 4.5 µs | 4.6 µs | +2.3% | 4.5 µs | -1.3% | 4.3 µs | -3.8% |
| native_nuttx | native_sem_create_destroy | 3.1 µs | 3.2 µs | +2.1% | 3.0 µs | -5.3% | 3.1 µs | -2.1% |
| native_nuttx | native_condvar_signal_wait | 99.0 µs | 98.8 µs | -0.2% | 98.9 µs | -0.1% | 97.8 µs | -1.2% |
| native_nuttx | native_event_signal_wait | 81.8 µs | 98.5 µs | +20.4% | 98.6 µs | +20.5% | 80.2 µs | -1.9% |
| native_nuttx | native_thread_yield | 3.5 µs | 3.6 µs | +2.3% | 3.5 µs | -1.2% | 3.3 µs | -5.4% |
| native_nuttx | native_thread_sleep_1ms | 1.98 ms | 1.98 ms | +0.0% | 1.98 ms | +0.0% | 1.98 ms | +0.0% |
| native_nuttx | native_thread_create_destroy | 495.4 µs | 500.8 µs | +1.1% | 488.3 µs | -1.4% | 489.4 µs | -1.2% |
| native_nuttx | native_thread_context_switch | 45.5 µs | 45.5 µs | -0.0% | 45.1 µs | -1.0% | 45.4 µs | -0.4% |
| native_nuttx | native_queue_send_receive | 33.4 µs | 33.2 µs | -0.6% | 33.9 µs | +1.5% | 34.7 µs | +3.9% |
| native_nuttx | native_queue_create_destroy | 397.1 µs | 398.8 µs | +0.4% | 394.8 µs | -0.6% | 395.5 µs | -0.4% |
| thread | ctx_switch | — | — | — | 46.4 µs | — | — | — |
Cases with |Δ| > 10.0% vs C:
- RUST
stream/throughput90709 vs 69311 (+30.9%) - RUST
native_nuttx/native_event_signal_wait98571 vs 81778 (+20.5%) - CPP
native_nuttx/native_event_signal_wait98477 vs 81778 (+20.4%) - RUST
sync/sem_take_give4807 vs 4271 (+12.5%)
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 | 3593 ns | 3494 ns | +99 ns |
| Thread yield | CPP | ove::Thread::yield | 3820 ns | 3576 ns | +244 ns |
| Thread yield | RUST | ove::Thread::yield | 3701 ns | 3451 ns | +250 ns |
| Thread yield | ZIG | ove.Thread.yield | 3504 ns | 3304 ns | +200 ns |
| Thread sleep 1ms | C | ove_thread_sleep_ms(1) | 1983491 ns | 1983433 ns | +58 ns |
| Thread sleep 1ms | CPP | ove::Thread::sleep_ms(1) | 1983931 ns | 1984009 ns | -78 ns |
| Thread sleep 1ms | RUST | ove::Thread::sleep_ms(1) | 1984299 ns | 1984228 ns | +71 ns |
| Thread sleep 1ms | ZIG | ove.Thread.sleepMs(1) | 1983887 ns | 1983892 ns | -5 ns |
| Thread create+destroy | C | ove_thread_create+destroy | 617033 ns | 495431 ns | +121602 ns |
| Thread create+destroy | CPP | ove::Thread (ctor+dtor) | 622994 ns | 500848 ns | +122146 ns |
| Thread create+destroy | RUST | ove::Thread::spawn+join | 591433 ns | 488292 ns | +103141 ns |
| Thread create+destroy | ZIG | ove.Thread.spawn+join | 591226 ns | 489374 ns | +101852 ns |
| Thread context_switch (2t) | C | ove ping-pong (2t) | 45764 ns | 45543 ns | +221 ns |
| Thread context_switch (2t) | CPP | ove ping-pong (2t) | 45565 ns | 45533 ns | +32 ns |
| Thread context_switch (2t) | ZIG | ove ping-pong (2t) | 45824 ns | 45378 ns | +446 ns |
| Mutex lock+unlock | C | ove_mutex_lock+unlock | 5372 ns | 15042 ns | -9670 ns |
| Mutex lock+unlock | CPP | ove::Mutex::lock+unlock | 5421 ns | 14991 ns | -9570 ns |
| Mutex lock+unlock | RUST | ove::Mutex::lock+unlock | 5317 ns | 14870 ns | -9553 ns |
| Mutex lock+unlock | ZIG | ove.Mutex.lock+unlock | 5491 ns | 15003 ns | -9512 ns |
| Mutex create+destroy | C | ove_mutex_create+destroy | 29028 ns | 5561 ns | +23467 ns |
| Mutex create+destroy | CPP | ove::Mutex (ctor+dtor) | 29285 ns | 5736 ns | +23549 ns |
| Mutex create+destroy | RUST | ove::Mutex (new+drop) | 30376 ns | 5193 ns | +25183 ns |
| Mutex create+destroy | ZIG | ove.Mutex.create+destroy | 29204 ns | 5305 ns | +23899 ns |
| Mutex contention (2t) | C | ove_mutex_lock+unlock (×2t) | 4665 ns | 14014 ns | -9349 ns |
| Mutex contention (2t) | CPP | ove::Mutex::lock+unlock (×2t) | 4968 ns | 14041 ns | -9073 ns |
| Mutex contention (2t) | RUST | ove::Mutex::lock+unlock (×2t) | 4784 ns | 14148 ns | -9364 ns |
| Mutex contention (2t) | ZIG | ove.Mutex.lock+unlock (×2t) | 4785 ns | 14154 ns | -9369 ns |
| Recursive mutex lock+unlock | C | ove_rmtx_lock+unlock | 8480 ns | 13962 ns | -5482 ns |
| Recursive mutex lock+unlock | CPP | ove::RMutex::lock+unlock | 8247 ns | 14008 ns | -5761 ns |
| Recursive mutex lock+unlock | RUST | ove::RMutex::lock+unlock | 8417 ns | 14161 ns | -5744 ns |
| Recursive mutex lock+unlock | ZIG | ove.RMutex.lock+unlock | 8234 ns | 14100 ns | -5866 ns |
| Sem take+give | C | ove_sem_take+give | 4271 ns | 4515 ns | -244 ns |
| Sem take+give | CPP | ove::Sem::take+give | 4181 ns | 4621 ns | -440 ns |
| Sem take+give | RUST | ove::Sem::take+give | 4807 ns | 4458 ns | +349 ns |
| Sem take+give | ZIG | ove.Sem.take+give | 4192 ns | 4343 ns | -151 ns |
| Sem create+destroy | C | ove_sem_create+destroy | 27743 ns | 3120 ns | +24623 ns |
| Sem create+destroy | CPP | ove::Sem (ctor+dtor) | 28117 ns | 3187 ns | +24930 ns |
| Sem create+destroy | RUST | ove::Sem (new+drop) | 28924 ns | 2954 ns | +25970 ns |
| Sem create+destroy | ZIG | ove.Sem.create+destroy | 27980 ns | 3053 ns | +24927 ns |
| Condvar signal+wait | C | ove_condvar_signal+wait | 62779 ns | 98978 ns | -36199 ns |
| Condvar signal+wait | CPP | ove::Condvar::signal+wait | 63014 ns | 98799 ns | -35785 ns |
| Condvar signal+wait | RUST | ove::Condvar::signal+wait | 63879 ns | 98852 ns | -34973 ns |
| Condvar signal+wait | ZIG | ove.Condvar.signal+wait | 63641 ns | 97830 ns | -34189 ns |
| Event signal+wait | C | ove_event_signal+wait | 45346 ns | 81778 ns | -36432 ns |
| Event signal+wait | CPP | ove::Event::signal+wait | 45532 ns | 98477 ns | -52945 ns |
| Event signal+wait | RUST | ove::Event::signal+wait | 46609 ns | 98571 ns | -51962 ns |
| Event signal+wait | ZIG | ove.Event.signal+wait | 45822 ns | 80228 ns | -34406 ns |
| Queue send+receive | C | ove_queue_send+receive | 11759 ns | 33412 ns | -21653 ns |
| Queue send+receive | CPP | ove::Queue::send+recv | 11578 ns | 33200 ns | -21622 ns |
| Queue send+receive | RUST | ove::Queue::send+recv | 11948 ns | 33905 ns | -21957 ns |
| Queue send+receive | ZIG | ove.Queue.send+recv | 12510 ns | 34730 ns | -22220 ns |
| Queue create+destroy | C | ove_queue_create+destroy | 57441 ns | 397072 ns | -339631 ns |
| Queue create+destroy | CPP | ove::Queue (ctor+dtor) | 57729 ns | 398829 ns | -341100 ns |
| Queue create+destroy | RUST | ove::Queue (new+drop) | 57670 ns | 394772 ns | -337102 ns |
| Queue create+destroy | ZIG | ove.Queue.create+destroy | 59390 ns | 395493 ns | -336103 ns |