Skip to content

Zero-allocation steady state for I/O object and operation churn - #389

Open
sgerbino wants to merge 12 commits into
cppalliance:developfrom
sgerbino:pr/mem-opts
Open

sgerbino wants to merge 12 commits into
cppalliance:developfrom
sgerbino:pr/mem-opts

Conversation

@sgerbino

@sgerbino sgerbino commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Replaces per-impl shared_ptr ownership with an intrusive refcount
(object_ref) and a per-service recycling pool (object_pool), then
extends recycling to the remaining per-operation allocations. Once
warmed, construct/destroy, accept, positional file I/O, timer waits,
and tcp_server connection dispatch allocate nothing.

Changes

  • object_pool<Impl> / object_ref: live/free intrusive lists behind
    one mutex, variadic acquire() as the library's only new site for
    impls, retire() at the zero-crossing recycles instead of deleting.
    All backends converted; IOCP's wrapper/internal split collapsed;
    timer unified (keeping its thread-local slot).
  • uring multishot accept: waiter_node + per-completion op merged into
    one pooled accept_node (2 heap nodes per accept -> 0).
  • Random-access file ops recycle through per-file free lists on posix,
    uring, and IOCP (~500 B malloc/free per read/write -> 0).
  • tcp_server launch: reused worker stop_source, pooled launch
    frame, post via frame-embedded continuation.
  • Fix (pre-existing, found by new tests): completions handed a
    deferring executor the op's embedded continuation, which its queue
    holds by reference while the op is recycled/reused/freed --
    use-after-free or corrupted resume on every backend.
    dispatch_coro now lends a self-destroying trampoline frame
    instead; the io_context fast path is unchanged. Includes
    deterministic multi-executor regression tests.
  • Zero-alloc gates probe that the counting interposer is live and
    loud-skip otherwise (Valgrind replaces the allocator at run time).
  • Fault harness: chain interposed syscalls through sanitizer
    __interceptor_ exports so ASan/TSan thread bookkeeping survives
    interception (clang >= 23 link-order change).

Verification

  • Zero-alloc gates (allocation-counting interposer) pin exact counts:
    accept/echo/close, impl reuse, delay(), raf write+read, and
    tcp_server churn at 0/cycle on epoll and uring (select keeps its
    documented 2/cycle descriptor-map cost).
  • A/B benchmarks: epoll accept_churn +4.4-8.2% across all rows,
    uring +1.2-2.2% measured before the accept-node pooling that removes
    its remaining per-accept allocations.
  • Adversarial review of the pool core and the recycling protocols;
    full CI matrix green; ASan/TSan clean.

Resolves #381.

@cppalliance-bot

cppalliance-bot commented Oct 8, 2026 •

Copy link
Copy Markdown

An automated preview of the documentation is available at https://389.corosio.prtest3.cppalliance.org/index.html

If more commits are pushed to the pull request, the docs will rebuild at the same URL.

2026-10-08 18:09:23 UTC

@cppalliance-bot

cppalliance-bot commented Oct 8, 2026 •

Copy link
Copy Markdown

GCOVR code coverage report https://389.corosio.prtest3.cppalliance.org/gcovr/index.html
LCOV code coverage report https://389.corosio.prtest3.cppalliance.org/genhtml/index.html
Coverage Diff Report https://389.corosio.prtest3.cppalliance.org/diff-report/index.html

Build time: 2026-10-08 18:21:20 UTC

The multishot acceptor allocated a waiter_node when parking an
accept and a fresh uring_accept_op at every completion boundary,
copying the request fields across and deleting the waiter -- two
heap round trips per accepted connection, plus a ready_fd_node
whenever a delivery arrived before an accept was parked.

A parked waiter and its completion have strictly sequential
lifetimes, so fold them into one accept_node that is both an
intrusive list node and the posted op. Nodes recycle through a
per-acceptor free list via the op's new dispose hook, ready-fd
nodes recycle the same way, and each in-flight node keeps the
acceptor alive through the op envelope's object_ref slot. The
inherited cancelled flag keeps its claim-token role; claiming
paths now restore the real completion status after stop_cb.reset()
quiesces any in-flight canceller.

The uring zero-alloc gate pins accept churn at 0 allocations per
cycle, matching epoll; only select retains its documented
2/cycle registered_descs_ cost.
Every read_some_at/write_some_at heap-allocated its op -- a
deliberate choice so concurrent operations at distinct offsets can
overlap, but one that cost ~500 bytes of malloc/free per call on
the posix, io_uring, and IOCP backends alike.

Keep the unlimited-concurrency model and recycle the ops instead:
completion pushes the op onto a per-file free list (posix reuses
the outstanding-ops hook and mutex; uring wraps the heap op types
in a pooled subclass that swaps the completion handler; IOCP
recycles raf_concurrent_op under its existing ops_mutex_). Each
completion copies out what it needs before the push, since a
concurrent initiation may refill the op immediately, and drops its
impl keepalive only after leaving the list mutex. The storage
belongs to the impl, survives impl recycling, and is freed by the
impl destructor.

The zero-alloc gate grows a raf churn test pinning a warmed
write+read round trip at 0 allocations on every backend.
Launching a worker for an accepted connection paid three heap
round trips: a fresh std::stop_source shared state, a
launch_wrapper coroutine frame through the global allocator, and
a wrapper op for posting the bare coroutine handle.

Reuse the worker's stop_source across connections and replace it
only once a stop has actually been delivered; route the
launch_wrapper frame through capy's frame_alloc_mixin so the
thread-local recycling allocator serves it; and post the launch
through a frame-embedded capy::continuation, which the Executor
concept already guarantees every executor accepts.

The zero-alloc gate grows a server churn test pinning a warmed
connect/echo/close round trip through tcp_server at 0 allocations
(select keeps its documented 2/cycle registered_descs_ cost).
Since clang 23's static ASan runtime, the fault harness's interposed
symbols bind ahead of the sanitizer's interceptors (verbosity=1
reports "failed to intercept 'pthread_create'"), so threads created
through the raw libc pthread_create bypass ASan's thread registry
and the first join aborts with "Joining already joined thread" --
every fault test failed instantly under local ASan builds.

Sanitizers export each interceptor as __interceptor_<name> precisely
so an interposer can cooperate. Under a sanitizer build, resolve the
census's libc half through those exports (weak references, so a name
the runtime does not intercept falls back to the RTLD_NEXT lookup
unchanged). Injection semantics are untouched: shadows still run
first and armed faults short-circuit before the chained call;
unsanitized builds compile the mechanism away entirely.
A completion whose awaiter runs on a non-io_context executor takes
dispatch_coro's deferring branch, which handed the executor the
op's EMBEDDED continuation -- held on its queue by reference until
dequeue (a documented stable-address contract). Every completion
tail then consumes its op: recycling it into a free list (pooled
uring accept/raf nodes), reusing the embedded slot on the next
operation (reactor and IOCP ops), or deleting it (heap ops). A
concurrent operation could therefore rewrite or free a queued
node, and the dequeued resume targeted a dead or rewritten handle.

Two new tests reproduce it deterministically (latch-sequenced, no
timing): park a single-worker pool behind a latch so the deferred
completion queues into it, refill the op from the io_context side,
then release the worker. They crashed on every backend -- uring
(pooled nodes), epoll/select (embedded accept op via coro_resume),
and IOCP in CI (embedded accept op) -- so the fix lives at the one
chokepoint every path shares: dispatch_coro's deferring branch now
lends the executor a continuation owned by a self-destroying
trampoline frame (post_resume; frames served by capy's recycling
pool) and no longer retains the caller's. The io_context fast path
is unchanged, and callers keep the uniform consume-then-resume
shape since nothing they own stays queued.

run_async could not serve as the trampoline: its launch wrapper
calls ex.on_work_finished() after the task completes, but the op's
executor_ref points into the awaiting coroutine's environment,
which the resume destroys -- completions must never touch the
executor after resuming the handle, and the trampoline doesn't.
Each reactor wake constructed to_add/to_cancel inside the loop,
swapped away pending_register_/pending_cancel_'s capacity, and
freed it at scope end -- two malloc/free per wake (pollfds beside
them was already hoisted). Hoist both and clear per iteration: the
capacities then ping-pong between the locals and the members
through the under-lock swap, and a warmed reactor wake allocates
nothing.
Vale's docstring lint reads the wrapped line's leading identifier
as bare prose; rewrapping keeps the reference intact.
@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Benchmark report

