Zephyr — zero-heap mode
Raw cross-binding benchmark results measured on STM32F746G-DISCOVERY (Cortex-M7 @ 216 MHz) running Zephyr RTOS 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: Zephyr 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_zephyr.c is C code calling raw Zephyr APIs (k_mutex_*, k_sem_*, k_msgq_*), compiled identically into every binary; the CPP/RUST/ZIG columns for those rows are the same C code measured in three different processes.
Zephyr
| Suite | Case | C | CPP | Δ CPP | RUST | Δ RUST | ZIG | Δ ZIG |
|---|---|---|---|---|---|---|---|---|
| time | time_get_us_overhead | 2.4 µs | 2.4 µs | -0.4% | 2.5 µs | +3.1% | 2.6 µs | +5.0% |
| time | delay_1ms | 1.09 ms | 1.09 ms | -0.0% | 1.09 ms | -0.1% | 1.09 ms | -0.0% |
| thread | yield | 10.5 µs | 10.9 µs | +3.8% | 10.5 µs | -0.4% | 10.8 µs | +2.4% |
| thread | get_self | 855 ns | 869 ns | +1.6% | 1.1 µs | +25.1% | 957 ns | +11.9% |
| thread | sleep_1ms | 1.09 ms | 1.09 ms | -0.0% | 1.09 ms | -0.1% | 1.09 ms | -0.0% |
| thread | context_switch | 56.6 µs | 55.7 µs | -1.6% | — | — | 57.4 µs | +1.4% |
| sync | mutex_lock_unlock | 2.9 µs | 2.9 µs | -0.5% | 3.2 µs | +10.0% | 2.9 µs | +0.8% |
| sync | mutex_contention_2t | 3.0 µs | 46.0 µs | +1430.0% | 3.4 µs | +11.7% | 45.4 µs | +1409.5% |
| sync | sem_take_give | 2.3 µs | 1.9 µs | -16.2% | 2.1 µs | -10.2% | 2.1 µs | -8.6% |
| sync | event_signal_wait | 56.9 µs | 56.1 µs | -1.4% | 55.4 µs | -2.8% | 57.5 µs | +1.0% |
| sync | condvar_signal_wait | 65.1 µs | 65.3 µs | +0.3% | 65.2 µs | +0.3% | 65.4 µs | +0.5% |
| sync | recursive_mutex_lock_unlock | 3.0 µs | 2.9 µs | -3.4% | 3.4 µs | +13.2% | 3.1 µs | +3.5% |
| queue | send_receive | 4.5 µs | 5.3 µs | +17.3% | 5.3 µs | +16.3% | 4.6 µs | +1.6% |
| queue | throughput_2t | 3.3 µs | 3.4 µs | +3.9% | 4.0 µs | +21.9% | 3.3 µs | +0.6% |
| timer | start_stop | 8.8 µs | 8.8 µs | -0.4% | 8.7 µs | -0.7% | 8.9 µs | +1.0% |
| eventgroup | set_get_bits | 9.1 µs | 8.9 µs | -2.8% | 8.9 µs | -2.5% | 9.2 µs | +0.8% |
| workqueue | submit_execute | 58.7 µs | 58.3 µs | -0.7% | 57.8 µs | -1.5% | 59.0 µs | +0.5% |
| stream | send_recv_64B | 14.3 µs | 24.8 µs | +73.6% | 17.0 µs | +18.9% | 14.5 µs | +1.5% |
| stream | throughput | 24.3 µs | 33.5 µs | +38.2% | 40.9 µs | +68.6% | 24.8 µs | +2.2% |
| native_zephyr | native_mutex_lock_unlock | 2.9 µs | 2.6 µs | -10.4% | 2.9 µs | -2.4% | 2.8 µs | -4.1% |
| native_zephyr | native_mutex_create_destroy | 860 ns | 827 ns | -3.8% | 920 ns | +7.0% | 860 ns | +0.0% |
| native_zephyr | native_mutex_contention_2t | 2.9 µs | 58.3 µs | +1878.0% | 3.0 µs | +2.6% | 2.9 µs | -2.5% |
| native_zephyr | native_recursive_mutex_lock_unlock | 3.0 µs | 2.6 µs | -11.0% | 2.9 µs | -3.3% | 2.8 µs | -5.9% |
| native_zephyr | native_sem_take_give | 2.1 µs | 1.5 µs | -29.1% | 1.7 µs | -18.9% | 1.6 µs | -21.2% |
| native_zephyr | native_sem_create_destroy | 702 ns | 703 ns | +0.1% | 739 ns | +5.3% | 809 ns | +15.2% |
| native_zephyr | native_condvar_signal_wait | 66.9 µs | 67.2 µs | +0.4% | 66.2 µs | -1.0% | 67.5 µs | +1.0% |
| native_zephyr | native_event_signal_wait | 63.3 µs | 63.4 µs | +0.2% | 62.3 µs | -1.6% | 64.2 µs | +1.3% |
| native_zephyr | native_thread_yield | 10.4 µs | 10.7 µs | +3.5% | 10.4 µs | +0.2% | 10.7 µs | +3.3% |
| native_zephyr | native_thread_sleep_1ms | 1.09 ms | 1.09 ms | -0.0% | 1.09 ms | -0.1% | 1.09 ms | -0.0% |
| native_zephyr | native_thread_create_destroy | 190.3 µs | 84.4 µs | -55.6% | 77.8 µs | -59.1% | 89.8 µs | -52.8% |
| native_zephyr | native_thread_context_switch | 56.0 µs | 55.0 µs | -1.8% | 54.0 µs | -3.6% | 56.8 µs | +1.4% |
| native_zephyr | native_queue_send_receive | 4.2 µs | 5.6 µs | +31.7% | 4.9 µs | +17.4% | 4.4 µs | +4.3% |
| native_zephyr | native_queue_create_destroy | 1.2 µs | 944 ns | -18.3% | 1.2 µs | +5.5% | 1.1 µs | -7.5% |
| native_zephyr | native_stream_send_recv_64B | 12.8 µs | 23.3 µs | +82.4% | 10.5 µs | -17.7% | 13.1 µs | +2.5% |
| thread | ctx_switch | — | — | — | 54.9 µs | — | — | — |
Cases with |Δ| > 10.0% vs C:
- CPP
native_zephyr/native_mutex_contention_2t58312 vs 2948 (+1878.0%) - CPP
sync/mutex_contention_2t45976 vs 3005 (+1430.0%) - ZIG
sync/mutex_contention_2t45360 vs 3005 (+1409.5%) - CPP
native_zephyr/native_stream_send_recv_64B23294 vs 12771 (+82.4%) - CPP
stream/send_recv_64B24787 vs 14277 (+73.6%) - RUST
stream/throughput40932 vs 24278 (+68.6%) - RUST
native_zephyr/native_thread_create_destroy77849 vs 190271 (-59.1%) - CPP
native_zephyr/native_thread_create_destroy84431 vs 190271 (-55.6%) - ZIG
native_zephyr/native_thread_create_destroy89780 vs 190271 (-52.8%) - CPP
stream/throughput33542 vs 24278 (+38.2%) - CPP
native_zephyr/native_queue_send_receive5551 vs 4214 (+31.7%) - CPP
native_zephyr/native_sem_take_give1457 vs 2054 (-29.1%) - RUST
thread/get_self1070 vs 855 (+25.1%) - RUST
queue/throughput_2t4007 vs 3288 (+21.9%) - ZIG
native_zephyr/native_sem_take_give1619 vs 2054 (-21.2%) - RUST
stream/send_recv_64B16981 vs 14277 (+18.9%) - RUST
native_zephyr/native_sem_take_give1665 vs 2054 (-18.9%) - CPP
native_zephyr/native_queue_create_destroy944 vs 1156 (-18.3%) - RUST
native_zephyr/native_stream_send_recv_64B10515 vs 12771 (-17.7%) - RUST
native_zephyr/native_queue_send_receive4948 vs 4214 (+17.4%) - CPP
queue/send_receive5329 vs 4542 (+17.3%) - RUST
queue/send_receive5283 vs 4542 (+16.3%) - CPP
sync/sem_take_give1938 vs 2313 (-16.2%) - ZIG
native_zephyr/native_sem_create_destroy809 vs 702 (+15.2%) - RUST
sync/recursive_mutex_lock_unlock3380 vs 2985 (+13.2%) - ZIG
thread/get_self957 vs 855 (+11.9%) - RUST
sync/mutex_contention_2t3358 vs 3005 (+11.7%) - CPP
native_zephyr/native_recursive_mutex_lock_unlock2647 vs 2973 (-11.0%) - CPP
native_zephyr/native_mutex_lock_unlock2628 vs 2933 (-10.4%) - RUST
sync/sem_take_give2078 vs 2313 (-10.2%) - RUST
sync/mutex_lock_unlock3167 vs 2878 (+10.0%)
Wrapper vs native Zephyr API (within-run delta)
Each row pairs one binding's wrapper measurement against the raw Zephyr 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 | 10521 ns | 10364 ns | +157 ns |
| Thread yield | CPP | ove::Thread::yield | 10918 ns | 10728 ns | +190 ns |
| Thread yield | RUST | ove::Thread::yield | 10474 ns | 10383 ns | +91 ns |
| Thread yield | ZIG | ove.Thread.yield | 10773 ns | 10707 ns | +66 ns |
| Thread sleep 1ms | C | ove_thread_sleep_ms(1) | 1087583 ns | 1087516 ns | +67 ns |
| Thread sleep 1ms | CPP | ove::Thread::sleep_ms(1) | 1087514 ns | 1087388 ns | +126 ns |
| Thread sleep 1ms | RUST | ove::Thread::sleep_ms(1) | 1085980 ns | 1085996 ns | -16 ns |
| Thread sleep 1ms | ZIG | ove.Thread.sleepMs(1) | 1087334 ns | 1087267 ns | +67 ns |
| Thread context_switch (2t) | C | ove ping-pong (2t) | 56567 ns | 55988 ns | +579 ns |
| Thread context_switch (2t) | CPP | ove ping-pong (2t) | 55662 ns | 54982 ns | +680 ns |
| Thread context_switch (2t) | ZIG | ove ping-pong (2t) | 57355 ns | 56779 ns | +576 ns |
| Mutex lock+unlock | C | ove_mutex_lock+unlock | 2878 ns | 2933 ns | -55 ns |
| Mutex lock+unlock | CPP | ove::Mutex::lock+unlock | 2865 ns | 2628 ns | +237 ns |
| Mutex lock+unlock | RUST | ove::Mutex::lock+unlock | 3167 ns | 2864 ns | +303 ns |
| Mutex lock+unlock | ZIG | ove.Mutex.lock+unlock | 2901 ns | 2813 ns | +88 ns |
| Mutex contention (2t) | C | ove_mutex_lock+unlock (×2t) | 3005 ns | 2948 ns | +57 ns |
| Mutex contention (2t) | CPP | ove::Mutex::lock+unlock (×2t) | 45976 ns | 58312 ns | -12336 ns |
| Mutex contention (2t) | RUST | ove::Mutex::lock+unlock (×2t) | 3358 ns | 3026 ns | +332 ns |
| Mutex contention (2t) | ZIG | ove.Mutex.lock+unlock (×2t) | 45360 ns | 2874 ns | +42486 ns |
| Recursive mutex lock+unlock | C | ove_rmtx_lock+unlock | 2985 ns | 2973 ns | +12 ns |
| Recursive mutex lock+unlock | CPP | ove::RMutex::lock+unlock | 2883 ns | 2647 ns | +236 ns |
| Recursive mutex lock+unlock | RUST | ove::RMutex::lock+unlock | 3380 ns | 2874 ns | +506 ns |
| Recursive mutex lock+unlock | ZIG | ove.RMutex.lock+unlock | 3088 ns | 2799 ns | +289 ns |
| Sem take+give | C | ove_sem_take+give | 2313 ns | 2054 ns | +259 ns |
| Sem take+give | CPP | ove::Sem::take+give | 1938 ns | 1457 ns | +481 ns |
| Sem take+give | RUST | ove::Sem::take+give | 2078 ns | 1665 ns | +413 ns |
| Sem take+give | ZIG | ove.Sem.take+give | 2114 ns | 1619 ns | +495 ns |
| Condvar signal+wait | C | ove_condvar_signal+wait | 65060 ns | 66881 ns | -1821 ns |
| Condvar signal+wait | CPP | ove::Condvar::signal+wait | 65262 ns | 67174 ns | -1912 ns |
| Condvar signal+wait | RUST | ove::Condvar::signal+wait | 65245 ns | 66225 ns | -980 ns |
| Condvar signal+wait | ZIG | ove.Condvar.signal+wait | 65393 ns | 67520 ns | -2127 ns |
| Event signal+wait | C | ove_event_signal+wait | 56943 ns | 63333 ns | -6390 ns |
| Event signal+wait | CPP | ove::Event::signal+wait | 56120 ns | 63447 ns | -7327 ns |
| Event signal+wait | RUST | ove::Event::signal+wait | 55365 ns | 62323 ns | -6958 ns |
| Event signal+wait | ZIG | ove.Event.signal+wait | 57495 ns | 64162 ns | -6667 ns |
| Queue send+receive | C | ove_queue_send+receive | 4542 ns | 4214 ns | +328 ns |
| Queue send+receive | CPP | ove::Queue::send+recv | 5329 ns | 5551 ns | -222 ns |
| Queue send+receive | RUST | ove::Queue::send+recv | 5283 ns | 4948 ns | +335 ns |
| Queue send+receive | ZIG | ove.Queue.send+recv | 4613 ns | 4397 ns | +216 ns |
| Stream send+recv 64B | C | ove_stream_send+recv 64B | 14277 ns | 12771 ns | +1506 ns |
| Stream send+recv 64B | CPP | ove::Stream::send+recv 64B | 24787 ns | 23294 ns | +1493 ns |
| Stream send+recv 64B | RUST | ove::Stream::send+recv 64B | 16981 ns | 10515 ns | +6466 ns |
| Stream send+recv 64B | ZIG | ove.Stream.send+recv 64B | 14493 ns | 13091 ns | +1402 ns |