OA foundation benchmark
A from-scratch C++ foundation for OA, now measured across containers, formatting, algorithms, ownership, runtime primitives, and the host-memory operations that moved into the same foundation surface.
Independent foundation, competitive on its real workloads
OA's foundation is an original implementation designed around OA's admitted product workloads. It was written from scratch; it is not an STL source port, compatibility layer, or renamed wrapper surface. The result is not a small synthetic win hidden behind one score: 27 of 32 recorded foundation cases are at parity or ahead on this host, while the remaining overheads stay visible below.
| Evidence slice | Current result |
|---|---|
| Foundation primitives | 32 cases spanning runtime calls, values, text, containers, algorithms, and ownership |
| Hash containers | Insertion used 34.1–35.1% of host time; collision cases used 63.4–66.1% |
| Thread-safe shared ownership | Make and copy/release reached parity after thread creation |
| Brace formatting | Integer, padded/bool, and fixed-float cases were faster; the mixed record reached parity |
| Dynamic small copy | 8 B and 32 B used 49.8% and 66.3% of libc latency |
| Cache-cold streaming | Nine stable wins from 1 KiB through 4 MiB; best row used 65.3% of libc time |
| Correctness | 281 foundation Release tests; focused formatting/output sanitizer passes |
This is fixed-host engineering evidence, not a universal performance claim. OA still uses explicit OS, compiler, C-runtime, and Vulkan adapters where they are the correct boundary. The separate linked-binary and full platform-independence matrix remains qualification work.
Foundation, not oa::std
Std is the short navigation label, not a namespace. The public vocabulary lives directly under oa: oa::Vector, oa::String, oa::Result, oa::HashMap, and oa::SharedPtr. The former pre-1.0 oa::Vec spelling has been removed.
| Surface | Implemented work | Contract |
|---|---|---|
| Values and failure | Fixed-width scalars, Status, Result, Optional, Variant, Pair | Explicit failure and bounded composition |
| Storage and views | Array, Span, Vector, StringView, String | OA-owned layouts and lifetime rules |
| Lookup and algorithms | HashMap, HashSet, hashing, sort, find, fill, min/max/clamp | Measured product-owned use cases |
| Formatting and output | format, print, write, explicit streams and flush | Bounded brace formatting and recoverable host I/O |
| Ownership and callables | UniquePtr, SharedPtr, WeakPtr, callback and owned functions | Unique ownership remains preferred |
| Runtime and memory | Atomics, locks, threads, clocks, virtual memory, byte operations, paths, files, CLI, Unicode | Portable contracts over private adapters |
Measured protocol
| Field | Recorded value |
|---|---|
| Evidence | Fixed-host engineering comparisons measured through 2026-08-28 |
| Toolchain | Clang 22.1.8; glibc 2.44; Linux 7.1.8-arch1-3 |
| Host | Intel Core i5-1145G7; process pinned to CPU 2 |
| Formatting host | Same fixed host; formatting campaign pinned separately to CPU 3 |
| Power and thermals | intel_pstate powersave; 400 MHz–4.4 GHz; package 70 C before and 66 C after |
| Formatting power | AC power; intel_pstate powersave governor; balanced power profile |
| Foundation workload | 32,768 general items; 8,192 hash items |
| Formatting workload | 32,768 items; five warmups; 21 alternating samples in each of seven fresh processes |
| Memory workload | Reusable dynamic buffers plus cache-cold 256 MiB rotating arenas |
| Sampling | 5 warmups; 21 rotating or alternating OA/host samples per fresh process |
| Estimator | Median of seven per-process ratios; range is complete min–max |
| Correctness | Independent preflight and checksum before reporting every measured pair |
Every ratio is OA latency divided by its equivalent host operation. Below 1.0 favors OA. A complete process range crossing 1.0 is treated as parity, even when the median falls on one side.
Foundation results
The full result is split by behavior so the table remains readable without collapsing the campaign into an average. First are runtime calls, bounded values, text views, and algorithms.
| Case | Median OA / host | Process range | Recorded result |
|---|---|---|---|
| Steady clock | 1.026× | 1.016–1.029× | 2.6% overhead |
| Mutex lock / unlock | 1.193× | 1.167–1.225× | 19.3% overhead |
| Array indexed read | 1.001× | 0.998–1.002× | Parity |
| Span traversal | 1.000× | 0.999–1.003× | Parity |
| Atomic relaxed add | 1.000× | 1.000–1.059× | Parity median |
| Optional lifecycle | 0.999× | 0.998–1.001× | Parity |
| Algorithm sort | 1.003× | 0.993–1.011× | Parity |
| Find / count algorithms | 0.939× | 0.938–0.939× | 6.1% less time |
| C strlen / byte | 0.994× | 0.981–1.039× | Parity |
| C strchr miss / byte | 1.004× | 0.985–1.006× | Parity |
| C strcmp equal / byte | 1.000× | 0.993–1.004× | Parity |
| C strncmp equal / byte | 1.009× | 0.999–1.013× | Parity to +0.9% |
| StringView find / byte | 1.009× | 0.984–1.016× | Parity to +0.9% |
| Scalar sin / tanh | 1.000× | 0.972–1.069× | Parity median |
The checked clock and mutex ABI boundaries retain measurable call overhead. Sort is at parity; find/count is a stable win. These results keep checks and failure semantics enabled.
Sequences, text, variants, and callables
| Case | Median OA / host | Process range | Recorded result |
|---|---|---|---|
| Vector · reserved scalar push | 1.593× | 1.589–1.701× | 59.3% overhead |
| Vector · geometric growth | 1.062× | 1.029–1.132× | 6.2% overhead |
| Vector · bulk append / element | 1.000× | 0.998–1.001× | Parity |
| String · reserved push | 0.923× | 0.906–0.996× | 7.7% less time |
| String · geometric growth | 0.876× | 0.865–0.892× | 12.4% less time |
| String · bulk append / byte | 1.004× | 1.001–1.012× | Parity to +0.4% |
| Variant emplace / visit | 1.001× | 0.999–1.002× | Parity |
| Function invoke | 1.000× | 0.999–1.000× | Parity |
Vector bulk append is the intended high-throughput path and is at parity. The reserved single-element loop exposes an optimizer control-flow gap rather than hiding it behind the bulk result. String wins in both reserved-push and geometric-growth workloads.
Lookup and ownership
| Case | Median OA / host | Process range | Recorded result |
|---|---|---|---|
| HashMap insertion | 0.341× | 0.309–0.346× | 65.9% less time |
| HashSet insertion | 0.351× | 0.278–0.356× | 64.9% less time |
| HashMap successful find | 0.879× | 0.861–0.882× | 12.1% less time |
| HashSet successful find | 0.751× | 0.675–0.762× | 24.9% less time |
| HashMap collision insertion | 0.661× | 0.628–0.760× | 33.9% less time |
| HashMap collision miss | 0.634× | 0.601–0.647× | 36.6% less time |
| SharedPtr make / release · initial process state | 0.999× | 0.785–1.042× | Parity; noisy |
| SharedPtr copy / release · initial process state | 2.627× | 2.512–2.701× | Host shortcut |
| SharedPtr make / release · after thread creation | 0.968× | 0.944–1.010× | Parity in spread |
| SharedPtr copy / release · after thread creation | 1.003× | 0.988–1.017× | Parity |
The hash tables are the largest general-foundation win. Shared ownership needs one explicit qualification: on this glibc/libstdc++ host, copy/release avoids atomic reference-count work until a thread has existed. OA keeps thread-safe counts in both process states. Once the host uses its thread-safe path, OA make/release and copy/release are at parity.
Brace formatting and record output
oa::format, oa::print, and oa::write use a bounded, literal brace-format syntax familiar from Python and {fmt}. This is OA's deliberately smaller dialect, not a source port or a claim of complete std::format or {fmt}compatibility. The benchmark compares identical formatted output with the toolchain's std::format.
Format.cpp
1#include <oa/core/std/print.h>23const oa::String message = oa::format("epoch={} loss={:.4f}", epoch, loss);4OA_RETURN_IF_ERROR(oa::print("epoch={} loss={:.4f}", epoch, loss));5OA_RETURN_IF_ERROR(oa::print(oa::PrintStream::Error, "failed: {}", reason));6OA_RETURN_IF_ERROR(oa::write("\rprogress={:.1f}%", percent));7OA_RETURN_IF_ERROR(oa::flush());8
| Case | Median OA / host | Process range | Recorded result |
|---|---|---|---|
| Signed decimal integer | 0.589× | 0.577–0.603× | 41.1% less latency |
| Padded hex + bool | 0.668× | 0.661–0.688× | 33.2% less latency |
| Fixed-precision float | 0.913× | 0.901–0.919× | 8.7% less latency |
| Padded hex + bool + float | 1.003× | 0.975–1.011× | Parity in spread |
Each row is the median paired OA/standard-library latency ratio across seven fresh processes. Integer formatting used 58.9% of host time, padded hexadecimal plus boolean used 66.8%, and fixed-precision floating point used 91.3%. The mixed record's 1.003× median crosses parity over its complete 0.975–1.011× range, so it is recorded as parity, not a regression.
| Contract | Behavior |
|---|---|
| Format program | Character-array literal with sequential {} or {:spec} fields and escaped braces |
| Supported values | OA strings/views, C strings, bool, character, integers, enums, float/double, pointers, and values with toString() |
| Specifier subset | Fill/alignment, sign, alternate form, zero padding, bounded width/precision, integer bases, and f/e/g floats |
| Output | print adds one newline; write adds none; Out/Error streams are explicit; flush is never implicit |
| Failure | Invalid format programs fail the always-on contract; host write and flush failures return Status |
| Bounds | Width is capped at 1 MiB and complete output at 16 MiB; floating conversion is pinned to the C numeric locale |
The accepted optimization keeps those checks intact: fixed literal syntax can fold at the call site, records through 128 bytes use bounded inline staging, and floating conversion writes directly into checked caller storage. No unchecked formatter, precision change, locale mutation, or hosted C++ dependency was added to obtain the result.
Host memory is now part of the foundation
The old raw-assembly memory path was removed. OA now uses legal exact-bounds compiler copies for dynamic blocks through 256 B, tuned platform operations where they remain best, and a separate oa::memcpyStream policy only when the destination will not be consumed soon. That separation keeps ordinary copy behavior predictable while admitting cache-aware wins for one-way uploads.
Dynamic copy with reusable buffers
| Case | Median OA / host | Process range | Recorded result |
|---|---|---|---|
| 8 B | 0.498× | 0.448–0.540× | 50.2% less latency |
| 32 B | 0.663× | 0.632–0.679× | 33.7% less latency |
| 256 B | 0.968× | 0.864–1.085× | Parity in spread |
| 4 KiB | 1.059× | 1.018–1.088× | Dispatcher overhead |
| 64 KiB | 1.003× | 1.001–1.024× | Parity |
| 1 MiB | 1.007× | 0.984–1.045× | Parity in spread |
| 16 MiB | 1.022× | 1.003–1.038× | Near parity |
| 64 MiB | 1.025× | 0.910–1.066× | Parity in spread |
Fixed compile-time OA and compiler-copy rows reduce to the same instructions. The dynamic dispatcher is retained for the stable 8 B and 32 B gains; large ordinary copies continue through libc and return to parity.
Cache-cold one-way streaming
The sweep rotates chunks through separate 256 MiB source and destination arenas—32 times the host's 8 MiB last-level cache. Each ratio cell includes the median followed by the complete seven-process range; throughput columns are absolute medians.
| Chunk | Ordinary OA / libc | Stream OA / libc | libc | OA stream |
|---|---|---|---|---|
| 256 B | 0.922× · 0.891–0.991 | 0.940× · 0.904–1.025 | 7.641 GB/s | 7.959 GB/s |
| 512 B | 1.007× · 0.975–1.055 | 1.016× · 0.975–1.054 | 8.358 GB/s | 8.571 GB/s |
| 1 KiB | 1.012× · 0.958–1.121 | 0.855× · 0.808–0.984 | 8.809 GB/s | 10.053 GB/s |
| 2 KiB | 1.006× · 0.989–1.036 | 0.653× · 0.608–0.731 | 7.396 GB/s | 11.300 GB/s |
| 4 KiB | 1.000× · 0.987–1.024 | 0.955× · 0.818–1.037 | 11.168 GB/s | 11.693 GB/s |
| 8 KiB | 1.006× · 0.971–1.030 | 0.882× · 0.826–0.900 | 10.871 GB/s | 12.467 GB/s |
| 16 KiB | 0.992× · 0.977–1.019 | 0.853× · 0.824–0.876 | 10.937 GB/s | 13.053 GB/s |
| 64 KiB | 1.008× · 0.975–1.044 | 0.792× · 0.765–0.856 | 10.880 GB/s | 13.587 GB/s |
| 256 KiB | 0.990× · 0.973–1.030 | 0.861× · 0.787–0.904 | 10.925 GB/s | 12.925 GB/s |
| 1 MiB | 1.000× · 0.985–1.017 | 0.831× · 0.809–0.860 | 10.798 GB/s | 13.023 GB/s |
| 2 MiB | 0.988× · 0.953–1.042 | 0.839× · 0.769–0.857 | 11.248 GB/s | 13.348 GB/s |
| 4 MiB | 1.015× · 0.963–1.036 | 0.829× · 0.780–0.882 | 11.129 GB/s | 13.492 GB/s |
| 8 MiB | 0.982× · 0.921–1.034 | 0.972× · 0.906–1.023 | 16.106 GB/s | 16.255 GB/s |
| 16 MiB | 0.996× · 0.980–1.136 | 0.990× · 0.918–1.078 | 16.170 GB/s | 16.284 GB/s |
| 64 MiB | 0.989× · 0.973–1.071 | 0.993× · 0.955–1.078 | 15.735 GB/s | 15.819 GB/s |
The qualified x86 non-temporal window runs from 1 KiB through 4 MiB. Nine rows in that window are stable wins; 2 KiB is best at 0.653×. From 64 KiB through 4 MiB, streaming uses 79.2–83.9% of libc time except the 256 KiB row at 86.1%. The 4 KiB range crosses parity and is classified as flat. Below and above the window, fallback restores parity.
Equality, ordering, and overlap
Each cell reports the median OA / libc ratio followed by its complete process range.
| Operation | 8 B | 256 B | 4 KiB | 64 KiB |
|---|---|---|---|---|
| memEqual · equal | 1.714× · 1.593–2.666 | 1.367× · 1.360–1.499 | 1.187× · 1.051–1.196 | 0.639× · 0.638–0.732 |
| memEqual · early mismatch | 1.629× · 1.629–1.640 | 0.778× | 0.787× · 0.779–0.843 | 0.894× · 0.824–1.033 |
| memEqual · late mismatch | 1.629× · 1.629–1.630 | 1.058× · 1.000–1.079 | 1.207× · 1.064–1.250 | 0.645× · 0.643–0.713 |
| memEqualConstantTime · equal | 1.617× · 1.571–1.713 | 1.402× · 1.363–1.548 | 0.563× · 0.554–0.603 | 0.664× · 0.592–0.665 |
memcmp and both overlapping memmove directions measured at a1.000×median at all four representative sizes. Constant-work equality has a stricter security contract than libc's early-exit comparison, so its result is not presented as a semantic speedup. Platform fill and zero also remain faster than the rejected hand-vectorized paths.
Measured decisions, including the rejected ones
| Decision | Why it remains |
|---|---|
| Adaptive streaming window | Keeps nine stable medium-size wins and restores parity outside the qualified range |
| Ordinary platform copy for large buffers | No durable OA advantage was measured for the general copy contract |
| Thread-safe SharedPtr counts | Portable ownership semantics do not depend on undocumented process-global thread state |
| Checked clock and mutex boundaries | Failure and ABI behavior remain explicit despite measured call overhead |
| Rejected force-all non-temporal copy | Regressed 256 B to 1.636× and 8–64 MiB to about 1.14× |
| Rejected AVX-512 eight-vector unroll | Seven processes established no stable improvement over four vectors |
| Rejected unchecked or non-atomic shortcuts | They weakened safety, portability, or failure contracts |
Correctness before timing
| Gate | Covered contract |
|---|---|
| Containers and algorithms | Collision, tombstone, rehash, adversarial order, aliasing, growth, throwing relocation, and lifetime |
| Ownership and concurrency | Reference-count bounds plus concurrent final strong and weak release |
| Memory | Full content, overlap, alignment, tails, guard bytes, ordinary equality, and fixed-length secret equality |
| Earlier foundation checkpoint | All 271 focused Release tests passed |
| Formatting checkpoint | All 281 foundation Release tests passed; 15 focused formatting/output tests passed under ASAN+LSAN and fail-fast UBSAN |
| Sanitizers | 272 tests passed under combined ASAN+UBSAN and under TSan; no finding suppressed |
| Coverage checkpoint | 77.72% lines, 78.24% functions, and 63.95% branches at the 4.29 header checkpoint |
Evidence boundary
This checkpoint qualifies one compiler, host library, machine, workload, and date. It does not establish cross-platform superiority, complete hostile-input resilience, or linked-binary independence from libstdc++ or libc++. YAML, VMA, private third-party link closure, no-exception/no-RTTI builds, longer fuzzing, allocator-fault campaigns, and the full compiler and platform matrix retain their own qualification gates.
Reproduce
Use a fixed power policy and record thermal conditions. Release comparison requires immutable commits, rotating or alternating samples, median and spread, and passing correctness gates. A single process is useful for profiling, not release evidence.
Foundation terminal
cmake --build build/release --target BenchStd TestOaStd -jctest --test-dir build/release -R '^TestOaStd$' --output-on-failuretaskset -c 2 ./bin/release/test/core/std/benchStd \--items 32768 --warmups 5 --samples 21# Formatting evidence was recorded separately on CPU 3.taskset -c 3 ./bin/release/test/core/std/benchStd \--items 32768 --warmups 5 --samples 21cmake --build build/release --target BenchMemory TestMemory -jtaskset -c 2 ./bin/release/test/core/memory/benchMemory --quick --copytaskset -c 2 ./bin/release/test/core/memory/benchMemory --quick --primitivestaskset -c 2 ./bin/release/test/core/memory/benchMemory --streaming# Run each campaign as at least seven fresh processes.