ff2966547b00 (base) vs 23880ff31a65 (head)

  • ✅ linux — clean (epoll, uring)
  • ⚠️ windows — 2 flagged (iocp)
  • ⚠️ macos — 2 flagged (kqueue)

⚠️ Flagged

Platform Backend Benchmark Metric Base Head Δ Noise
windows iocp accept_churn/burst/100 ops_per_sec 149.1 ops/s 155.6 ops/s 🟢▲ +4.40% 0.93%
windows iocp accept_churn/burst_lockless/100 ops_per_sec 152.4 ops/s 158.5 ops/s 🟢▲ +3.85% 0.64%
macos kqueue accept_churn/burst/100 ops_per_sec 431.9 ops/s 443.3 ops/s 🟢▲ +3.36% 0.81%
macos kqueue accept_churn/concurrent/1 ops_per_sec 19.58K ops/s 20.18K ops/s 🟢▲ +3.49% 1.03%
linux — full results (226 benchmarks, 5 iterations, 1.5s each)

accept_churn

Benchmark Backend Metric Base Head Δ Noise
burst/10 epoll ops_per_sec 1.88K ops/s 1.91K ops/s 🟢▲ +2.01% 1.01%
burst/10 uring ops_per_sec 1.71K ops/s 1.73K ops/s 🟢▲ +1.32% 0.88%
burst/100 epoll ops_per_sec 189.3 ops/s 192.6 ops/s 🟢▲ +2.10% 1.11%
burst/100 uring ops_per_sec 174.3 ops/s 177.2 ops/s 🟢▲ +1.89% 0.57%
burst_lockless/10 epoll ops_per_sec 1.90K ops/s 1.93K ops/s 🟢▲ +2.09% 1.17%
burst_lockless/10 uring ops_per_sec 1.83K ops/s 1.85K ops/s 🟢▲ +1.54% 0.99%
burst_lockless/100 epoll ops_per_sec 191.0 ops/s 194.1 ops/s 🟢▲ +2.06% 1.07%
burst_lockless/100 uring ops_per_sec 186.3 ops/s 189.6 ops/s 🟢▲ +2.22% 0.99%
concurrent/1 epoll ops_per_sec 14.98K ops/s 15.29K ops/s 🟢▲ +2.41% 0.94%
concurrent/1 uring ops_per_sec 12.77K ops/s 12.99K ops/s 🟢▲ +1.76% 0.80%
concurrent/16 epoll ops_per_sec 14.99K ops/s 15.31K ops/s 🟢▲ +2.53% 1.13%
concurrent/16 uring ops_per_sec 12.64K ops/s 12.85K ops/s 🟢▲ +1.69% 0.85%
concurrent/4 epoll ops_per_sec 14.98K ops/s 15.29K ops/s 🟢▲ +2.30% 0.95%
concurrent/4 uring ops_per_sec 12.75K ops/s 12.91K ops/s 🟢▲ +1.07% 1.11%
sequential epoll ops_per_sec 14.99K ops/s 15.31K ops/s 🟢▲ +2.46% 1.26%
sequential uring ops_per_sec 12.77K ops/s 12.98K ops/s 🟢▲ +1.54% 1.14%
sequential_lockless epoll ops_per_sec 15.05K ops/s 15.36K ops/s 🟢▲ +2.27% 1.13%
sequential_lockless uring ops_per_sec 13.66K ops/s 13.90K ops/s 🟢▲ +1.86% 0.98%

fan_out

Benchmark Backend Metric Base Head Δ Noise
concurrent_parents/1 epoll ops_per_sec 3.71K ops/s 3.69K ops/s 🟢▲ +0.03% 1.13%
concurrent_parents/1 uring ops_per_sec 3.45K ops/s 3.44K ops/s 🟢▲ +0.09% 1.20%
concurrent_parents/16 epoll ops_per_sec 3.58K ops/s 3.58K ops/s 🔴▼ -0.20% 0.49%
concurrent_parents/16 uring ops_per_sec 3.33K ops/s 3.31K ops/s 🔴▼ -0.23% 1.04%
concurrent_parents/4 epoll ops_per_sec 3.61K ops/s 3.59K ops/s 🔴▼ -0.39% 1.11%
concurrent_parents/4 uring ops_per_sec 3.36K ops/s 3.34K ops/s 🔴▼ -0.06% 1.13%
concurrent_parents_lockless/1 epoll ops_per_sec 3.73K ops/s 3.73K ops/s 🟢▲ +0.06% 0.20%
concurrent_parents_lockless/1 uring ops_per_sec 3.67K ops/s 3.66K ops/s 🔴▼ -0.15% 0.82%
concurrent_parents_lockless/16 epoll ops_per_sec 3.61K ops/s 3.61K ops/s 🔴▼ -0.18% 0.18%
concurrent_parents_lockless/16 uring ops_per_sec 3.52K ops/s 3.52K ops/s 🔴▼ -0.28% 0.38%
concurrent_parents_lockless/4 epoll ops_per_sec 3.63K ops/s 3.63K ops/s 🔴▼ -0.03% 0.15%
concurrent_parents_lockless/4 uring ops_per_sec 3.55K ops/s 3.55K ops/s 🔴▼ -0.03% 0.49%
fork_join/1 epoll ops_per_sec 54.94K ops/s 54.75K ops/s 🟢▲ +0.09% 1.04%
fork_join/1 uring ops_per_sec 53.48K ops/s 53.30K ops/s 🟢▲ +0.01% 1.05%
fork_join/16 epoll ops_per_sec 3.69K ops/s 3.70K ops/s 🟢▲ +0.46% 0.26%
fork_join/16 uring ops_per_sec 3.45K ops/s 3.45K ops/s 🔴▼ -0.25% 1.01%
fork_join/4 epoll ops_per_sec 14.64K ops/s 14.65K ops/s 🟢▲ +0.01% 0.25%
fork_join/4 uring ops_per_sec 13.79K ops/s 13.71K ops/s 🔴▼ -0.27% 1.30%
fork_join/64 epoll ops_per_sec 897.4 ops/s 900.8 ops/s 🟢▲ +0.24% 0.19%
fork_join/64 uring ops_per_sec 813.7 ops/s 817.0 ops/s 🟢▲ +0.02% 1.16%
fork_join_lockless/1 epoll ops_per_sec 55.59K ops/s 55.51K ops/s 🔴▼ -0.22% 0.18%
fork_join_lockless/1 uring ops_per_sec 55.95K ops/s 56.13K ops/s 🔴▼ -0.08% 1.11%
fork_join_lockless/16 epoll ops_per_sec 3.73K ops/s 3.73K ops/s 🟢▲ +0.06% 0.20%
fork_join_lockless/16 uring ops_per_sec 3.67K ops/s 3.67K ops/s 🟢▲ +0.40% 1.03%
fork_join_lockless/4 epoll ops_per_sec 14.80K ops/s 14.82K ops/s 🟢▲ +0.06% 0.25%
fork_join_lockless/4 uring ops_per_sec 14.61K ops/s 14.58K ops/s 🔴▼ -0.18% 1.23%
fork_join_lockless/64 epoll ops_per_sec 907.8 ops/s 909.3 ops/s 🟢▲ +0.31% 0.26%
fork_join_lockless/64 uring ops_per_sec 870.1 ops/s 869.5 ops/s 🟢▲ +0.30% 1.05%
nested/16 epoll ops_per_sec 895.2 ops/s 892.7 ops/s 🟢▲ +0.25% 1.12%
nested/16 uring ops_per_sec 810.3 ops/s 802.2 ops/s 🔴▼ -0.49% 1.06%
nested/4 epoll ops_per_sec 3.68K ops/s 3.67K ops/s 🟢▲ +0.04% 1.25%
nested/4 uring ops_per_sec 3.42K ops/s 3.41K ops/s 🔴▼ -0.12% 1.19%
nested_lockless/16 epoll ops_per_sec 905.0 ops/s 902.7 ops/s 🟢▲ +0.05% 1.01%
nested_lockless/16 uring ops_per_sec 861.0 ops/s 856.9 ops/s 🔴▼ -0.27% 0.95%
nested_lockless/4 epoll ops_per_sec 3.72K ops/s 3.71K ops/s 🟢▲ +0.11% 1.15%
nested_lockless/4 uring ops_per_sec 3.65K ops/s 3.63K ops/s 🔴▼ -0.49% 1.13%

