Skip to content

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_2t 58312 vs 2948 (+1878.0%)
  • CPP sync/mutex_contention_2t 45976 vs 3005 (+1430.0%)
  • ZIG sync/mutex_contention_2t 45360 vs 3005 (+1409.5%)
  • CPP native_zephyr/native_stream_send_recv_64B 23294 vs 12771 (+82.4%)
  • CPP stream/send_recv_64B 24787 vs 14277 (+73.6%)
  • RUST stream/throughput 40932 vs 24278 (+68.6%)
  • RUST native_zephyr/native_thread_create_destroy 77849 vs 190271 (-59.1%)
  • CPP native_zephyr/native_thread_create_destroy 84431 vs 190271 (-55.6%)
  • ZIG native_zephyr/native_thread_create_destroy 89780 vs 190271 (-52.8%)
  • CPP stream/throughput 33542 vs 24278 (+38.2%)
  • CPP native_zephyr/native_queue_send_receive 5551 vs 4214 (+31.7%)
  • CPP native_zephyr/native_sem_take_give 1457 vs 2054 (-29.1%)
  • RUST thread/get_self 1070 vs 855 (+25.1%)
  • RUST queue/throughput_2t 4007 vs 3288 (+21.9%)
  • ZIG native_zephyr/native_sem_take_give 1619 vs 2054 (-21.2%)
  • RUST stream/send_recv_64B 16981 vs 14277 (+18.9%)
  • RUST native_zephyr/native_sem_take_give 1665 vs 2054 (-18.9%)
  • CPP native_zephyr/native_queue_create_destroy 944 vs 1156 (-18.3%)
  • RUST native_zephyr/native_stream_send_recv_64B 10515 vs 12771 (-17.7%)
  • RUST native_zephyr/native_queue_send_receive 4948 vs 4214 (+17.4%)
  • CPP queue/send_receive 5329 vs 4542 (+17.3%)
  • RUST queue/send_receive 5283 vs 4542 (+16.3%)
  • CPP sync/sem_take_give 1938 vs 2313 (-16.2%)
  • ZIG native_zephyr/native_sem_create_destroy 809 vs 702 (+15.2%)
  • RUST sync/recursive_mutex_lock_unlock 3380 vs 2985 (+13.2%)
  • ZIG thread/get_self 957 vs 855 (+11.9%)
  • RUST sync/mutex_contention_2t 3358 vs 3005 (+11.7%)
  • CPP native_zephyr/native_recursive_mutex_lock_unlock 2647 vs 2973 (-11.0%)
  • CPP native_zephyr/native_mutex_lock_unlock 2628 vs 2933 (-10.4%)
  • RUST sync/sem_take_give 2078 vs 2313 (-10.2%)
  • RUST sync/mutex_lock_unlock 3167 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