FreeRTOS — heap mode
Raw cross-binding benchmark results measured on STM32F746G-DISCOVERY (Cortex-M7 @ 216 MHz) running FreeRTOS 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: FreeRTOS 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_freertos.c is C code calling raw FreeRTOS APIs (xSemaphoreTake, xQueueSend, xTaskCreateStatic), compiled identically into every binary; the CPP/RUST/ZIG columns for those rows are the same C code measured in three different processes.
FreeRTOS
| Suite | Case | C | CPP | Δ CPP | RUST | Δ RUST | ZIG | Δ ZIG |
|---|---|---|---|---|---|---|---|---|
| time | time_get_us_overhead | 883 ns | 1.2 µs | +31.9% | 1.1 µs | +21.2% | 1.0 µs | +15.7% |
| time | delay_1ms | 984.4 µs | 984.0 µs | -0.0% | 983.1 µs | -0.1% | 984.2 µs | -0.0% |
| thread | create_destroy | 176.4 µs | 184.2 µs | +4.4% | 46.6 µs | -73.6% | 176.3 µs | -0.1% |
| thread | yield | 4.5 µs | 4.3 µs | -4.9% | 4.4 µs | -1.4% | 4.5 µs | +0.7% |
| thread | get_self | 2.6 µs | 2.8 µs | +6.7% | 2.8 µs | +8.0% | 2.6 µs | +0.2% |
| thread | sleep_1ms | 984.4 µs | 984.0 µs | -0.0% | 983.1 µs | -0.1% | 984.2 µs | -0.0% |
| thread | context_switch | 51.9 µs | 50.7 µs | -2.4% | — | — | 51.7 µs | -0.5% |
| sync | mutex_memory | 96 B | 96 B | — | 96 B | — | 96 B | — |
| sync | sem_memory | 96 B | 96 B | — | 96 B | — | 96 B | — |
| sync | event_memory | 96 B | 96 B | — | 96 B | — | 96 B | — |
| sync | condvar_memory | 16 B | 16 B | — | 16 B | — | 16 B | — |
| sync | mutex_lock_unlock | 8.1 µs | 8.2 µs | +1.6% | 8.5 µs | +5.7% | 8.0 µs | -1.1% |
| sync | mutex_create_destroy | 18.9 µs | 18.3 µs | -3.0% | 19.2 µs | +1.4% | 18.9 µs | -0.2% |
| sync | mutex_contention_2t | 8.2 µs | 18.7 µs | +128.8% | 8.9 µs | +8.4% | 26.2 µs | +220.7% |
| sync | sem_take_give | 6.5 µs | 6.4 µs | -1.4% | 6.6 µs | +1.5% | 6.4 µs | -1.8% |
| sync | sem_create_destroy | 15.3 µs | 14.4 µs | -5.7% | 15.6 µs | +2.3% | 15.6 µs | +2.0% |
| sync | event_signal_wait | 50.2 µs | 49.8 µs | -0.9% | 49.3 µs | -1.7% | 50.0 µs | -0.3% |
| sync | condvar_signal_wait | 34.2 µs | 33.9 µs | -0.8% | 34.3 µs | +0.3% | 34.2 µs | -0.0% |
| sync | recursive_mutex_lock_unlock | 10.2 µs | 10.2 µs | -0.0% | 10.1 µs | -0.6% | 9.9 µs | -3.1% |
| queue | memory | 128 B | 128 B | — | 128 B | — | 128 B | — |
| queue | send_receive | 8.2 µs | 8.2 µs | +0.5% | 9.3 µs | +12.9% | 8.5 µs | +3.4% |
| queue | create_destroy | 15.0 µs | 14.3 µs | -4.2% | 15.3 µs | +2.2% | 14.9 µs | -0.7% |
| queue | throughput_2t | 4.0 µs | 4.2 µs | +4.7% | 4.8 µs | +20.6% | 4.1 µs | +0.9% |
| timer | memory | 64 B | 64 B | — | 64 B | — | 64 B | — |
| timer | create_destroy | 45.6 µs | 44.6 µs | -2.3% | 45.4 µs | -0.6% | 48.6 µs | +6.4% |
| timer | start_stop | 67.7 µs | 66.0 µs | -2.5% | 66.6 µs | -1.6% | 73.4 µs | +8.5% |
| eventgroup | memory | 48 B | 48 B | — | 48 B | — | 48 B | — |
| eventgroup | set_get_bits | 7.3 µs | 6.6 µs | -10.2% | 6.9 µs | -6.2% | 7.1 µs | -3.4% |
| eventgroup | create_destroy | 13.8 µs | 13.4 µs | -3.1% | 14.2 µs | +2.5% | 14.1 µs | +2.2% |
| workqueue | memory | 2520 B | 2520 B | — | 2520 B | — | 2520 B | — |
| workqueue | create_destroy | 357.9 µs | 374.8 µs | +4.7% | 97.4 µs | -72.8% | 357.7 µs | -0.0% |
| workqueue | submit_execute | 57.7 µs | 54.9 µs | -4.8% | 56.7 µs | -1.7% | 57.8 µs | +0.2% |
| stream | memory | 352 B | 352 B | — | 352 B | — | 352 B | — |
| stream | send_recv_64B | 20.6 µs | 20.5 µs | -0.6% | 25.0 µs | +21.3% | 33.4 µs | +62.1% |
| stream | create_destroy | 59.4 µs | 61.7 µs | +3.9% | 23.3 µs | -60.8% | 59.3 µs | -0.2% |
| stream | throughput | 31.2 µs | 26.5 µs | -15.1% | 49.6 µs | +58.9% | 39.7 µs | +27.1% |
| native_freertos | native_mutex_lock_unlock | 7.4 µs | 7.8 µs | +5.1% | 8.0 µs | +8.7% | 7.2 µs | -2.3% |
| native_freertos | native_mutex_create_destroy | 17.4 µs | 16.9 µs | -3.3% | 16.7 µs | -4.1% | 17.5 µs | +0.1% |
| native_freertos | native_mutex_contention_2t | 7.5 µs | 7.7 µs | +3.8% | 8.1 µs | +8.6% | 7.3 µs | -2.8% |
| native_freertos | native_recursive_mutex_lock_unlock | 9.3 µs | 9.6 µs | +4.2% | 9.6 µs | +3.7% | 9.1 µs | -1.8% |
| native_freertos | native_sem_take_give | 5.8 µs | 5.6 µs | -3.3% | 6.3 µs | +7.4% | 5.8 µs | -1.0% |
| native_freertos | native_sem_create_destroy | 13.2 µs | 12.7 µs | -3.6% | 12.6 µs | -4.8% | 13.4 µs | +1.1% |
| native_freertos | native_condvar_signal_wait | 20.3 µs | 19.4 µs | -4.2% | 19.6 µs | -3.4% | 20.5 µs | +1.1% |
| native_freertos | native_event_signal_wait | 20.3 µs | 19.4 µs | -4.0% | 19.6 µs | -3.2% | 20.3 µs | +0.4% |
| native_freertos | native_thread_yield | 4.4 µs | 4.1 µs | -6.6% | 4.2 µs | -3.9% | 4.3 µs | -2.6% |
| native_freertos | native_thread_sleep_1ms | 984.3 µs | 983.9 µs | -0.0% | 983.1 µs | -0.1% | 984.2 µs | -0.0% |
| native_freertos | native_thread_create_destroy | 166.0 µs | 174.9 µs | +5.4% | 36.0 µs | -78.3% | 165.9 µs | -0.1% |
| native_freertos | native_thread_context_switch | 34.9 µs | 34.4 µs | -1.2% | 34.4 µs | -1.3% | 34.8 µs | -0.2% |
| native_freertos | native_queue_send_receive | 7.3 µs | 7.5 µs | +3.1% | 8.5 µs | +17.1% | 7.8 µs | +7.8% |
| native_freertos | native_queue_create_destroy | 13.4 µs | 13.0 µs | -2.9% | 12.8 µs | -4.5% | 13.5 µs | +0.9% |
| native_freertos | native_stream_send_recv_64B | 19.4 µs | 19.0 µs | -1.6% | 17.0 µs | -12.0% | 31.7 µs | +63.8% |
| thread | ctx_switch | — | — | — | 51.4 µs | — | — | — |
Cases with |Δ| > 10.0% vs C:
- ZIG
sync/mutex_contention_2t26212 vs 8173 (+220.7%) - CPP
sync/mutex_contention_2t18701 vs 8173 (+128.8%) - RUST
native_freertos/native_thread_create_destroy35952 vs 165977 (-78.3%) - RUST
thread/create_destroy46573 vs 176444 (-73.6%) - RUST
workqueue/create_destroy97440 vs 357866 (-72.8%) - ZIG
native_freertos/native_stream_send_recv_64B31718 vs 19361 (+63.8%) - ZIG
stream/send_recv_64B33385 vs 20598 (+62.1%) - RUST
stream/create_destroy23305 vs 59390 (-60.8%) - RUST
stream/throughput49598 vs 31212 (+58.9%) - CPP
time/time_get_us_overhead1165 vs 883 (+31.9%) - ZIG
stream/throughput39666 vs 31212 (+27.1%) - RUST
stream/send_recv_64B24989 vs 20598 (+21.3%) - RUST
time/time_get_us_overhead1070 vs 883 (+21.2%) - RUST
queue/throughput_2t4850 vs 4021 (+20.6%) - RUST
native_freertos/native_queue_send_receive8512 vs 7272 (+17.1%) - ZIG
time/time_get_us_overhead1022 vs 883 (+15.7%) - CPP
stream/throughput26494 vs 31212 (-15.1%) - RUST
queue/send_receive9258 vs 8202 (+12.9%) - RUST
native_freertos/native_stream_send_recv_64B17028 vs 19361 (-12.0%) - CPP
eventgroup/set_get_bits6600 vs 7348 (-10.2%)
Wrapper vs native FreeRTOS API (within-run delta)
Each row pairs one binding's wrapper measurement against the raw FreeRTOS 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 | 4488 ns | 4379 ns | +109 ns |
| Thread yield | CPP | ove::Thread::yield | 4267 ns | 4092 ns | +175 ns |
| Thread yield | RUST | ove::Thread::yield | 4423 ns | 4209 ns | +214 ns |
| Thread yield | ZIG | ove.Thread.yield | 4519 ns | 4266 ns | +253 ns |
| Thread sleep 1ms | C | ove_thread_sleep_ms(1) | 984370 ns | 984340 ns | +30 ns |
| Thread sleep 1ms | CPP | ove::Thread::sleep_ms(1) | 984014 ns | 983923 ns | +91 ns |
| Thread sleep 1ms | RUST | ove::Thread::sleep_ms(1) | 983131 ns | 983093 ns | +38 ns |
| Thread sleep 1ms | ZIG | ove.Thread.sleepMs(1) | 984214 ns | 984184 ns | +30 ns |
| Thread create+destroy | C | ove_thread_create+destroy | 176444 ns | 165977 ns | +10467 ns |
| Thread create+destroy | CPP | ove::Thread (ctor+dtor) | 184190 ns | 174932 ns | +9258 ns |
| Thread create+destroy | RUST | ove::Thread::spawn+join | 46573 ns | 35952 ns | +10621 ns |
| Thread create+destroy | ZIG | ove.Thread.spawn+join | 176270 ns | 165893 ns | +10377 ns |
| Thread context_switch (2t) | C | ove ping-pong (2t) | 51932 ns | 34865 ns | +17067 ns |
| Thread context_switch (2t) | CPP | ove ping-pong (2t) | 50679 ns | 34438 ns | +16241 ns |
| Thread context_switch (2t) | ZIG | ove ping-pong (2t) | 51691 ns | 34806 ns | +16885 ns |
| Mutex lock+unlock | C | ove_mutex_lock+unlock | 8057 ns | 7376 ns | +681 ns |
| Mutex lock+unlock | CPP | ove::Mutex::lock+unlock | 8182 ns | 7750 ns | +432 ns |
| Mutex lock+unlock | RUST | ove::Mutex::lock+unlock | 8514 ns | 8016 ns | +498 ns |
| Mutex lock+unlock | ZIG | ove.Mutex.lock+unlock | 7970 ns | 7207 ns | +763 ns |
| Mutex create+destroy | C | ove_mutex_create+destroy | 18904 ns | 17439 ns | +1465 ns |
| Mutex create+destroy | CPP | ove::Mutex (ctor+dtor) | 18345 ns | 16855 ns | +1490 ns |
| Mutex create+destroy | RUST | ove::Mutex (new+drop) | 19176 ns | 16725 ns | +2451 ns |
| Mutex create+destroy | ZIG | ove.Mutex.create+destroy | 18874 ns | 17456 ns | +1418 ns |
| Mutex contention (2t) | C | ove_mutex_lock+unlock (×2t) | 8173 ns | 7466 ns | +707 ns |
| Mutex contention (2t) | CPP | ove::Mutex::lock+unlock (×2t) | 18701 ns | 7746 ns | +10955 ns |
| Mutex contention (2t) | RUST | ove::Mutex::lock+unlock (×2t) | 8863 ns | 8108 ns | +755 ns |
| Mutex contention (2t) | ZIG | ove.Mutex.lock+unlock (×2t) | 26212 ns | 7254 ns | +18958 ns |
| Recursive mutex lock+unlock | C | ove_rmtx_lock+unlock | 10200 ns | 9260 ns | +940 ns |
| Recursive mutex lock+unlock | CPP | ove::RMutex::lock+unlock | 10196 ns | 9645 ns | +551 ns |
| Recursive mutex lock+unlock | RUST | ove::RMutex::lock+unlock | 10136 ns | 9601 ns | +535 ns |
| Recursive mutex lock+unlock | ZIG | ove.RMutex.lock+unlock | 9882 ns | 9093 ns | +789 ns |
| Sem take+give | C | ove_sem_take+give | 6508 ns | 5828 ns | +680 ns |
| Sem take+give | CPP | ove::Sem::take+give | 6418 ns | 5635 ns | +783 ns |
| Sem take+give | RUST | ove::Sem::take+give | 6603 ns | 6258 ns | +345 ns |
| Sem take+give | ZIG | ove.Sem.take+give | 6389 ns | 5771 ns | +618 ns |
| Sem create+destroy | C | ove_sem_create+destroy | 15261 ns | 13208 ns | +2053 ns |
| Sem create+destroy | CPP | ove::Sem (ctor+dtor) | 14394 ns | 12734 ns | +1660 ns |
| Sem create+destroy | RUST | ove::Sem (new+drop) | 15618 ns | 12570 ns | +3048 ns |
| Sem create+destroy | ZIG | ove.Sem.create+destroy | 15562 ns | 13354 ns | +2208 ns |
| Condvar signal+wait | C | ove_condvar_signal+wait | 34217 ns | 20273 ns | +13944 ns |
| Condvar signal+wait | CPP | ove::Condvar::signal+wait | 33947 ns | 19418 ns | +14529 ns |
| Condvar signal+wait | RUST | ove::Condvar::signal+wait | 34304 ns | 19581 ns | +14723 ns |
| Condvar signal+wait | ZIG | ove.Condvar.signal+wait | 34200 ns | 20505 ns | +13695 ns |
| Event signal+wait | C | ove_event_signal+wait | 50197 ns | 20252 ns | +29945 ns |
| Event signal+wait | CPP | ove::Event::signal+wait | 49770 ns | 19437 ns | +30333 ns |
| Event signal+wait | RUST | ove::Event::signal+wait | 49346 ns | 19612 ns | +29734 ns |
| Event signal+wait | ZIG | ove.Event.signal+wait | 50044 ns | 20328 ns | +29716 ns |
| Queue send+receive | C | ove_queue_send+receive | 8202 ns | 7272 ns | +930 ns |
| Queue send+receive | CPP | ove::Queue::send+recv | 8244 ns | 7497 ns | +747 ns |
| Queue send+receive | RUST | ove::Queue::send+recv | 9258 ns | 8512 ns | +746 ns |
| Queue send+receive | ZIG | ove.Queue.send+recv | 8478 ns | 7837 ns | +641 ns |
| Queue create+destroy | C | ove_queue_create+destroy | 14961 ns | 13386 ns | +1575 ns |
| Queue create+destroy | CPP | ove::Queue (ctor+dtor) | 14336 ns | 13000 ns | +1336 ns |
| Queue create+destroy | RUST | ove::Queue (new+drop) | 15286 ns | 12783 ns | +2503 ns |
| Queue create+destroy | ZIG | ove.Queue.create+destroy | 14851 ns | 13511 ns | +1340 ns |
| Stream send+recv 64B | C | ove_stream_send+recv 64B | 20598 ns | 19361 ns | +1237 ns |
| Stream send+recv 64B | CPP | ove::Stream::send+recv 64B | 20468 ns | 19046 ns | +1422 ns |
| Stream send+recv 64B | RUST | ove::Stream::send+recv 64B | 24989 ns | 17028 ns | +7961 ns |
| Stream send+recv 64B | ZIG | ove.Stream.send+recv 64B | 33385 ns | 31718 ns | +1667 ns |