http_server

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 epoll ops_per_sec 55.12K ops/s 55.36K ops/s 🟢▲ +0.29% 0.94%
concurrent/1 uring ops_per_sec 53.47K ops/s 53.84K ops/s 🟢▲ +0.27% 0.86%
concurrent/16 epoll ops_per_sec 57.82K ops/s 57.84K ops/s 🟢▲ +0.04% 0.15%
concurrent/16 uring ops_per_sec 52.82K ops/s 53.20K ops/s 🟢▲ +0.14% 1.08%
concurrent/32 epoll ops_per_sec 57.40K ops/s 57.46K ops/s 🟢▲ +0.19% 0.29%
concurrent/32 uring ops_per_sec 52.44K ops/s 52.82K ops/s 🟢▲ +0.26% 1.13%
concurrent/4 epoll ops_per_sec 57.16K ops/s 57.45K ops/s 🟢▲ +0.36% 0.96%
concurrent/4 uring ops_per_sec 52.82K ops/s 53.34K ops/s 🟢▲ +0.40% 1.21%
multithread/1 epoll ops_per_sec 57.38K ops/s 57.45K ops/s 🟢▲ +0.08% 0.11%
multithread/1 uring ops_per_sec 52.43K ops/s 52.82K ops/s 🟢▲ +0.26% 1.13%
multithread/16 epoll ops_per_sec 162.1K ops/s 162.3K ops/s 🔴▼ -0.09% 0.41%
multithread/16 uring ops_per_sec 75.25K ops/s 75.47K ops/s 🟢▲ +0.42% 19.53%
multithread/2 epoll ops_per_sec 87.31K ops/s 86.90K ops/s 🔴▼ -0.73% 0.84%
multithread/2 uring ops_per_sec 90.43K ops/s 91.36K ops/s 🟢▲ +0.86% 0.62%
multithread/4 epoll ops_per_sec 159.8K ops/s 159.7K ops/s 🔴▼ -0.26% 0.73%
multithread/4 uring ops_per_sec 80.15K ops/s 80.32K ops/s 🟢▲ +0.31% 0.27%
multithread/8 epoll ops_per_sec 162.2K ops/s 161.9K ops/s 🔴▼ -0.29% 0.31%
multithread/8 uring ops_per_sec 77.50K ops/s 77.83K ops/s 🟢▲ +0.33% 0.26%
single_conn epoll ops_per_sec 55.09K ops/s 55.30K ops/s 🟢▲ +0.06% 0.79%
single_conn uring ops_per_sec 53.34K ops/s 53.52K ops/s 🟢▲ +0.45% 0.39%
single_conn_lockless epoll ops_per_sec 55.74K ops/s 56.11K ops/s 🟢▲ +0.61% 0.99%
single_conn_lockless uring ops_per_sec 55.95K ops/s 56.27K ops/s 🟢▲ +0.53% 0.33%

local_socket_latency

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 epoll latency_mean_ns 7.17 µs 7.23 µs 🟢▲ +0.47% 4.08%
concurrent/1 uring latency_mean_ns 6.56 µs 6.56 µs 🔴▼ -0.26% 1.16%
concurrent/16 epoll latency_mean_ns 109.89 µs 109.72 µs 🟢▲ +0.34% 0.91%
concurrent/16 uring latency_mean_ns 108.11 µs 108.02 µs 🟢▲ +0.19% 1.27%
concurrent/4 epoll latency_mean_ns 27.74 µs 27.70 µs 🟢▲ +0.16% 1.42%
concurrent/4 uring latency_mean_ns 27.03 µs 26.67 µs 🟢▲ +2.13% 2.28%
concurrent_lockless/1 epoll latency_mean_ns 7.25 µs 7.25 µs 🟢▲ +0.31% 5.73%
concurrent_lockless/1 uring latency_mean_ns 6.55 µs 6.81 µs 🔴▼ -0.03% 6.08%
concurrent_lockless/16 epoll latency_mean_ns 108.34 µs 108.63 µs 🔴▼ -0.07% 0.91%
concurrent_lockless/16 uring latency_mean_ns 108.02 µs 107.74 µs 🟢▲ +0.28% 0.70%
concurrent_lockless/4 epoll latency_mean_ns 27.19 µs 27.48 µs 🟢▲ +0.09% 2.12%
concurrent_lockless/4 uring latency_mean_ns 26.86 µs 26.68 µs 🟢▲ +0.30% 1.23%
pingpong/1 epoll latency_mean_ns 7.20 µs 7.18 µs 🟢▲ +0.52% 4.28%
pingpong/1 uring latency_mean_ns 6.60 µs 6.61 µs 🟢▲ +0.25% 2.82%
pingpong/1024 epoll latency_mean_ns 8.02 µs 7.59 µs 🟢▲ +8.21% 4.93%
pingpong/1024 uring latency_mean_ns 7.09 µs 7.22 µs 🟢▲ +0.22% 5.18%
pingpong/64 epoll latency_mean_ns 7.38 µs 7.08 µs 🟢▲ +0.72% 4.80%
pingpong/64 uring latency_mean_ns 6.72 µs 6.57 µs 🟢▲ +0.54% 4.35%
pingpong_lockless/1 epoll latency_mean_ns 6.96 µs 6.97 µs 🔴▼ -0.04% 0.40%
pingpong_lockless/1 uring latency_mean_ns 6.54 µs 6.53 µs 🟢▲ +0.44% 0.67%
pingpong_lockless/1024 epoll latency_mean_ns 7.52 µs 7.52 µs ⚪ 0.00% 5.09%
pingpong_lockless/1024 uring latency_mean_ns 7.26 µs 7.30 µs 🟢▲ +0.17% 4.53%
pingpong_lockless/64 epoll latency_mean_ns 7.14 µs 7.28 µs 🔴▼ -0.02% 5.21%
pingpong_lockless/64 uring latency_mean_ns 6.57 µs 6.70 µs 🔴▼ -0.22% 4.31%

local_socket_throughput

Benchmark Backend Metric Base Head Δ Noise
bidirectional/1024 epoll bytes_per_sec 305.3 MB/s 304.9 MB/s 🔴▼ -0.13% 1.04%
bidirectional/1024 uring bytes_per_sec 301.9 MB/s 301.7 MB/s ⚪ 0.00% 0.65%
bidirectional/1048576 epoll bytes_per_sec 3.16 GB/s 3.16 GB/s 🟢▲ +0.29% 2.32%
bidirectional/1048576 uring bytes_per_sec 3.32 GB/s 3.33 GB/s 🔴▼ -0.35% 1.76%
bidirectional/16384 epoll bytes_per_sec 3.11 GB/s 3.02 GB/s 🔴▼ -3.23% 1.74%
bidirectional/16384 uring bytes_per_sec 2.39 GB/s 2.40 GB/s 🔴▼ -0.37% 2.48%
bidirectional/262144 epoll bytes_per_sec 3.18 GB/s 3.20 GB/s 🟢▲ +0.83% 2.53%
bidirectional/262144 uring bytes_per_sec 3.31 GB/s 3.31 GB/s 🟢▲ +0.34% 1.24%
bidirectional/4096 epoll bytes_per_sec 1.01 GB/s 998.8 MB/s 🔴▼ -0.64% 0.78%
bidirectional/4096 uring bytes_per_sec 995.1 MB/s 989.4 MB/s 🔴▼ -0.53% 0.72%
bidirectional/65536 epoll bytes_per_sec 2.98 GB/s 2.97 GB/s 🔴▼ -1.53% 1.88%
bidirectional/65536 uring bytes_per_sec 3.05 GB/s 3.01 GB/s 🔴▼ -0.76% 2.40%
bidirectional_lockless/1024 epoll bytes_per_sec 308.1 MB/s 308.7 MB/s 🔴▼ -0.33% 1.24%
bidirectional_lockless/1024 uring bytes_per_sec 304.7 MB/s 304.8 MB/s 🟢▲ +0.90% 0.81%
bidirectional_lockless/1048576 epoll bytes_per_sec 3.16 GB/s 3.17 GB/s 🔴▼ -0.78% 2.63%
bidirectional_lockless/1048576 uring bytes_per_sec 3.39 GB/s 3.40 GB/s 🔴▼ -0.97% 2.45%
bidirectional_lockless/16384 epoll bytes_per_sec 3.08 GB/s 3.09 GB/s 🔴▼ -0.04% 2.45%
bidirectional_lockless/16384 uring bytes_per_sec 2.59 GB/s 2.62 GB/s 🟢▲ +1.44% 2.94%
bidirectional_lockless/262144 epoll bytes_per_sec 3.19 GB/s 3.20 GB/s 🟢▲ +0.56% 2.88%
bidirectional_lockless/262144 uring bytes_per_sec 3.37 GB/s 3.37 GB/s 🟢▲ +1.13% 1.44%
bidirectional_lockless/4096 epoll bytes_per_sec 1.02 GB/s 1.01 GB/s 🔴▼ -0.51% 0.84%
bidirectional_lockless/4096 uring bytes_per_sec 1.00 GB/s 991.0 MB/s 🔴▼ -0.79% 1.21%
bidirectional_lockless/65536 epoll bytes_per_sec 2.98 GB/s 2.95 GB/s 🔴▼ -1.69% 2.02%
bidirectional_lockless/65536 uring bytes_per_sec 3.22 GB/s 3.18 GB/s 🔴▼ -0.88% 2.28%
unidirectional/1024 epoll bytes_per_sec 297.5 MB/s 297.1 MB/s 🔴▼ -0.47% 1.07%
unidirectional/1024 uring bytes_per_sec 303.1 MB/s 302.2 MB/s 🟢▲ +0.10% 1.01%
unidirectional/1048576 epoll bytes_per_sec 3.30 GB/s 3.29 GB/s 🔴▼ -1.02% 2.24%
unidirectional/1048576 uring bytes_per_sec 3.46 GB/s 3.46 GB/s 🔴▼ -1.35% 2.40%
unidirectional/16384 epoll bytes_per_sec 3.04 GB/s 3.05 GB/s 🟢▲ +0.41% 1.90%
unidirectional/16384 uring bytes_per_sec 2.63 GB/s 2.59 GB/s 🔴▼ -1.50% 3.36%
unidirectional/262144 epoll bytes_per_sec 3.29 GB/s 3.33 GB/s 🟢▲ +0.26% 2.45%
unidirectional/262144 uring bytes_per_sec 3.42 GB/s 3.45 GB/s 🟢▲ +1.48% 2.90%
unidirectional/4096 epoll bytes_per_sec 989.3 MB/s 979.6 MB/s 🔴▼ -0.94% 0.55%
unidirectional/4096 uring bytes_per_sec 991.0 MB/s 992.2 MB/s 🟢▲ +0.74% 1.87%
unidirectional/65536 epoll bytes_per_sec 3.27 GB/s 3.25 GB/s 🔴▼ -0.79% 1.47%
unidirectional/65536 uring bytes_per_sec 3.31 GB/s 3.32 GB/s 🟢▲ +0.80% 2.65%
unidirectional_lockless/1024 epoll bytes_per_sec 301.9 MB/s 301.6 MB/s 🟢▲ +0.26% 1.16%
unidirectional_lockless/1024 uring bytes_per_sec 305.1 MB/s 304.5 MB/s 🔴▼ -0.17% 0.95%
unidirectional_lockless/1048576 epoll bytes_per_sec 3.31 GB/s 3.32 GB/s 🟢▲ +0.61% 3.14%
unidirectional_lockless/1048576 uring bytes_per_sec 3.39 GB/s 3.40 GB/s 🟢▲ +0.39% 2.23%
unidirectional_lockless/16384 epoll bytes_per_sec 3.07 GB/s 3.08 GB/s 🟢▲ +1.00% 1.74%
unidirectional_lockless/16384 uring bytes_per_sec 2.67 GB/s 2.60 GB/s 🔴▼ -3.03% 3.46%
unidirectional_lockless/262144 epoll bytes_per_sec 3.30 GB/s 3.35 GB/s 🟢▲ +0.72% 1.68%
unidirectional_lockless/262144 uring bytes_per_sec 3.38 GB/s 3.39 GB/s 🟢▲ +2.44% 4.16%
unidirectional_lockless/4096 epoll bytes_per_sec 996.7 MB/s 989.6 MB/s 🔴▼ -1.16% 0.97%
unidirectional_lockless/4096 uring bytes_per_sec 991.4 MB/s 995.2 MB/s 🔴▼ -0.54% 1.15%
unidirectional_lockless/65536 epoll bytes_per_sec 3.25 GB/s 3.26 GB/s 🟢▲ +0.40% 1.15%
unidirectional_lockless/65536 uring bytes_per_sec 3.31 GB/s 3.30 GB/s 🔴▼ -0.31% 2.04%

socket_latency

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 epoll latency_mean_ns 14.79 µs 14.71 µs 🟢▲ +0.28% 1.06%
concurrent/1 uring latency_mean_ns 14.53 µs 14.55 µs 🔴▼ -0.15% 0.39%
concurrent/16 epoll latency_mean_ns 233.21 µs 233.11 µs 🟢▲ +0.12% 0.16%
concurrent/16 uring latency_mean_ns 235.46 µs 235.34 µs 🟢▲ +0.01% 0.33%
concurrent/4 epoll latency_mean_ns 58.23 µs 58.20 µs 🔴▼ -0.05% 0.18%
concurrent/4 uring latency_mean_ns 58.40 µs 58.41 µs 🔴▼ -0.03% 0.37%
concurrent_lockless/1 epoll latency_mean_ns 14.67 µs 14.62 µs 🟢▲ +0.29% 0.86%
concurrent_lockless/1 uring latency_mean_ns 14.54 µs 14.52 µs 🟢▲ +0.24% 0.49%
concurrent_lockless/16 epoll latency_mean_ns 231.96 µs 230.50 µs 🟢▲ +0.15% 1.08%
concurrent_lockless/16 uring latency_mean_ns 235.27 µs 234.75 µs 🟢▲ +0.31% 0.32%
concurrent_lockless/4 epoll latency_mean_ns 57.88 µs 57.52 µs 🟢▲ +0.15% 1.21%
concurrent_lockless/4 uring latency_mean_ns 58.41 µs 58.36 µs 🟢▲ +0.27% 0.32%
pingpong/1 epoll latency_mean_ns 14.63 µs 14.60 µs 🟢▲ +0.14% 1.15%
pingpong/1 uring latency_mean_ns 14.46 µs 14.50 µs 🔴▼ -0.39% 0.27%
pingpong/1024 epoll latency_mean_ns 15.03 µs 14.92 µs 🟢▲ +0.22% 1.07%
pingpong/1024 uring latency_mean_ns 14.81 µs 14.79 µs 🟢▲ +0.24% 0.35%
pingpong/64 epoll latency_mean_ns 14.73 µs 14.64 µs 🟢▲ +0.04% 1.33%
pingpong/64 uring latency_mean_ns 14.54 µs 14.55 µs 🟢▲ +0.04% 0.32%
pingpong_lockless/1 epoll latency_mean_ns 14.61 µs 14.54 µs 🔴▼ -0.03% 1.12%
pingpong_lockless/1 uring latency_mean_ns 14.45 µs 14.45 µs 🟢▲ +0.02% 0.35%
pingpong_lockless/1024 epoll latency_mean_ns 14.93 µs 14.87 µs 🟢▲ +0.13% 1.15%
pingpong_lockless/1024 uring latency_mean_ns 14.76 µs 14.76 µs 🟢▲ +0.13% 0.46%
pingpong_lockless/64 epoll latency_mean_ns 14.67 µs 14.61 µs 🟢▲ +0.08% 1.16%
pingpong_lockless/64 uring latency_mean_ns 14.53 µs 14.53 µs 🔴▼ -0.09% 0.40%

socket_throughput

Benchmark Backend Metric Base Head Δ Noise
bidirectional/1024 epoll bytes_per_sec 135.4 MB/s 134.2 MB/s 🔴▼ -0.32% 1.34%
bidirectional/1024 uring bytes_per_sec 140.9 MB/s 140.5 MB/s 🔴▼ -0.18% 0.99%
bidirectional/1048576 epoll bytes_per_sec 3.30 GB/s 3.32 GB/s 🟢▲ +0.15% 2.10%
bidirectional/1048576 uring bytes_per_sec 3.24 GB/s 3.26 GB/s 🟢▲ +0.42% 0.63%
bidirectional/16384 epoll bytes_per_sec 1.64 GB/s 1.65 GB/s 🟢▲ +0.65% 0.87%
bidirectional/16384 uring bytes_per_sec 1.55 GB/s 1.54 GB/s 🟢▲ +0.39% 2.50%
bidirectional/262144 epoll bytes_per_sec 3.23 GB/s 3.21 GB/s 🔴▼ -0.24% 1.05%
bidirectional/262144 uring bytes_per_sec 3.21 GB/s 3.15 GB/s 🔴▼ -1.77% 1.19%
bidirectional/4096 epoll bytes_per_sec 507.3 MB/s 506.8 MB/s 🟢▲ +0.42% 1.35%
bidirectional/4096 uring bytes_per_sec 492.0 MB/s 491.2 MB/s 🟢▲ +0.28% 1.45%
bidirectional/65536 epoll bytes_per_sec 2.64 GB/s 2.58 GB/s 🔴▼ -2.02% 2.32%
bidirectional/65536 uring bytes_per_sec 2.78 GB/s 2.80 GB/s 🟢▲ +0.55% 1.02%
bidirectional_lockless/1024 epoll bytes_per_sec 135.2 MB/s 134.6 MB/s 🔴▼ -0.36% 0.99%
bidirectional_lockless/1024 uring bytes_per_sec 140.8 MB/s 140.9 MB/s 🟢▲ +0.05% 0.41%
bidirectional_lockless/1048576 epoll bytes_per_sec 3.30 GB/s 3.34 GB/s 🟢▲ +0.20% 3.26%
bidirectional_lockless/1048576 uring bytes_per_sec 3.36 GB/s 3.32 GB/s 🔴▼ -0.98% 0.91%
bidirectional_lockless/16384 epoll bytes_per_sec 1.64 GB/s 1.63 GB/s 🟢▲ +0.09% 2.23%
bidirectional_lockless/16384 uring bytes_per_sec 1.54 GB/s 1.54 GB/s 🟢▲ +0.09% 0.39%
bidirectional_lockless/262144 epoll bytes_per_sec 3.22 GB/s 3.22 GB/s 🟢▲ +0.22% 0.99%
bidirectional_lockless/262144 uring bytes_per_sec 3.28 GB/s 3.24 GB/s 🔴▼ -1.09% 1.00%
bidirectional_lockless/4096 epoll bytes_per_sec 509.4 MB/s 506.9 MB/s 🔴▼ -0.73% 0.72%
bidirectional_lockless/4096 uring bytes_per_sec 493.8 MB/s 494.2 MB/s 🟢▲ +0.17% 0.43%
bidirectional_lockless/65536 epoll bytes_per_sec 2.58 GB/s 2.58 GB/s 🟢▲ +2.64% 3.33%
bidirectional_lockless/65536 uring bytes_per_sec 2.76 GB/s 2.78 GB/s 🟢▲ +1.38% 1.69%
multithread/2 epoll bytes_per_sec 3.41 GB/s 3.39 GB/s 🔴▼ -0.40% 0.50%
multithread/2 uring bytes_per_sec 3.63 GB/s 3.67 GB/s 🔴▼ -0.17% 1.15%
multithread/4 epoll bytes_per_sec 4.85 GB/s 4.88 GB/s 🟢▲ +0.35% 0.51%
multithread/4 uring bytes_per_sec 5.07 GB/s 5.06 GB/s 🔴▼ -0.48% 0.45%
multithread/8 epoll bytes_per_sec 4.96 GB/s 4.97 GB/s 🟢▲ +0.19% 0.14%
multithread/8 uring bytes_per_sec 5.13 GB/s 5.14 GB/s 🟢▲ +0.07% 0.23%
unidirectional/1024 epoll bytes_per_sec 125.5 MB/s 125.6 MB/s ⚪ 0.00% 0.25%
unidirectional/1024 uring bytes_per_sec 139.5 MB/s 140.3 MB/s 🟢▲ +0.37% 1.21%
unidirectional/1048576 epoll bytes_per_sec 3.34 GB/s 3.36 GB/s 🟢▲ +0.29% 1.45%
unidirectional/1048576 uring bytes_per_sec 3.41 GB/s 3.43 GB/s 🟢▲ +0.33% 0.82%
unidirectional/16384 epoll bytes_per_sec 1.56 GB/s 1.54 GB/s 🔴▼ -1.20% 1.35%
unidirectional/16384 uring bytes_per_sec 1.55 GB/s 1.58 GB/s 🟢▲ +1.83% 2.10%
unidirectional/262144 epoll bytes_per_sec 3.34 GB/s 3.33 GB/s 🔴▼ -0.82% 0.71%
unidirectional/262144 uring bytes_per_sec 3.20 GB/s 3.21 GB/s 🔴▼ -0.20% 0.77%
unidirectional/4096 epoll bytes_per_sec 470.5 MB/s 472.1 MB/s 🟢▲ +0.14% 0.64%
unidirectional/4096 uring bytes_per_sec 489.5 MB/s 492.0 MB/s 🟢▲ +0.06% 1.03%
unidirectional/65536 epoll bytes_per_sec 2.63 GB/s 2.69 GB/s 🟢▲ +0.13% 5.37%
unidirectional/65536 uring bytes_per_sec 2.71 GB/s 2.70 GB/s 🟢▲ +0.89% 2.93%
unidirectional_lockless/1024 epoll bytes_per_sec 126.6 MB/s 126.3 MB/s 🔴▼ -0.02% 0.71%
unidirectional_lockless/1024 uring bytes_per_sec 139.4 MB/s 139.1 MB/s 🔴▼ -0.24% 0.48%
unidirectional_lockless/1048576 epoll bytes_per_sec 3.39 GB/s 3.37 GB/s 🔴▼ -0.57% 1.67%
unidirectional_lockless/1048576 uring bytes_per_sec 3.36 GB/s 3.38 GB/s 🟢▲ +0.32% 0.98%
unidirectional_lockless/16384 epoll bytes_per_sec 1.58 GB/s 1.57 GB/s 🔴▼ -1.38% 1.44%
unidirectional_lockless/16384 uring bytes_per_sec 1.61 GB/s 1.63 GB/s 🟢▲ +0.89% 1.35%
unidirectional_lockless/262144 epoll bytes_per_sec 3.38 GB/s 3.35 GB/s 🔴▼ -0.40% 1.82%
unidirectional_lockless/262144 uring bytes_per_sec 3.26 GB/s 3.25 GB/s 🟢▲ +0.17% 1.20%
unidirectional_lockless/4096 epoll bytes_per_sec 475.8 MB/s 474.7 MB/s 🟢▲ +0.13% 1.14%
unidirectional_lockless/4096 uring bytes_per_sec 492.9 MB/s 492.0 MB/s 🟢▲ +0.44% 0.94%
unidirectional_lockless/65536 epoll bytes_per_sec 2.76 GB/s 2.75 GB/s 🔴▼ -0.22% 2.75%
unidirectional_lockless/65536 uring bytes_per_sec 2.75 GB/s 2.71 GB/s 🔴▼ -0.12% 3.79%
windows — full results (77 benchmarks, 5 iterations, 1.5s each)

accept_churn

Benchmark Backend Metric Base Head Δ Noise
burst/10 iocp ops_per_sec 1.53K ops/s 1.55K ops/s 🟢▲ +1.42% 0.25%
burst/100 iocp ops_per_sec 149.1 ops/s 155.6 ops/s 🟢▲ +4.40% 0.93%
burst_lockless/10 iocp ops_per_sec 1.53K ops/s 1.56K ops/s 🟢▲ +1.65% 0.18%
burst_lockless/100 iocp ops_per_sec 152.4 ops/s 158.5 ops/s 🟢▲ +3.85% 0.64%
concurrent/1 iocp ops_per_sec 12.24K ops/s 12.49K ops/s 🟢▲ +1.84% 1.42%
concurrent/16 iocp ops_per_sec 13.21K ops/s 13.46K ops/s 🟢▲ +1.79% 0.45%
concurrent/4 iocp ops_per_sec 12.92K ops/s 13.15K ops/s 🟢▲ +1.88% 0.38%
sequential iocp ops_per_sec 12.19K ops/s 12.44K ops/s 🟢▲ +1.62% 1.26%
sequential_lockless iocp ops_per_sec 12.28K ops/s 12.51K ops/s 🟢▲ +1.14% 1.33%

fan_out

Benchmark Backend Metric Base Head Δ Noise
concurrent_parents/1 iocp ops_per_sec 7.20K ops/s 7.23K ops/s 🟢▲ +0.23% 0.36%
concurrent_parents/16 iocp ops_per_sec 6.46K ops/s 6.47K ops/s 🟢▲ +0.05% 1.41%
concurrent_parents/4 iocp ops_per_sec 6.91K ops/s 6.95K ops/s 🟢▲ +0.83% 0.79%
concurrent_parents_lockless/1 iocp ops_per_sec 7.20K ops/s 7.22K ops/s 🟢▲ +0.50% 0.39%
concurrent_parents_lockless/16 iocp ops_per_sec 6.49K ops/s 6.51K ops/s 🟢▲ +0.32% 1.50%
concurrent_parents_lockless/4 iocp ops_per_sec 6.93K ops/s 6.98K ops/s 🟢▲ +0.75% 0.64%
fork_join/1 iocp ops_per_sec 113.5K ops/s 113.6K ops/s 🟢▲ +0.35% 0.46%
fork_join/16 iocp ops_per_sec 7.17K ops/s 7.24K ops/s 🟢▲ +0.52% 0.69%
fork_join/4 iocp ops_per_sec 29.37K ops/s 29.41K ops/s 🟢▲ +0.30% 0.50%
fork_join/64 iocp ops_per_sec 1.72K ops/s 1.74K ops/s 🟢▲ +0.47% 1.25%
fork_join_lockless/1 iocp ops_per_sec 113.3K ops/s 113.6K ops/s 🟢▲ +0.13% 0.41%
fork_join_lockless/16 iocp ops_per_sec 7.18K ops/s 7.23K ops/s 🟢▲ +0.30% 0.31%
fork_join_lockless/4 iocp ops_per_sec 29.31K ops/s 29.42K ops/s 🟢▲ +0.34% 0.24%
fork_join_lockless/64 iocp ops_per_sec 1.73K ops/s 1.74K ops/s 🟢▲ +0.67% 1.00%
nested/16 iocp ops_per_sec 1.70K ops/s 1.71K ops/s 🟢▲ +0.72% 1.21%
nested/4 iocp ops_per_sec 7.04K ops/s 7.08K ops/s 🟢▲ +0.60% 0.25%
nested_lockless/16 iocp ops_per_sec 1.70K ops/s 1.71K ops/s 🟢▲ +0.20% 1.20%
nested_lockless/4 iocp ops_per_sec 7.03K ops/s 7.08K ops/s 🟢▲ +0.74% 0.32%

http_server

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 iocp ops_per_sec 111.6K ops/s 112.0K ops/s 🟢▲ +0.58% 0.49%
concurrent/16 iocp ops_per_sec 108.3K ops/s 109.2K ops/s 🟢▲ +0.54% 0.44%
concurrent/32 iocp ops_per_sec 107.7K ops/s 108.8K ops/s 🟢▲ +1.12% 0.31%
concurrent/4 iocp ops_per_sec 109.2K ops/s 109.7K ops/s 🟢▲ +0.27% 0.48%
multithread/1 iocp ops_per_sec 107.8K ops/s 108.9K ops/s 🟢▲ +1.15% 0.30%
multithread/16 iocp ops_per_sec 266.1K ops/s 267.1K ops/s 🟢▲ +0.35% 0.58%
multithread/2 iocp ops_per_sec 180.9K ops/s 182.3K ops/s 🟢▲ +0.71% 0.96%
multithread/4 iocp ops_per_sec 224.6K ops/s 225.7K ops/s 🟢▲ +0.53% 0.83%
multithread/8 iocp ops_per_sec 265.5K ops/s 267.7K ops/s 🟢▲ +0.63% 0.45%
single_conn iocp ops_per_sec 111.8K ops/s 111.8K ops/s 🔴▼ -0.17% 0.57%
single_conn_lockless iocp ops_per_sec 111.7K ops/s 112.2K ops/s 🟢▲ +0.46% 0.51%

socket_latency

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 iocp latency_mean_ns 7.59 µs 7.55 µs 🟢▲ +0.36% 0.33%
concurrent/16 iocp latency_mean_ns 125.94 µs 127.93 µs 🔴▼ -1.01% 3.55%
concurrent/4 iocp latency_mean_ns 30.39 µs 30.50 µs 🔴▼ -0.34% 0.52%
concurrent_lockless/1 iocp latency_mean_ns 7.59 µs 7.56 µs 🟢▲ +0.17% 0.39%
concurrent_lockless/16 iocp latency_mean_ns 121.12 µs 121.06 µs 🟢▲ +0.14% 0.38%
concurrent_lockless/4 iocp latency_mean_ns 30.32 µs 30.41 µs 🔴▼ -0.42% 0.35%
pingpong/1 iocp latency_mean_ns 7.57 µs 7.54 µs 🟢▲ +0.38% 0.44%
pingpong/1024 iocp latency_mean_ns 7.68 µs 7.69 µs 🟢▲ +0.08% 0.38%
pingpong/64 iocp latency_mean_ns 7.59 µs 7.58 µs 🔴▼ -0.03% 0.24%
pingpong_lockless/1 iocp latency_mean_ns 7.56 µs 7.53 µs 🟢▲ +0.52% 0.55%
pingpong_lockless/1024 iocp latency_mean_ns 7.68 µs 7.68 µs 🟢▲ +0.05% 0.26%
pingpong_lockless/64 iocp latency_mean_ns 7.60 µs 7.56 µs 🟢▲ +0.61% 0.26%

socket_throughput

Benchmark Backend Metric Base Head Δ Noise
bidirectional/1024 iocp bytes_per_sec 282.3 MB/s 282.8 MB/s 🟢▲ +0.07% 0.64%
bidirectional/1048576 iocp bytes_per_sec 5.72 GB/s 5.20 GB/s 🔴▼ -13.04% 8.36%
bidirectional/16384 iocp bytes_per_sec 3.75 GB/s 3.77 GB/s 🟢▲ +0.42% 0.70%
bidirectional/262144 iocp bytes_per_sec 9.41 GB/s 9.62 GB/s 🟢▲ +2.18% 1.77%
bidirectional/4096 iocp bytes_per_sec 1.08 GB/s 1.09 GB/s 🟢▲ +0.37% 0.40%
bidirectional/65536 iocp bytes_per_sec 9.01 GB/s 9.09 GB/s 🟢▲ +0.29% 2.38%
bidirectional_lockless/1024 iocp bytes_per_sec 281.9 MB/s 282.5 MB/s 🟢▲ +0.26% 0.42%
bidirectional_lockless/1048576 iocp bytes_per_sec 5.94 GB/s 5.52 GB/s 🔴▼ -8.07% 6.07%
bidirectional_lockless/16384 iocp bytes_per_sec 3.73 GB/s 3.73 GB/s 🔴▼ -0.05% 0.67%
bidirectional_lockless/262144 iocp bytes_per_sec 9.59 GB/s 9.69 GB/s 🟢▲ +1.84% 2.56%
bidirectional_lockless/4096 iocp bytes_per_sec 1.08 GB/s 1.08 GB/s 🟢▲ +0.31% 0.39%
bidirectional_lockless/65536 iocp bytes_per_sec 9.01 GB/s 8.95 GB/s 🔴▼ -0.59% 1.70%
multithread/2 iocp bytes_per_sec 12.80 GB/s 12.72 GB/s 🔴▼ -0.18% 1.06%
multithread/4 iocp bytes_per_sec 16.95 GB/s 17.13 GB/s 🟢▲ +0.27% 1.17%
multithread/8 iocp bytes_per_sec 18.42 GB/s 18.50 GB/s 🔴▼ -0.17% 1.14%
unidirectional/1024 iocp bytes_per_sec 285.4 MB/s 286.5 MB/s 🟢▲ +0.06% 0.66%
unidirectional/1048576 iocp bytes_per_sec 4.35 GB/s 4.39 GB/s 🟢▲ +1.73% 5.29%
unidirectional/16384 iocp bytes_per_sec 3.80 GB/s 3.80 GB/s 🔴▼ -0.16% 0.41%
unidirectional/262144 iocp bytes_per_sec 8.62 GB/s 9.12 GB/s 🟢▲ +5.37% 5.29%
unidirectional/4096 iocp bytes_per_sec 1.10 GB/s 1.10 GB/s 🔴▼ -0.23% 0.57%
unidirectional/65536 iocp bytes_per_sec 9.27 GB/s 9.31 GB/s 🟢▲ +0.04% 1.73%
unidirectional_lockless/1024 iocp bytes_per_sec 285.7 MB/s 287.0 MB/s 🟢▲ +0.54% 0.44%
unidirectional_lockless/1048576 iocp bytes_per_sec 5.19 GB/s 4.85 GB/s 🔴▼ -5.51% 4.53%
unidirectional_lockless/16384 iocp bytes_per_sec 3.79 GB/s 3.81 GB/s 🟢▲ +0.57% 1.08%
unidirectional_lockless/262144 iocp bytes_per_sec 9.66 GB/s 9.75 GB/s 🟢▲ +0.22% 2.30%
unidirectional_lockless/4096 iocp bytes_per_sec 1.10 GB/s 1.10 GB/s 🔴▼ -0.03% 0.54%
unidirectional_lockless/65536 iocp bytes_per_sec 9.21 GB/s 9.39 GB/s ⚪ 0.00% 3.99%
macos — full results (113 benchmarks, 5 iterations, 1.5s each)

accept_churn

Benchmark Backend Metric Base Head Δ Noise
burst/10 kqueue ops_per_sec 4.26K ops/s 4.40K ops/s 🟢▲ +2.84% 1.13%
burst/100 kqueue ops_per_sec 431.9 ops/s 443.3 ops/s 🟢▲ +3.36% 0.81%
burst_lockless/10 kqueue ops_per_sec 4.28K ops/s 4.40K ops/s 🟢▲ +2.88% 0.98%
burst_lockless/100 kqueue ops_per_sec 436.2 ops/s 452.3 ops/s 🟢▲ +3.25% 1.35%
concurrent/1 kqueue ops_per_sec 19.58K ops/s 20.18K ops/s 🟢▲ +3.49% 1.03%
concurrent/16 kqueue ops_per_sec 35.63K ops/s 36.46K ops/s 🟢▲ +2.65% 1.14%
concurrent/4 kqueue ops_per_sec 29.10K ops/s 29.24K ops/s 🔴▼ -0.08% 0.86%
sequential kqueue ops_per_sec 19.88K ops/s 20.37K ops/s 🟢▲ +2.21% 0.74%
sequential_lockless kqueue ops_per_sec 19.80K ops/s 20.14K ops/s 🟢▲ +1.86% 1.20%

fan_out

Benchmark Backend Metric Base Head Δ Noise
concurrent_parents/1 kqueue ops_per_sec 7.67K ops/s 7.69K ops/s 🔴▼ -0.04% 1.08%
concurrent_parents/16 kqueue ops_per_sec 7.99K ops/s 8.04K ops/s 🔴▼ -0.23% 14.60%
concurrent_parents/4 kqueue ops_per_sec 8.13K ops/s 8.06K ops/s 🔴▼ -0.32% 1.82%
concurrent_parents_lockless/1 kqueue ops_per_sec 7.74K ops/s 7.73K ops/s 🔴▼ -0.11% 1.18%
concurrent_parents_lockless/16 kqueue ops_per_sec 8.08K ops/s 8.05K ops/s 🟢▲ +0.39% 14.77%
concurrent_parents_lockless/4 kqueue ops_per_sec 8.15K ops/s 8.14K ops/s 🔴▼ -0.03% 1.58%
fork_join/1 kqueue ops_per_sec 45.79K ops/s 45.79K ops/s 🟢▲ +0.43% 1.26%
fork_join/16 kqueue ops_per_sec 7.69K ops/s 7.69K ops/s 🔴▼ -0.06% 1.18%
fork_join/4 kqueue ops_per_sec 21.71K ops/s 21.81K ops/s 🟢▲ +0.69% 0.51%
fork_join/64 kqueue ops_per_sec 2.02K ops/s 2.02K ops/s 🟢▲ +0.28% 2.47%
fork_join_lockless/1 kqueue ops_per_sec 47.00K ops/s 46.91K ops/s 🔴▼ -0.19% 0.08%
fork_join_lockless/16 kqueue ops_per_sec 7.74K ops/s 7.74K ops/s 🔴▼ -0.24% 1.34%
fork_join_lockless/4 kqueue ops_per_sec 21.90K ops/s 21.88K ops/s 🟢▲ +0.19% 0.53%
fork_join_lockless/64 kqueue ops_per_sec 2.03K ops/s 2.02K ops/s 🔴▼ -0.11% 2.48%
nested/16 kqueue ops_per_sec 2.00K ops/s 1.99K ops/s 🔴▼ -0.08% 1.79%
nested/4 kqueue ops_per_sec 7.06K ops/s 7.06K ops/s 🔴▼ -0.06% 0.92%
nested_lockless/16 kqueue ops_per_sec 2.01K ops/s 2.00K ops/s 🟢▲ +0.69% 2.41%
nested_lockless/4 kqueue ops_per_sec 7.15K ops/s 7.13K ops/s 🔴▼ -0.50% 1.25%

http_server

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 kqueue ops_per_sec 49.59K ops/s 49.25K ops/s 🔴▼ -0.42% 0.38%
concurrent/16 kqueue ops_per_sec 127.3K ops/s 129.0K ops/s 🟢▲ +1.19% 0.69%
concurrent/32 kqueue ops_per_sec 127.0K ops/s 128.8K ops/s 🟢▲ +1.50% 1.41%
concurrent/4 kqueue ops_per_sec 88.02K ops/s 88.77K ops/s 🟢▲ +0.87% 0.55%
multithread/1 kqueue ops_per_sec 126.8K ops/s 128.4K ops/s 🟢▲ +0.84% 1.29%
multithread/16 kqueue ops_per_sec 127.3K ops/s 127.5K ops/s 🔴▼ -0.14% 0.67%
multithread/2 kqueue ops_per_sec 176.9K ops/s 177.2K ops/s 🟢▲ +0.42% 1.77%
multithread/4 kqueue ops_per_sec 160.8K ops/s 161.5K ops/s 🟢▲ +0.38% 1.01%
multithread/8 kqueue ops_per_sec 132.6K ops/s 132.0K ops/s 🔴▼ -1.40% 1.62%
single_conn kqueue ops_per_sec 49.65K ops/s 49.34K ops/s 🔴▼ -0.47% 0.27%
single_conn_lockless kqueue ops_per_sec 49.80K ops/s 49.51K ops/s 🔴▼ -0.59% 0.34%

local_socket_latency

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 kqueue latency_mean_ns 2.06 µs 2.06 µs 🔴▼ -0.10% 0.24%
concurrent/16 kqueue latency_mean_ns 30.64 µs 30.53 µs 🟢▲ +0.16% 0.32%
concurrent/4 kqueue latency_mean_ns 7.66 µs 7.65 µs 🟢▲ +0.29% 0.37%
concurrent_lockless/1 kqueue latency_mean_ns 2.02 µs 2.04 µs 🔴▼ -0.89% 0.45%
concurrent_lockless/16 kqueue latency_mean_ns 30.13 µs 30.11 µs 🟢▲ +0.04% 0.27%
concurrent_lockless/4 kqueue latency_mean_ns 7.54 µs 7.54 µs 🔴▼ -0.05% 0.37%
pingpong/1 kqueue latency_mean_ns 2.05 µs 2.06 µs 🔴▼ -0.54% 0.49%
pingpong/1024 kqueue latency_mean_ns 2.16 µs 2.16 µs 🟢▲ +0.14% 0.34%
pingpong/64 kqueue latency_mean_ns 2.05 µs 2.06 µs 🔴▼ -0.07% 0.31%
pingpong_lockless/1 kqueue latency_mean_ns 2.02 µs 2.03 µs 🔴▼ -0.42% 0.64%
pingpong_lockless/1024 kqueue latency_mean_ns 2.13 µs 2.13 µs 🔴▼ -0.29% 0.14%
pingpong_lockless/64 kqueue latency_mean_ns 2.02 µs 2.03 µs 🔴▼ -0.23% 0.33%

local_socket_throughput

Benchmark Backend Metric Base Head Δ Noise
bidirectional/1024 kqueue bytes_per_sec 1.22 GB/s 1.22 GB/s 🔴▼ -0.01% 0.32%
bidirectional/1048576 kqueue bytes_per_sec 3.85 GB/s 3.86 GB/s 🟢▲ +0.41% 0.38%
bidirectional/16384 kqueue bytes_per_sec 3.85 GB/s 3.87 GB/s 🔴▼ -0.07% 1.12%
bidirectional/262144 kqueue bytes_per_sec 3.86 GB/s 3.86 GB/s 🟢▲ +0.44% 0.94%
bidirectional/4096 kqueue bytes_per_sec 2.91 GB/s 2.92 GB/s 🟢▲ +0.15% 0.65%
bidirectional/65536 kqueue bytes_per_sec 3.86 GB/s 3.86 GB/s 🔴▼ -0.60% 1.05%
bidirectional_lockless/1024 kqueue bytes_per_sec 1.23 GB/s 1.23 GB/s 🔴▼ -0.34% 0.44%
bidirectional_lockless/1048576 kqueue bytes_per_sec 3.90 GB/s 3.92 GB/s 🟢▲ +0.13% 0.83%
bidirectional_lockless/16384 kqueue bytes_per_sec 3.92 GB/s 3.91 GB/s 🔴▼ -0.11% 0.41%
bidirectional_lockless/262144 kqueue bytes_per_sec 3.91 GB/s 3.91 GB/s 🟢▲ +0.22% 0.81%
bidirectional_lockless/4096 kqueue bytes_per_sec 2.96 GB/s 2.94 GB/s 🔴▼ -0.45% 0.38%
bidirectional_lockless/65536 kqueue bytes_per_sec 3.92 GB/s 3.90 GB/s 🔴▼ -0.42% 0.75%
unidirectional/1024 kqueue bytes_per_sec 1.19 GB/s 1.19 GB/s 🟢▲ +0.09% 0.44%
unidirectional/1048576 kqueue bytes_per_sec 3.46 GB/s 3.46 GB/s 🟢▲ +0.01% 0.28%
unidirectional/16384 kqueue bytes_per_sec 3.46 GB/s 3.47 GB/s 🟢▲ +0.26% 0.36%
unidirectional/262144 kqueue bytes_per_sec 3.46 GB/s 3.46 GB/s 🔴▼ -0.47% 0.70%
unidirectional/4096 kqueue bytes_per_sec 2.68 GB/s 2.69 GB/s 🟢▲ +0.40% 0.47%
unidirectional/65536 kqueue bytes_per_sec 3.46 GB/s 3.47 GB/s 🟢▲ +0.40% 0.34%
unidirectional_lockless/1024 kqueue bytes_per_sec 1.20 GB/s 1.20 GB/s 🔴▼ -0.18% 0.47%
unidirectional_lockless/1048576 kqueue bytes_per_sec 3.50 GB/s 3.51 GB/s 🟢▲ +0.32% 0.31%
unidirectional_lockless/16384 kqueue bytes_per_sec 3.52 GB/s 3.53 GB/s 🟢▲ +0.38% 0.41%
unidirectional_lockless/262144 kqueue bytes_per_sec 3.51 GB/s 3.51 GB/s 🟢▲ +0.07% 0.34%
unidirectional_lockless/4096 kqueue bytes_per_sec 2.73 GB/s 2.72 GB/s 🔴▼ -0.40% 0.26%
unidirectional_lockless/65536 kqueue bytes_per_sec 3.52 GB/s 3.52 GB/s 🟢▲ +0.16% 0.51%

socket_latency

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 kqueue latency_mean_ns 18.80 µs 18.78 µs 🔴▼ -0.05% 0.66%
concurrent/16 kqueue latency_mean_ns 120.23 µs 120.56 µs 🔴▼ -0.15% 0.29%
concurrent/4 kqueue latency_mean_ns 43.35 µs 43.49 µs 🔴▼ -0.54% 1.06%
concurrent_lockless/1 kqueue latency_mean_ns 18.66 µs 18.76 µs 🔴▼ -0.71% 0.45%
concurrent_lockless/16 kqueue latency_mean_ns 119.68 µs 120.07 µs 🔴▼ -0.53% 0.69%
concurrent_lockless/4 kqueue latency_mean_ns 43.07 µs 43.07 µs 🔴▼ -0.08% 0.45%
pingpong/1 kqueue latency_mean_ns 15.45 µs 15.50 µs 🔴▼ -0.15% 0.80%
pingpong/1024 kqueue latency_mean_ns 18.90 µs 18.95 µs 🔴▼ -0.12% 0.30%
pingpong/64 kqueue latency_mean_ns 18.72 µs 18.77 µs 🔴▼ -0.29% 0.50%
pingpong_lockless/1 kqueue latency_mean_ns 15.40 µs 15.47 µs 🔴▼ -0.22% 0.79%
pingpong_lockless/1024 kqueue latency_mean_ns 18.93 µs 18.94 µs 🟢▲ +0.03% 0.35%
pingpong_lockless/64 kqueue latency_mean_ns 18.67 µs 18.74 µs 🔴▼ -0.33% 0.50%

socket_throughput

Benchmark Backend Metric Base Head Δ Noise
bidirectional/1024 kqueue bytes_per_sec 410.5 MB/s 408.7 MB/s 🟢▲ +0.10% 0.79%
bidirectional/1048576 kqueue bytes_per_sec 7.78 GB/s 7.54 GB/s 🔴▼ -0.77% 4.87%
bidirectional/16384 kqueue bytes_per_sec 3.99 GB/s 3.98 GB/s 🔴▼ -0.39% 0.62%
bidirectional/262144 kqueue bytes_per_sec 8.74 GB/s 8.68 GB/s 🔴▼ -0.63% 1.47%
bidirectional/4096 kqueue bytes_per_sec 1.49 GB/s 1.49 GB/s 🔴▼ -0.01% 0.65%
bidirectional/65536 kqueue bytes_per_sec 7.53 GB/s 7.51 GB/s 🟢▲ +0.80% 1.91%
bidirectional_lockless/1024 kqueue bytes_per_sec 414.1 MB/s 410.3 MB/s 🔴▼ -0.63% 0.79%
bidirectional_lockless/1048576 kqueue bytes_per_sec 7.79 GB/s 7.68 GB/s 🔴▼ -1.00% 6.56%
bidirectional_lockless/16384 kqueue bytes_per_sec 4.00 GB/s 4.01 GB/s 🟢▲ +0.82% 0.86%
bidirectional_lockless/262144 kqueue bytes_per_sec 8.72 GB/s 8.79 GB/s 🟢▲ +1.21% 1.63%
bidirectional_lockless/4096 kqueue bytes_per_sec 1.50 GB/s 1.50 GB/s 🔴▼ -0.46% 0.75%
bidirectional_lockless/65536 kqueue bytes_per_sec 7.59 GB/s 7.66 GB/s 🟢▲ +1.05% 1.18%
multithread/2 kqueue bytes_per_sec 7.68 GB/s 7.57 GB/s 🟢▲ +1.04% 3.08%
multithread/4 kqueue bytes_per_sec 3.83 GB/s 3.71 GB/s 🔴▼ -1.62% 5.39%
multithread/8 kqueue bytes_per_sec 3.30 GB/s 3.29 GB/s 🔴▼ -3.22% 5.20%
unidirectional/1024 kqueue bytes_per_sec 317.7 MB/s 316.7 MB/s 🔴▼ -0.45% 1.05%
unidirectional/1048576 kqueue bytes_per_sec 9.04 GB/s 8.78 GB/s 🔴▼ -0.33% 5.69%
unidirectional/16384 kqueue bytes_per_sec 3.71 GB/s 3.70 GB/s 🔴▼ -0.25% 0.50%
unidirectional/262144 kqueue bytes_per_sec 8.82 GB/s 8.83 GB/s 🔴▼ -0.74% 3.57%
unidirectional/4096 kqueue bytes_per_sec 1.23 GB/s 1.24 GB/s 🟢▲ +0.08% 1.71%
unidirectional/65536 kqueue bytes_per_sec 7.26 GB/s 7.23 GB/s 🟢▲ +0.20% 2.01%
unidirectional_lockless/1024 kqueue bytes_per_sec 327.9 MB/s 327.2 MB/s 🔴▼ -0.02% 0.38%
unidirectional_lockless/1048576 kqueue bytes_per_sec 9.03 GB/s 8.85 GB/s 🟢▲ +0.14% 5.30%
unidirectional_lockless/16384 kqueue bytes_per_sec 3.73 GB/s 3.74 GB/s 🟢▲ +0.19% 1.17%
unidirectional_lockless/262144 kqueue bytes_per_sec 8.85 GB/s 8.79 GB/s 🔴▼ -1.19% 0.98%
unidirectional_lockless/4096 kqueue bytes_per_sec 1.25 GB/s 1.24 GB/s 🔴▼ -0.57% 1.42%
unidirectional_lockless/65536 kqueue bytes_per_sec 7.21 GB/s 7.20 GB/s 🔴▼ -0.54% 2.13%

Run & raw JSON artifacts · flag rule: |median Δ| > max(2%, 3×CV of the noisier side) · advisory only

@sgerbino
sgerbino marked this pull request as ready for review October 8, 2026 19:12

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

refactor: pool and recycle io_object impls owned by services

2 participants