Skip to content

Report sync API runtime failures through return values - #406

Merged
mvandeberg merged 14 commits into
cppalliance:developfrom
sgerbino:pr/sync-results
Oct 27, 2026
Merged

mvandeberg merged 14 commits into
cppalliance:developfrom
sgerbino:pr/sync-results

Conversation

@sgerbino

Copy link
Copy Markdown
Collaborator

Synchronous calls now report runtime failures the same way async operations do: through the return value. A closed object reports bad_file_descriptor there too. Exceptions are left for root setup, contract violations, a run loop that cannot continue, and the convenience constructors that compose code-returning calls.

Breaking changes

Before After
size(), available(), release() throw return capy::results<T>
set_option() / get_option() throw return std::error_code / capy::results<Option>
ipv4_address("…"), ipv6_address("…"), ip_address("…"), endpoint("…"), local_endpoint("…") make_ipv4_address, make_ipv6_address, make_ip_address, make_endpoint, make_local_endpoint
make_socket_pair / make_mocket_pair (test) throw return capy::results<…>
bad max_events_per_poll / inline_budget_max threw std::out_of_range from the reactor io_context construction throws std::invalid_argument on every backend

A failed release() leaves the object owning the handle and returns the invalid sentinel, never descriptor 0.

The throwing convenience constructors stay: tcp_acceptor / local_stream_acceptor (context or executor, endpoint, backlog) and signal_set (context or executor, signals...), along with their native counterparts.

Fixes

  • uring: a ring wait that returns EBUSY is retried instead of throwing out of run(). This happens on the 5.15 and 6.1 kernel lines when the CQ overflows.
  • IOCP self-stop: a failed shutdown post inside work_finished() no longer calls std::terminate. The next run or poll call retries the wakeup and throws std::system_error only if the retry also fails.
  • Windows connect_pair: setup failures come back as error codes instead of escaping noexcept.
  • Native accept() on a moved-from acceptor: completes with bad_file_descriptor instead of throwing logic_error. A peer accepted for a destroyed awaiter is now closed.

Other changes

  • tcp_server::bind binds without exceptions.
  • The native acceptors and native signal set gain the base convenience constructors.
  • The rulebook, guide and run-loop docs now describe the error model.
  • Tests use std::ignore instead of (void) casts.
  • Unused detail/except.hpp includes are removed.

Each of the 14 commits builds and passes the test suite on its own.

Resolves #400

A failed size query, a busy release and a failed FIONREAD are ordinary runtime outcomes, so they now come back through the return value like every async operation, and a closed object reports bad_file_descriptor there too. A failed release leaves the object owning the handle and carries the invalid sentinel, never descriptor 0.
An option the kernel rejects is a runtime outcome, and so is a closed socket, so both now come back through the return value. Bench setup checks every set_option call instead of letting a failed TCP_NODELAY skew its numbers.
… with make_* factories

Unparseable input is a runtime outcome, so the make_* factories are now the only way to build an address or endpoint from a string. make_local_endpoint replaces the local_endpoint path constructor, reporting filename_too_long for a path the socket address cannot hold instead of throwing it.
@cppalliance-bot

cppalliance-bot commented Oct 27, 2026 •

Copy link
Copy Markdown

An automated preview of the documentation is available at https://406.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-27 17:40:59 UTC

@cppalliance-bot

cppalliance-bot commented Oct 27, 2026 •

Copy link
Copy Markdown

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

Build time: 2026-10-27 18:01:35 UTC

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Benchmark report

1f6e774b240c (base) vs 5e91ab49ac99 (head)

  • ✅ linux — clean (epoll, uring)
  • ✅ windows — clean (iocp)
  • ✅ macos — clean (kqueue)
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.92K ops/s 1.91K ops/s 🔴▼ -0.28% 1.15%
burst/10 uring ops_per_sec 1.82K ops/s 1.81K ops/s 🔴▼ -0.37% 0.96%
burst/100 epoll ops_per_sec 193.3 ops/s 192.8 ops/s 🔴▼ -0.05% 0.59%
burst/100 uring ops_per_sec 186.7 ops/s 186.8 ops/s 🟢▲ +0.33% 0.61%
burst_lockless/10 epoll ops_per_sec 1.93K ops/s 1.93K ops/s 🟢▲ +0.02% 0.24%
burst_lockless/10 uring ops_per_sec 1.96K ops/s 1.96K ops/s 🔴▼ -0.03% 1.29%
burst_lockless/100 epoll ops_per_sec 194.8 ops/s 195.1 ops/s 🟢▲ +0.30% 0.25%
burst_lockless/100 uring ops_per_sec 199.9 ops/s 200.0 ops/s ⚪ 0.00% 0.62%
concurrent/1 epoll ops_per_sec 15.25K ops/s 15.23K ops/s 🔴▼ -0.15% 1.36%
concurrent/1 uring ops_per_sec 13.68K ops/s 13.56K ops/s 🔴▼ -0.67% 0.60%
concurrent/16 epoll ops_per_sec 15.32K ops/s 15.25K ops/s 🟢▲ +0.14% 1.55%
concurrent/16 uring ops_per_sec 13.65K ops/s 13.49K ops/s 🔴▼ -1.72% 0.98%
concurrent/4 epoll ops_per_sec 15.30K ops/s 15.26K ops/s 🔴▼ -0.14% 1.46%
concurrent/4 uring ops_per_sec 13.65K ops/s 13.49K ops/s 🔴▼ -1.67% 0.95%
sequential epoll ops_per_sec 15.26K ops/s 15.23K ops/s 🔴▼ -0.01% 1.34%
sequential uring ops_per_sec 13.70K ops/s 13.62K ops/s 🟢▲ +0.24% 1.06%
sequential_lockless epoll ops_per_sec 15.45K ops/s 15.41K ops/s 🟢▲ +0.33% 1.31%
sequential_lockless uring ops_per_sec 14.58K ops/s 14.51K ops/s 🔴▼ -0.45% 0.87%

fan_out

Benchmark Backend Metric Base Head Δ Noise
concurrent_parents/1 epoll ops_per_sec 3.69K ops/s 3.69K ops/s 🔴▼ -0.06% 0.20%
concurrent_parents/1 uring ops_per_sec 3.42K ops/s 3.45K ops/s 🟢▲ +0.13% 1.25%
concurrent_parents/16 epoll ops_per_sec 3.57K ops/s 3.57K ops/s 🟢▲ +0.05% 0.15%
concurrent_parents/16 uring ops_per_sec 3.32K ops/s 3.34K ops/s 🟢▲ +0.04% 1.40%
concurrent_parents/4 epoll ops_per_sec 3.59K ops/s 3.59K ops/s 🟢▲ +0.19% 0.32%
concurrent_parents/4 uring ops_per_sec 3.33K ops/s 3.35K ops/s 🟢▲ +0.06% 1.22%
concurrent_parents_lockless/1 epoll ops_per_sec 3.73K ops/s 3.73K ops/s 🔴▼ -0.03% 0.75%
concurrent_parents_lockless/1 uring ops_per_sec 3.48K ops/s 3.49K ops/s 🔴▼ -0.04% 1.35%
concurrent_parents_lockless/16 epoll ops_per_sec 3.61K ops/s 3.62K ops/s 🟢▲ +0.03% 0.95%
concurrent_parents_lockless/16 uring ops_per_sec 3.36K ops/s 3.37K ops/s 🟢▲ +0.57% 1.14%
concurrent_parents_lockless/4 epoll ops_per_sec 3.62K ops/s 3.64K ops/s 🟢▲ +0.07% 0.89%
concurrent_parents_lockless/4 uring ops_per_sec 3.38K ops/s 3.39K ops/s 🟢▲ +0.22% 1.28%
fork_join/1 epoll ops_per_sec 54.46K ops/s 54.58K ops/s 🟢▲ +0.17% 0.17%
fork_join/1 uring ops_per_sec 53.16K ops/s 52.89K ops/s 🔴▼ -0.66% 1.22%
fork_join/16 epoll ops_per_sec 3.68K ops/s 3.70K ops/s 🟢▲ +0.19% 1.02%
fork_join/16 uring ops_per_sec 3.44K ops/s 3.44K ops/s 🔴▼ -0.23% 1.15%
fork_join/4 epoll ops_per_sec 14.60K ops/s 14.62K ops/s 🟢▲ +0.21% 0.31%
fork_join/4 uring ops_per_sec 13.74K ops/s 13.75K ops/s 🟢▲ +0.12% 1.19%
fork_join/64 epoll ops_per_sec 899.1 ops/s 902.4 ops/s 🔴▼ -0.12% 1.09%
fork_join/64 uring ops_per_sec 817.1 ops/s 814.3 ops/s 🔴▼ -0.35% 1.13%
fork_join_lockless/1 epoll ops_per_sec 55.43K ops/s 55.42K ops/s 🔴▼ -0.19% 1.08%
fork_join_lockless/1 uring ops_per_sec 53.88K ops/s 53.65K ops/s 🔴▼ -0.17% 1.17%
fork_join_lockless/16 epoll ops_per_sec 3.74K ops/s 3.74K ops/s 🟢▲ +0.12% 1.25%
fork_join_lockless/16 uring ops_per_sec 3.48K ops/s 3.48K ops/s 🟢▲ +0.02% 1.08%
fork_join_lockless/4 epoll ops_per_sec 14.82K ops/s 14.84K ops/s 🟢▲ +0.04% 1.31%
fork_join_lockless/4 uring ops_per_sec 13.88K ops/s 13.87K ops/s 🔴▼ -0.09% 1.18%
fork_join_lockless/64 epoll ops_per_sec 911.1 ops/s 909.5 ops/s 🟢▲ +0.04% 1.31%
fork_join_lockless/64 uring ops_per_sec 823.0 ops/s 823.9 ops/s 🔴▼ -0.21% 1.02%
nested/16 epoll ops_per_sec 895.8 ops/s 891.8 ops/s ⚪ 0.00% 1.19%
nested/16 uring ops_per_sec 802.7 ops/s 803.9 ops/s 🔴▼ -0.27% 1.00%
nested/4 epoll ops_per_sec 3.68K ops/s 3.67K ops/s 🟢▲ +0.18% 1.26%
nested/4 uring ops_per_sec 3.39K ops/s 3.40K ops/s 🔴▼ -0.09% 1.10%
nested_lockless/16 epoll ops_per_sec 899.5 ops/s 900.7 ops/s 🔴▼ -0.06% 0.30%
nested_lockless/16 uring ops_per_sec 814.4 ops/s 817.8 ops/s 🔴▼ -0.39% 1.22%
nested_lockless/4 epoll ops_per_sec 3.71K ops/s 3.70K ops/s 🟢▲ +0.13% 1.25%
nested_lockless/4 uring ops_per_sec 3.43K ops/s 3.44K ops/s 🔴▼ -0.06% 0.97%

http_server

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 epoll ops_per_sec 55.16K ops/s 55.26K ops/s 🟢▲ +0.19% 1.04%
concurrent/1 uring ops_per_sec 53.74K ops/s 53.36K ops/s 🔴▼ -0.28% 1.08%
concurrent/16 epoll ops_per_sec 57.81K ops/s 57.77K ops/s 🟢▲ +0.10% 0.54%
concurrent/16 uring ops_per_sec 53.27K ops/s 52.87K ops/s 🔴▼ -0.23% 1.08%
concurrent/32 epoll ops_per_sec 57.31K ops/s 57.44K ops/s 🟢▲ +0.31% 0.20%
concurrent/32 uring ops_per_sec 52.81K ops/s 52.49K ops/s 🔴▼ -0.14% 1.08%
concurrent/4 epoll ops_per_sec 57.24K ops/s 57.18K ops/s 🟢▲ +0.05% 0.91%
concurrent/4 uring ops_per_sec 53.36K ops/s 52.91K ops/s 🔴▼ -0.19% 1.17%
multithread/1 epoll ops_per_sec 57.23K ops/s 57.31K ops/s 🟢▲ +0.16% 0.23%
multithread/1 uring ops_per_sec 52.86K ops/s 52.53K ops/s 🔴▼ -0.35% 0.99%
multithread/16 epoll ops_per_sec 160.3K ops/s 159.9K ops/s 🔴▼ -0.18% 0.43%
multithread/16 uring ops_per_sec 75.87K ops/s 82.46K ops/s 🟢▲ +0.16% 19.18%
multithread/2 epoll ops_per_sec 85.89K ops/s 86.80K ops/s 🟢▲ +1.00% 0.47%
multithread/2 uring ops_per_sec 90.05K ops/s 90.63K ops/s 🟢▲ +0.59% 0.57%
multithread/4 epoll ops_per_sec 157.2K ops/s 157.4K ops/s 🔴▼ -0.23% 1.58%
multithread/4 uring ops_per_sec 79.59K ops/s 80.04K ops/s 🟢▲ +0.20% 0.64%
multithread/8 epoll ops_per_sec 158.7K ops/s 159.5K ops/s 🟢▲ +0.53% 0.64%
multithread/8 uring ops_per_sec 65.34K ops/s 71.60K ops/s 🟢▲ +0.10% 26.11%
single_conn epoll ops_per_sec 55.29K ops/s 55.24K ops/s 🟢▲ +0.10% 1.10%
single_conn uring ops_per_sec 53.75K ops/s 53.49K ops/s 🔴▼ -0.19% 0.57%
single_conn_lockless epoll ops_per_sec 55.88K ops/s 55.91K ops/s 🟢▲ +0.17% 1.10%
single_conn_lockless uring ops_per_sec 54.35K ops/s 53.96K ops/s 🔴▼ -0.25% 1.04%

local_socket_latency

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 epoll latency_mean_ns 7.21 µs 7.37 µs 🟢▲ +0.05% 4.08%
concurrent/1 uring latency_mean_ns 6.72 µs 6.76 µs 🔴▼ -0.57% 4.82%
concurrent/16 epoll latency_mean_ns 110.99 µs 110.31 µs 🟢▲ +0.45% 0.81%
concurrent/16 uring latency_mean_ns 108.51 µs 108.68 µs 🔴▼ -0.51% 1.18%
concurrent/4 epoll latency_mean_ns 27.90 µs 27.78 µs 🟢▲ +0.36% 1.53%
concurrent/4 uring latency_mean_ns 27.12 µs 27.37 µs 🔴▼ -0.40% 1.32%
concurrent_lockless/1 epoll latency_mean_ns 7.26 µs 7.01 µs 🟢▲ +1.96% 4.19%
concurrent_lockless/1 uring latency_mean_ns 6.84 µs 6.99 µs 🔴▼ -0.61% 5.27%
concurrent_lockless/16 epoll latency_mean_ns 109.68 µs 108.93 µs 🟢▲ +0.64% 0.21%
concurrent_lockless/16 uring latency_mean_ns 108.24 µs 108.42 µs 🔴▼ -0.11% 0.95%
concurrent_lockless/4 epoll latency_mean_ns 27.67 µs 27.58 µs 🟢▲ +0.27% 1.18%
concurrent_lockless/4 uring latency_mean_ns 26.97 µs 26.99 µs 🔴▼ -0.39% 1.20%
pingpong/1 epoll latency_mean_ns 7.39 µs 7.29 µs 🟢▲ +0.82% 5.14%
pingpong/1 uring latency_mean_ns 6.75 µs 6.84 µs 🟢▲ +1.03% 5.92%
pingpong/1024 epoll latency_mean_ns 7.91 µs 7.77 µs 🟢▲ +0.17% 4.42%
pingpong/1024 uring latency_mean_ns 7.51 µs 7.26 µs 🔴▼ -0.25% 5.72%
pingpong/64 epoll latency_mean_ns 7.41 µs 7.41 µs 🔴▼ -0.21% 4.92%
pingpong/64 uring latency_mean_ns 6.66 µs 6.60 µs 🔴▼ -0.44% 1.55%
pingpong_lockless/1 epoll latency_mean_ns 7.13 µs 6.98 µs 🟢▲ +0.90% 4.06%
pingpong_lockless/1 uring latency_mean_ns 6.69 µs 6.56 µs 🔴▼ -0.36% 4.23%
pingpong_lockless/1024 epoll latency_mean_ns 7.81 µs 7.38 µs 🟢▲ +8.43% 4.59%
pingpong_lockless/1024 uring latency_mean_ns 7.23 µs 7.13 µs 🔴▼ -0.70% 5.08%
pingpong_lockless/64 epoll latency_mean_ns 7.05 µs 7.00 µs 🟢▲ +0.46% 0.84%
pingpong_lockless/64 uring latency_mean_ns 6.74 µs 6.85 µs 🔴▼ -0.61% 5.30%

local_socket_throughput

Benchmark Backend Metric Base Head Δ Noise
bidirectional/1024 epoll bytes_per_sec 304.4 MB/s 305.1 MB/s 🟢▲ +0.42% 1.07%
bidirectional/1024 uring bytes_per_sec 300.6 MB/s 303.1 MB/s 🔴▼ -0.03% 1.54%
bidirectional/1048576 epoll bytes_per_sec 3.14 GB/s 3.25 GB/s 🟢▲ +1.59% 5.23%
bidirectional/1048576 uring bytes_per_sec 3.32 GB/s 3.27 GB/s 🔴▼ -2.34% 2.97%
bidirectional/16384 epoll bytes_per_sec 3.07 GB/s 3.09 GB/s 🟢▲ +0.59% 1.52%
bidirectional/16384 uring bytes_per_sec 2.39 GB/s 2.42 GB/s 🟢▲ +1.13% 1.16%
bidirectional/262144 epoll bytes_per_sec 3.19 GB/s 3.20 GB/s 🔴▼ -0.15% 1.57%
bidirectional/262144 uring bytes_per_sec 3.31 GB/s 3.29 GB/s 🔴▼ -0.50% 1.56%
bidirectional/4096 epoll bytes_per_sec 994.8 MB/s 1.01 GB/s 🟢▲ +1.03% 1.79%
bidirectional/4096 uring bytes_per_sec 987.3 MB/s 994.9 MB/s 🟢▲ +0.49% 0.91%
bidirectional/65536 epoll bytes_per_sec 2.96 GB/s 2.96 GB/s 🟢▲ +0.14% 1.78%
bidirectional/65536 uring bytes_per_sec 2.96 GB/s 2.99 GB/s 🟢▲ +0.39% 2.25%
bidirectional_lockless/1024 epoll bytes_per_sec 305.4 MB/s 310.7 MB/s 🟢▲ +0.92% 1.67%
bidirectional_lockless/1024 uring bytes_per_sec 304.1 MB/s 303.9 MB/s 🟢▲ +0.07% 0.88%
bidirectional_lockless/1048576 epoll bytes_per_sec 3.15 GB/s 3.25 GB/s 🟢▲ +2.33% 4.98%
bidirectional_lockless/1048576 uring bytes_per_sec 3.30 GB/s 3.29 GB/s 🔴▼ -0.75% 2.32%
bidirectional_lockless/16384 epoll bytes_per_sec 3.10 GB/s 3.06 GB/s 🔴▼ -2.46% 3.62%
bidirectional_lockless/16384 uring bytes_per_sec 2.42 GB/s 2.43 GB/s 🔴▼ -0.16% 0.99%
bidirectional_lockless/262144 epoll bytes_per_sec 3.20 GB/s 3.19 GB/s 🔴▼ -0.16% 2.04%
bidirectional_lockless/262144 uring bytes_per_sec 3.32 GB/s 3.30 GB/s 🟢▲ +0.20% 1.85%
bidirectional_lockless/4096 epoll bytes_per_sec 1.00 GB/s 1.01 GB/s 🟢▲ +0.59% 1.17%
bidirectional_lockless/4096 uring bytes_per_sec 996.0 MB/s 994.9 MB/s 🔴▼ -0.07% 0.86%
bidirectional_lockless/65536 epoll bytes_per_sec 2.96 GB/s 2.96 GB/s 🔴▼ -0.05% 2.22%
bidirectional_lockless/65536 uring bytes_per_sec 2.97 GB/s 2.99 GB/s 🟢▲ +0.99% 2.44%
unidirectional/1024 epoll bytes_per_sec 295.9 MB/s 297.7 MB/s 🟢▲ +0.42% 0.97%
unidirectional/1024 uring bytes_per_sec 303.4 MB/s 301.4 MB/s 🔴▼ -1.41% 1.27%
unidirectional/1048576 epoll bytes_per_sec 3.24 GB/s 3.30 GB/s 🟢▲ +2.61% 3.10%
unidirectional/1048576 uring bytes_per_sec 3.44 GB/s 3.39 GB/s 🟢▲ +0.16% 3.09%
unidirectional/16384 epoll bytes_per_sec 3.06 GB/s 3.07 GB/s 🔴▼ -0.60% 2.28%
unidirectional/16384 uring bytes_per_sec 2.65 GB/s 2.64 GB/s 🔴▼ -0.48% 1.58%
unidirectional/262144 epoll bytes_per_sec 3.27 GB/s 3.23 GB/s 🔴▼ -1.24% 3.49%
unidirectional/262144 uring bytes_per_sec 3.44 GB/s 3.41 GB/s 🟢▲ +0.67% 2.07%
unidirectional/4096 epoll bytes_per_sec 974.7 MB/s 985.0 MB/s 🟢▲ +0.59% 0.77%
unidirectional/4096 uring bytes_per_sec 993.4 MB/s 991.0 MB/s 🔴▼ -0.21% 1.17%
unidirectional/65536 epoll bytes_per_sec 3.27 GB/s 3.19 GB/s 🔴▼ -1.65% 3.10%
unidirectional/65536 uring bytes_per_sec 3.21 GB/s 3.31 GB/s 🟢▲ +4.89% 3.62%
unidirectional_lockless/1024 epoll bytes_per_sec 299.9 MB/s 299.2 MB/s 🔴▼ -0.33% 0.73%
unidirectional_lockless/1024 uring bytes_per_sec 304.8 MB/s 303.4 MB/s 🔴▼ -0.50% 1.16%
unidirectional_lockless/1048576 epoll bytes_per_sec 3.26 GB/s 3.36 GB/s 🟢▲ +1.69% 3.91%
unidirectional_lockless/1048576 uring bytes_per_sec 3.44 GB/s 3.42 GB/s 🟢▲ +0.37% 3.21%
unidirectional_lockless/16384 epoll bytes_per_sec 3.07 GB/s 3.09 GB/s 🔴▼ -0.20% 2.02%
unidirectional_lockless/16384 uring bytes_per_sec 2.63 GB/s 2.65 GB/s 🟢▲ +0.01% 2.20%
unidirectional_lockless/262144 epoll bytes_per_sec 3.30 GB/s 3.25 GB/s 🔴▼ -0.79% 2.69%
unidirectional_lockless/262144 uring bytes_per_sec 3.39 GB/s 3.44 GB/s 🟢▲ +2.10% 1.80%
unidirectional_lockless/4096 epoll bytes_per_sec 982.8 MB/s 990.6 MB/s 🟢▲ +0.80% 0.25%
unidirectional_lockless/4096 uring bytes_per_sec 997.3 MB/s 995.7 MB/s 🔴▼ -0.31% 1.06%
unidirectional_lockless/65536 epoll bytes_per_sec 3.23 GB/s 3.18 GB/s 🔴▼ -1.30% 4.24%
unidirectional_lockless/65536 uring bytes_per_sec 3.22 GB/s 3.27 GB/s 🔴▼ -0.87% 2.66%

socket_latency

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 epoll latency_mean_ns 14.70 µs 14.78 µs 🔴▼ -0.06% 1.22%
concurrent/1 uring latency_mean_ns 14.57 µs 14.71 µs 🔴▼ -1.07% 0.23%
concurrent/16 epoll latency_mean_ns 230.94 µs 232.59 µs 🔴▼ -0.05% 1.44%
concurrent/16 uring latency_mean_ns 236.15 µs 237.62 µs 🔴▼ -0.63% 0.21%
concurrent/4 epoll latency_mean_ns 57.69 µs 58.21 µs 🔴▼ -0.25% 1.57%
concurrent/4 uring latency_mean_ns 58.53 µs 59.04 µs 🔴▼ -0.84% 0.23%
concurrent_lockless/1 epoll latency_mean_ns 14.53 µs 14.63 µs 🔴▼ -0.45% 1.35%
concurrent_lockless/1 uring latency_mean_ns 14.57 µs 14.68 µs 🔴▼ -0.88% 0.31%
concurrent_lockless/16 epoll latency_mean_ns 229.59 µs 230.83 µs 🔴▼ -0.08% 1.35%
concurrent_lockless/16 uring latency_mean_ns 235.65 µs 237.43 µs 🔴▼ -0.79% 0.14%
concurrent_lockless/4 epoll latency_mean_ns 57.36 µs 57.62 µs 🔴▼ -0.01% 1.42%
concurrent_lockless/4 uring latency_mean_ns 58.49 µs 58.96 µs 🔴▼ -0.76% 0.24%
pingpong/1 epoll latency_mean_ns 14.66 µs 14.73 µs 🔴▼ -0.11% 0.98%
pingpong/1 uring latency_mean_ns 14.29 µs 14.59 µs 🔴▼ -2.79% 1.49%
pingpong/1024 epoll latency_mean_ns 15.03 µs 15.06 µs 🔴▼ -0.19% 1.03%
pingpong/1024 uring latency_mean_ns 14.71 µs 14.91 µs 🔴▼ -0.91% 1.02%
pingpong/64 epoll latency_mean_ns 14.73 µs 14.82 µs 🔴▼ -0.20% 0.94%
pingpong/64 uring latency_mean_ns 14.42 µs 14.69 µs 🔴▼ -1.60% 1.44%
pingpong_lockless/1 epoll latency_mean_ns 14.48 µs 14.63 µs 🔴▼ -0.20% 1.34%
pingpong_lockless/1 uring latency_mean_ns 14.33 µs 14.58 µs 🔴▼ -0.86% 1.41%
pingpong_lockless/1024 epoll latency_mean_ns 14.91 µs 14.97 µs 🔴▼ -0.01% 1.39%
pingpong_lockless/1024 uring latency_mean_ns 14.70 µs 14.93 µs 🔴▼ -0.88% 0.88%
pingpong_lockless/64 epoll latency_mean_ns 14.61 µs 14.70 µs 🔴▼ -0.26% 1.12%
pingpong_lockless/64 uring latency_mean_ns 14.41 µs 14.68 µs 🔴▼ -0.84% 1.47%

socket_throughput

Benchmark Backend Metric Base Head Δ Noise
bidirectional/1024 epoll bytes_per_sec 133.3 MB/s 133.9 MB/s 🟢▲ +0.35% 0.37%
bidirectional/1024 uring bytes_per_sec 140.1 MB/s 140.2 MB/s 🟢▲ +0.14% 0.28%
bidirectional/1048576 epoll bytes_per_sec 3.27 GB/s 3.23 GB/s 🔴▼ -0.07% 2.02%
bidirectional/1048576 uring bytes_per_sec 3.25 GB/s 3.21 GB/s 🔴▼ -1.37% 1.24%
bidirectional/16384 epoll bytes_per_sec 1.62 GB/s 1.63 GB/s 🟢▲ +1.18% 1.70%
bidirectional/16384 uring bytes_per_sec 1.53 GB/s 1.52 GB/s 🔴▼ -0.26% 0.46%
bidirectional/262144 epoll bytes_per_sec 3.19 GB/s 3.21 GB/s 🟢▲ +0.32% 1.43%
bidirectional/262144 uring bytes_per_sec 3.19 GB/s 3.16 GB/s 🔴▼ -0.32% 1.55%
bidirectional/4096 epoll bytes_per_sec 501.8 MB/s 505.9 MB/s 🟢▲ +1.08% 0.46%
bidirectional/4096 uring bytes_per_sec 491.2 MB/s 489.6 MB/s 🔴▼ -0.06% 0.59%
bidirectional/65536 epoll bytes_per_sec 2.56 GB/s 2.60 GB/s 🟢▲ +5.06% 4.43%
bidirectional/65536 uring bytes_per_sec 2.81 GB/s 2.77 GB/s 🔴▼ -1.31% 1.46%
bidirectional_lockless/1024 epoll bytes_per_sec 134.1 MB/s 135.0 MB/s 🟢▲ +0.22% 1.09%
bidirectional_lockless/1024 uring bytes_per_sec 141.2 MB/s 140.4 MB/s 🟢▲ +0.04% 1.07%
bidirectional_lockless/1048576 epoll bytes_per_sec 3.29 GB/s 3.26 GB/s 🔴▼ -1.61% 2.17%
bidirectional_lockless/1048576 uring bytes_per_sec 3.18 GB/s 3.23 GB/s 🟢▲ +1.99% 1.52%
bidirectional_lockless/16384 epoll bytes_per_sec 1.62 GB/s 1.63 GB/s 🟢▲ +1.14% 1.74%
bidirectional_lockless/16384 uring bytes_per_sec 1.54 GB/s 1.53 GB/s 🔴▼ -0.34% 0.82%
bidirectional_lockless/262144 epoll bytes_per_sec 3.21 GB/s 3.20 GB/s 🟢▲ +0.16% 1.11%
bidirectional_lockless/262144 uring bytes_per_sec 3.14 GB/s 3.15 GB/s 🟢▲ +0.72% 1.06%
bidirectional_lockless/4096 epoll bytes_per_sec 504.6 MB/s 509.1 MB/s 🟢▲ +0.65% 1.26%
bidirectional_lockless/4096 uring bytes_per_sec 493.9 MB/s 492.0 MB/s 🟢▲ +0.38% 1.25%
bidirectional_lockless/65536 epoll bytes_per_sec 2.53 GB/s 2.60 GB/s 🟢▲ +2.23% 2.36%
bidirectional_lockless/65536 uring bytes_per_sec 2.80 GB/s 2.75 GB/s 🔴▼ -1.56% 1.58%
multithread/2 epoll bytes_per_sec 3.57 GB/s 3.53 GB/s 🔴▼ -0.22% 1.51%
multithread/2 uring bytes_per_sec 3.77 GB/s 3.75 GB/s 🔴▼ -0.63% 0.91%
multithread/4 epoll bytes_per_sec 5.24 GB/s 5.26 GB/s 🟢▲ +0.82% 0.84%
multithread/4 uring bytes_per_sec 5.40 GB/s 5.41 GB/s 🟢▲ +0.05% 0.45%
multithread/8 epoll bytes_per_sec 5.39 GB/s 5.39 GB/s 🟢▲ +0.39% 0.92%
multithread/8 uring bytes_per_sec 5.45 GB/s 5.49 GB/s 🟢▲ +0.90% 0.37%
unidirectional/1024 epoll bytes_per_sec 125.6 MB/s 125.2 MB/s 🟢▲ +0.31% 1.20%
unidirectional/1024 uring bytes_per_sec 139.6 MB/s 139.2 MB/s 🔴▼ -0.29% 1.04%
unidirectional/1048576 epoll bytes_per_sec 3.30 GB/s 3.36 GB/s 🟢▲ +1.23% 1.72%
unidirectional/1048576 uring bytes_per_sec 3.40 GB/s 3.38 GB/s 🔴▼ -0.54% 0.74%
unidirectional/16384 epoll bytes_per_sec 1.53 GB/s 1.54 GB/s 🟢▲ +0.68% 1.55%
unidirectional/16384 uring bytes_per_sec 1.55 GB/s 1.55 GB/s 🔴▼ -0.10% 2.92%
unidirectional/262144 epoll bytes_per_sec 3.28 GB/s 3.30 GB/s 🟢▲ +0.26% 1.68%
unidirectional/262144 uring bytes_per_sec 3.19 GB/s 3.16 GB/s 🔴▼ -0.89% 1.55%
unidirectional/4096 epoll bytes_per_sec 471.8 MB/s 471.4 MB/s 🟢▲ +0.40% 1.13%
unidirectional/4096 uring bytes_per_sec 492.3 MB/s 490.1 MB/s 🔴▼ -0.08% 1.22%
unidirectional/65536 epoll bytes_per_sec 2.68 GB/s 2.65 GB/s 🔴▼ -1.43% 5.63%
unidirectional/65536 uring bytes_per_sec 2.77 GB/s 2.71 GB/s 🔴▼ -1.58% 3.16%
unidirectional_lockless/1024 epoll bytes_per_sec 125.6 MB/s 125.7 MB/s 🟢▲ +0.02% 0.18%
unidirectional_lockless/1024 uring bytes_per_sec 139.6 MB/s 138.8 MB/s 🔴▼ -0.30% 1.16%
unidirectional_lockless/1048576 epoll bytes_per_sec 3.32 GB/s 3.29 GB/s 🔴▼ -1.68% 2.12%
unidirectional_lockless/1048576 uring bytes_per_sec 3.36 GB/s 3.36 GB/s 🔴▼ -0.31% 0.74%
unidirectional_lockless/16384 epoll bytes_per_sec 1.53 GB/s 1.56 GB/s 🟢▲ +2.84% 1.10%
unidirectional_lockless/16384 uring bytes_per_sec 1.60 GB/s 1.59 GB/s 🔴▼ -0.33% 1.95%
unidirectional_lockless/262144 epoll bytes_per_sec 3.34 GB/s 3.33 GB/s 🟢▲ +0.43% 1.05%
unidirectional_lockless/262144 uring bytes_per_sec 3.20 GB/s 3.22 GB/s 🔴▼ -0.11% 1.19%
unidirectional_lockless/4096 epoll bytes_per_sec 469.5 MB/s 473.5 MB/s 🟢▲ +0.82% 0.42%
unidirectional_lockless/4096 uring bytes_per_sec 488.7 MB/s 487.1 MB/s 🟢▲ +0.16% 0.97%
unidirectional_lockless/65536 epoll bytes_per_sec 2.77 GB/s 2.73 GB/s 🔴▼ -0.68% 2.84%
unidirectional_lockless/65536 uring bytes_per_sec 2.71 GB/s 2.71 GB/s 🟢▲ +0.35% 0.84%
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.57K ops/s 1.57K ops/s ⚪ 0.00% 0.43%
burst/100 iocp ops_per_sec 156.5 ops/s 157.0 ops/s 🔴▼ -0.45% 1.02%
burst_lockless/10 iocp ops_per_sec 1.57K ops/s 1.57K ops/s 🔴▼ -0.14% 0.38%
burst_lockless/100 iocp ops_per_sec 158.7 ops/s 159.5 ops/s 🟢▲ +0.36% 0.55%
concurrent/1 iocp ops_per_sec 12.44K ops/s 12.49K ops/s 🟢▲ +0.14% 0.33%
concurrent/16 iocp ops_per_sec 13.48K ops/s 13.50K ops/s 🟢▲ +0.01% 0.25%
concurrent/4 iocp ops_per_sec 13.14K ops/s 13.16K ops/s ⚪ 0.00% 0.32%
sequential iocp ops_per_sec 12.42K ops/s 12.43K ops/s 🟢▲ +0.19% 0.25%
sequential_lockless iocp ops_per_sec 12.48K ops/s 12.50K ops/s 🟢▲ +0.24% 0.34%

fan_out

Benchmark Backend Metric Base Head Δ Noise
concurrent_parents/1 iocp ops_per_sec 7.24K ops/s 7.30K ops/s 🟢▲ +0.77% 0.32%
concurrent_parents/16 iocp ops_per_sec 6.17K ops/s 6.20K ops/s 🟢▲ +1.06% 1.98%
concurrent_parents/4 iocp ops_per_sec 6.82K ops/s 6.87K ops/s 🟢▲ +0.60% 0.73%
concurrent_parents_lockless/1 iocp ops_per_sec 7.23K ops/s 7.29K ops/s 🟢▲ +0.94% 0.34%
concurrent_parents_lockless/16 iocp ops_per_sec 6.31K ops/s 6.35K ops/s 🟢▲ +0.42% 1.78%
concurrent_parents_lockless/4 iocp ops_per_sec 6.85K ops/s 6.90K ops/s 🟢▲ +0.81% 0.62%
fork_join/1 iocp ops_per_sec 110.6K ops/s 111.3K ops/s 🟢▲ +1.03% 1.07%
fork_join/16 iocp ops_per_sec 7.24K ops/s 7.30K ops/s 🟢▲ +0.83% 0.46%
fork_join/4 iocp ops_per_sec 28.80K ops/s 29.08K ops/s 🟢▲ +0.99% 0.47%
fork_join/64 iocp ops_per_sec 1.71K ops/s 1.72K ops/s 🟢▲ +0.14% 1.23%
fork_join_lockless/1 iocp ops_per_sec 110.7K ops/s 111.6K ops/s 🟢▲ +0.38% 0.38%
fork_join_lockless/16 iocp ops_per_sec 7.25K ops/s 7.29K ops/s 🟢▲ +0.81% 0.26%
fork_join_lockless/4 iocp ops_per_sec 28.73K ops/s 29.05K ops/s 🟢▲ +1.28% 0.42%
fork_join_lockless/64 iocp ops_per_sec 1.71K ops/s 1.72K ops/s 🟢▲ +0.40% 1.47%
nested/16 iocp ops_per_sec 1.66K ops/s 1.68K ops/s 🟢▲ +0.32% 1.51%
nested/4 iocp ops_per_sec 7.07K ops/s 7.10K ops/s 🟢▲ +0.43% 0.24%
nested_lockless/16 iocp ops_per_sec 1.67K ops/s 1.68K ops/s 🟢▲ +0.49% 0.82%
nested_lockless/4 iocp ops_per_sec 7.07K ops/s 7.11K ops/s 🟢▲ +0.70% 0.21%

http_server

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 iocp ops_per_sec 109.9K ops/s 111.1K ops/s 🟢▲ +1.13% 0.13%
concurrent/16 iocp ops_per_sec 107.5K ops/s 108.1K ops/s 🟢▲ +0.32% 0.34%
concurrent/32 iocp ops_per_sec 106.4K ops/s 107.6K ops/s 🟢▲ +1.06% 0.69%
concurrent/4 iocp ops_per_sec 107.9K ops/s 108.8K ops/s 🟢▲ +0.98% 0.34%
multithread/1 iocp ops_per_sec 106.5K ops/s 107.5K ops/s 🟢▲ +0.75% 0.85%
multithread/16 iocp ops_per_sec 267.3K ops/s 267.8K ops/s 🟢▲ +0.04% 0.62%
multithread/2 iocp ops_per_sec 180.8K ops/s 182.3K ops/s 🟢▲ +0.69% 0.57%
multithread/4 iocp ops_per_sec 226.3K ops/s 225.8K ops/s 🔴▼ -0.30% 0.62%
multithread/8 iocp ops_per_sec 267.0K ops/s 266.8K ops/s 🔴▼ -0.08% 0.51%
single_conn iocp ops_per_sec 109.9K ops/s 110.5K ops/s 🟢▲ +0.31% 0.53%
single_conn_lockless iocp ops_per_sec 110.0K ops/s 111.1K ops/s 🟢▲ +1.02% 0.50%

socket_latency

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 iocp latency_mean_ns 7.73 µs 7.64 µs 🟢▲ +0.83% 0.43%
concurrent/16 iocp latency_mean_ns 133.58 µs 126.31 µs 🟢▲ +5.82% 3.18%
concurrent/4 iocp latency_mean_ns 30.81 µs 30.70 µs 🟢▲ +0.31% 0.22%
concurrent_lockless/1 iocp latency_mean_ns 7.71 µs 7.66 µs 🟢▲ +0.65% 0.35%
concurrent_lockless/16 iocp latency_mean_ns 123.99 µs 122.51 µs 🟢▲ +0.89% 1.46%
concurrent_lockless/4 iocp latency_mean_ns 30.91 µs 30.62 µs 🟢▲ +0.89% 0.51%
pingpong/1 iocp latency_mean_ns 7.71 µs 7.63 µs 🟢▲ +0.69% 0.40%
pingpong/1024 iocp latency_mean_ns 7.83 µs 7.75 µs 🟢▲ +0.81% 0.44%
pingpong/64 iocp latency_mean_ns 7.71 µs 7.64 µs 🟢▲ +0.85% 0.33%
pingpong_lockless/1 iocp latency_mean_ns 7.69 µs 7.62 µs 🟢▲ +0.96% 0.43%
pingpong_lockless/1024 iocp latency_mean_ns 7.85 µs 7.77 µs 🟢▲ +1.08% 0.48%
pingpong_lockless/64 iocp latency_mean_ns 7.73 µs 7.66 µs 🟢▲ +0.74% 0.53%

socket_throughput

Benchmark Backend Metric Base Head Δ Noise
bidirectional/1024 iocp bytes_per_sec 279.2 MB/s 278.3 MB/s 🔴▼ -0.44% 0.63%
bidirectional/1048576 iocp bytes_per_sec 5.32 GB/s 5.45 GB/s 🟢▲ +2.09% 11.76%
bidirectional/16384 iocp bytes_per_sec 3.74 GB/s 3.72 GB/s 🔴▼ -0.34% 1.08%
bidirectional/262144 iocp bytes_per_sec 9.63 GB/s 9.52 GB/s 🟢▲ +0.26% 2.04%
bidirectional/4096 iocp bytes_per_sec 1.07 GB/s 1.07 GB/s 🟢▲ +0.07% 0.67%
bidirectional/65536 iocp bytes_per_sec 9.11 GB/s 8.95 GB/s 🔴▼ -0.95% 3.65%
bidirectional_lockless/1024 iocp bytes_per_sec 279.0 MB/s 279.2 MB/s 🔴▼ -0.05% 0.50%
bidirectional_lockless/1048576 iocp bytes_per_sec 5.68 GB/s 5.80 GB/s 🟢▲ +3.56% 11.43%
bidirectional_lockless/16384 iocp bytes_per_sec 3.72 GB/s 3.73 GB/s 🟢▲ +0.40% 0.65%
bidirectional_lockless/262144 iocp bytes_per_sec 9.66 GB/s 9.72 GB/s 🟢▲ +1.13% 1.81%
bidirectional_lockless/4096 iocp bytes_per_sec 1.07 GB/s 1.08 GB/s 🟢▲ +0.30% 0.49%
bidirectional_lockless/65536 iocp bytes_per_sec 9.05 GB/s 9.01 GB/s 🔴▼ -0.75% 1.42%
multithread/2 iocp bytes_per_sec 12.84 GB/s 12.86 GB/s 🟢▲ +0.28% 0.66%
multithread/4 iocp bytes_per_sec 17.10 GB/s 17.21 GB/s 🟢▲ +0.55% 0.85%
multithread/8 iocp bytes_per_sec 18.29 GB/s 18.36 GB/s 🟢▲ +0.64% 1.03%
unidirectional/1024 iocp bytes_per_sec 281.9 MB/s 283.8 MB/s 🟢▲ +0.71% 0.44%
unidirectional/1048576 iocp bytes_per_sec 4.43 GB/s 4.57 GB/s 🟢▲ +5.29% 4.25%
unidirectional/16384 iocp bytes_per_sec 3.77 GB/s 3.80 GB/s 🟢▲ +0.16% 0.86%
unidirectional/262144 iocp bytes_per_sec 8.77 GB/s 8.89 GB/s 🟢▲ +0.08% 4.54%
unidirectional/4096 iocp bytes_per_sec 1.08 GB/s 1.09 GB/s 🟢▲ +0.40% 0.46%
unidirectional/65536 iocp bytes_per_sec 9.28 GB/s 9.25 GB/s 🔴▼ -0.28% 2.11%
unidirectional_lockless/1024 iocp bytes_per_sec 281.9 MB/s 283.7 MB/s 🟢▲ +0.77% 0.55%
unidirectional_lockless/1048576 iocp bytes_per_sec 5.09 GB/s 5.04 GB/s 🟢▲ +0.65% 6.67%
unidirectional_lockless/16384 iocp bytes_per_sec 3.78 GB/s 3.69 GB/s 🔴▼ -0.76% 5.24%
unidirectional_lockless/262144 iocp bytes_per_sec 9.80 GB/s 9.85 GB/s 🟢▲ +0.98% 0.76%
unidirectional_lockless/4096 iocp bytes_per_sec 1.08 GB/s 1.09 GB/s 🟢▲ +0.93% 0.42%
unidirectional_lockless/65536 iocp bytes_per_sec 9.34 GB/s 8.79 GB/s 🔴▼ -3.13% 12.17%
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.31K ops/s 4.32K ops/s 🟢▲ +0.02% 1.14%
burst/100 kqueue ops_per_sec 446.0 ops/s 444.8 ops/s 🔴▼ -0.04% 1.20%
burst_lockless/10 kqueue ops_per_sec 4.37K ops/s 4.38K ops/s 🟢▲ +0.29% 0.29%
burst_lockless/100 kqueue ops_per_sec 447.3 ops/s 449.0 ops/s 🟢▲ +0.49% 0.69%
concurrent/1 kqueue ops_per_sec 20.11K ops/s 20.09K ops/s 🔴▼ -0.47% 0.96%
concurrent/16 kqueue ops_per_sec 36.14K ops/s 36.16K ops/s 🟢▲ +0.32% 0.63%
concurrent/4 kqueue ops_per_sec 29.22K ops/s 29.24K ops/s 🟢▲ +0.17% 0.85%
sequential kqueue ops_per_sec 20.46K ops/s 20.35K ops/s 🔴▼ -1.05% 0.76%
sequential_lockless kqueue ops_per_sec 20.14K ops/s 20.28K ops/s 🟢▲ +0.57% 1.13%

fan_out

Benchmark Backend Metric Base Head Δ Noise
concurrent_parents/1 kqueue ops_per_sec 8.04K ops/s 8.03K ops/s 🔴▼ -0.21% 0.66%
concurrent_parents/16 kqueue ops_per_sec 8.09K ops/s 8.54K ops/s 🔴▼ -0.04% 12.83%
concurrent_parents/4 kqueue ops_per_sec 8.17K ops/s 8.12K ops/s 🔴▼ -0.02% 1.23%
concurrent_parents_lockless/1 kqueue ops_per_sec 8.08K ops/s 8.10K ops/s 🟢▲ +0.37% 0.46%
concurrent_parents_lockless/16 kqueue ops_per_sec 8.11K ops/s 8.24K ops/s 🟢▲ +0.38% 14.55%
concurrent_parents_lockless/4 kqueue ops_per_sec 8.24K ops/s 8.20K ops/s 🔴▼ -0.06% 1.16%
fork_join/1 kqueue ops_per_sec 49.07K ops/s 49.14K ops/s 🟢▲ +0.06% 0.52%
fork_join/16 kqueue ops_per_sec 8.02K ops/s 8.04K ops/s 🟢▲ +0.28% 0.89%
fork_join/4 kqueue ops_per_sec 23.64K ops/s 23.67K ops/s 🟢▲ +0.26% 0.75%
fork_join/64 kqueue ops_per_sec 2.04K ops/s 2.03K ops/s 🟢▲ +0.06% 1.79%
fork_join_lockless/1 kqueue ops_per_sec 50.27K ops/s 50.24K ops/s 🔴▼ -0.16% 0.27%
fork_join_lockless/16 kqueue ops_per_sec 8.08K ops/s 8.11K ops/s 🟢▲ +0.44% 0.51%
fork_join_lockless/4 kqueue ops_per_sec 23.73K ops/s 23.69K ops/s 🔴▼ -0.46% 0.83%
fork_join_lockless/64 kqueue ops_per_sec 2.05K ops/s 2.05K ops/s 🔴▼ -0.11% 1.80%
nested/16 kqueue ops_per_sec 2.01K ops/s 2.00K ops/s 🟢▲ +0.05% 1.65%
nested/4 kqueue ops_per_sec 7.95K ops/s 7.95K ops/s 🔴▼ -0.16% 0.96%
nested_lockless/16 kqueue ops_per_sec 2.03K ops/s 2.01K ops/s 🔴▼ -0.09% 1.67%
nested_lockless/4 kqueue ops_per_sec 8.02K ops/s 8.02K ops/s 🟢▲ +0.03% 0.69%

http_server

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 kqueue ops_per_sec 49.54K ops/s 49.44K ops/s 🔴▼ -0.15% 0.36%
concurrent/16 kqueue ops_per_sec 130.1K ops/s 130.3K ops/s 🟢▲ +0.14% 0.36%
concurrent/32 kqueue ops_per_sec 128.6K ops/s 129.3K ops/s 🟢▲ +0.15% 1.11%
concurrent/4 kqueue ops_per_sec 89.52K ops/s 89.87K ops/s 🟢▲ +0.51% 0.87%
multithread/1 kqueue ops_per_sec 128.8K ops/s 129.5K ops/s 🟢▲ +0.34% 1.01%
multithread/16 kqueue ops_per_sec 132.9K ops/s 132.6K ops/s 🔴▼ -0.42% 0.35%
multithread/2 kqueue ops_per_sec 184.8K ops/s 184.0K ops/s 🔴▼ -0.51% 1.04%
multithread/4 kqueue ops_per_sec 161.4K ops/s 162.6K ops/s 🟢▲ +1.05% 1.10%
multithread/8 kqueue ops_per_sec 136.7K ops/s 138.2K ops/s 🟢▲ +1.75% 1.05%
single_conn kqueue ops_per_sec 49.52K ops/s 49.46K ops/s 🔴▼ -0.21% 0.43%
single_conn_lockless kqueue ops_per_sec 49.89K ops/s 49.89K ops/s 🟢▲ +0.02% 0.35%

local_socket_latency

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 kqueue latency_mean_ns 1.84 µs 1.84 µs 🟢▲ +0.29% 0.66%
concurrent/16 kqueue latency_mean_ns 27.36 µs 27.37 µs 🟢▲ +0.07% 0.38%
concurrent/4 kqueue latency_mean_ns 6.87 µs 6.87 µs 🔴▼ -0.05% 0.58%
concurrent_lockless/1 kqueue latency_mean_ns 1.83 µs 1.83 µs ⚪ 0.00% 0.67%
concurrent_lockless/16 kqueue latency_mean_ns 27.19 µs 27.19 µs 🟢▲ +0.30% 0.54%
concurrent_lockless/4 kqueue latency_mean_ns 6.81 µs 6.84 µs 🔴▼ -0.20% 0.60%
pingpong/1 kqueue latency_mean_ns 1.84 µs 1.83 µs 🟢▲ +0.42% 0.85%
pingpong/1024 kqueue latency_mean_ns 1.94 µs 1.94 µs 🟢▲ +0.38% 0.69%
pingpong/64 kqueue latency_mean_ns 1.84 µs 1.84 µs 🟢▲ +0.24% 0.53%
pingpong_lockless/1 kqueue latency_mean_ns 1.82 µs 1.82 µs 🟢▲ +0.24% 0.61%
pingpong_lockless/1024 kqueue latency_mean_ns 1.92 µs 1.91 µs 🟢▲ +0.16% 0.52%
pingpong_lockless/64 kqueue latency_mean_ns 1.83 µs 1.82 µs 🟢▲ +0.87% 0.91%

local_socket_throughput

Benchmark Backend Metric Base Head Δ Noise
bidirectional/1024 kqueue bytes_per_sec 1.30 GB/s 1.30 GB/s 🔴▼ -0.20% 0.49%
bidirectional/1048576 kqueue bytes_per_sec 3.87 GB/s 3.87 GB/s 🔴▼ -0.11% 0.39%
bidirectional/16384 kqueue bytes_per_sec 3.87 GB/s 3.88 GB/s 🟢▲ +0.79% 0.92%
bidirectional/262144 kqueue bytes_per_sec 3.87 GB/s 3.87 GB/s 🔴▼ -0.08% 0.63%
bidirectional/4096 kqueue bytes_per_sec 2.91 GB/s 2.92 GB/s 🟢▲ +0.20% 0.90%
bidirectional/65536 kqueue bytes_per_sec 3.88 GB/s 3.86 GB/s 🔴▼ -0.48% 0.49%
bidirectional_lockless/1024 kqueue bytes_per_sec 1.31 GB/s 1.30 GB/s 🔴▼ -0.65% 0.88%
bidirectional_lockless/1048576 kqueue bytes_per_sec 3.96 GB/s 3.97 GB/s 🟢▲ +0.36% 0.69%
bidirectional_lockless/16384 kqueue bytes_per_sec 3.93 GB/s 3.96 GB/s 🟢▲ +1.12% 1.05%
bidirectional_lockless/262144 kqueue bytes_per_sec 3.95 GB/s 3.95 GB/s 🔴▼ -0.36% 0.68%
bidirectional_lockless/4096 kqueue bytes_per_sec 2.96 GB/s 2.97 GB/s 🟢▲ +0.23% 0.58%
bidirectional_lockless/65536 kqueue bytes_per_sec 3.95 GB/s 3.97 GB/s 🟢▲ +0.34% 0.69%
unidirectional/1024 kqueue bytes_per_sec 1.28 GB/s 1.28 GB/s 🟢▲ +0.72% 0.43%
unidirectional/1048576 kqueue bytes_per_sec 3.52 GB/s 3.52 GB/s 🔴▼ -0.06% 0.71%
unidirectional/16384 kqueue bytes_per_sec 3.53 GB/s 3.53 GB/s 🟢▲ +0.02% 0.26%
unidirectional/262144 kqueue bytes_per_sec 3.52 GB/s 3.52 GB/s 🔴▼ -0.39% 0.49%
unidirectional/4096 kqueue bytes_per_sec 2.71 GB/s 2.71 GB/s 🔴▼ -0.16% 0.28%
unidirectional/65536 kqueue bytes_per_sec 3.52 GB/s 3.52 GB/s 🔴▼ -0.36% 0.57%
unidirectional_lockless/1024 kqueue bytes_per_sec 1.28 GB/s 1.28 GB/s 🟢▲ +0.20% 0.59%
unidirectional_lockless/1048576 kqueue bytes_per_sec 3.58 GB/s 3.59 GB/s 🟢▲ +0.32% 0.33%
unidirectional_lockless/16384 kqueue bytes_per_sec 3.60 GB/s 3.59 GB/s 🟢▲ +0.09% 0.44%
unidirectional_lockless/262144 kqueue bytes_per_sec 3.59 GB/s 3.60 GB/s 🟢▲ +0.27% 0.37%
unidirectional_lockless/4096 kqueue bytes_per_sec 2.75 GB/s 2.76 GB/s 🟢▲ +0.05% 0.90%
unidirectional_lockless/65536 kqueue bytes_per_sec 3.59 GB/s 3.59 GB/s ⚪ 0.00% 0.34%

socket_latency

Benchmark Backend Metric Base Head Δ Noise
concurrent/1 kqueue latency_mean_ns 18.75 µs 18.86 µs 🔴▼ -0.57% 0.68%
concurrent/16 kqueue latency_mean_ns 119.95 µs 120.53 µs 🔴▼ -0.30% 0.49%
concurrent/4 kqueue latency_mean_ns 42.86 µs 43.54 µs 🔴▼ -1.47% 1.13%
concurrent_lockless/1 kqueue latency_mean_ns 18.74 µs 18.75 µs 🔴▼ -0.13% 0.29%
concurrent_lockless/16 kqueue latency_mean_ns 119.54 µs 120.36 µs 🔴▼ -0.03% 1.00%
concurrent_lockless/4 kqueue latency_mean_ns 42.49 µs 42.64 µs 🔴▼ -0.51% 0.64%
pingpong/1 kqueue latency_mean_ns 15.43 µs 15.52 µs 🔴▼ -0.14% 1.02%
pingpong/1024 kqueue latency_mean_ns 19.08 µs 19.08 µs 🔴▼ -0.13% 0.58%
pingpong/64 kqueue latency_mean_ns 18.78 µs 18.86 µs 🔴▼ -0.60% 0.38%
pingpong_lockless/1 kqueue latency_mean_ns 15.37 µs 15.39 µs 🔴▼ -0.05% 0.14%
pingpong_lockless/1024 kqueue latency_mean_ns 19.03 µs 19.06 µs 🔴▼ -0.16% 0.15%
pingpong_lockless/64 kqueue latency_mean_ns 18.71 µs 18.77 µs 🔴▼ -0.15% 0.59%

socket_throughput

Benchmark Backend Metric Base Head Δ Noise
bidirectional/1024 kqueue bytes_per_sec 475.5 MB/s 474.1 MB/s 🔴▼ -0.21% 0.76%
bidirectional/1048576 kqueue bytes_per_sec 7.85 GB/s 7.65 GB/s 🔴▼ -1.65% 4.65%
bidirectional/16384 kqueue bytes_per_sec 4.54 GB/s 4.50 GB/s 🔴▼ -0.92% 1.15%
bidirectional/262144 kqueue bytes_per_sec 8.85 GB/s 8.74 GB/s 🔴▼ -0.34% 3.47%
bidirectional/4096 kqueue bytes_per_sec 1.82 GB/s 1.81 GB/s 🔴▼ -0.63% 0.89%
bidirectional/65536 kqueue bytes_per_sec 7.59 GB/s 7.53 GB/s 🔴▼ -1.03% 1.14%
bidirectional_lockless/1024 kqueue bytes_per_sec 474.3 MB/s 476.2 MB/s 🟢▲ +0.13% 1.71%
bidirectional_lockless/1048576 kqueue bytes_per_sec 7.67 GB/s 7.72 GB/s 🟢▲ +1.98% 6.98%
bidirectional_lockless/16384 kqueue bytes_per_sec 4.58 GB/s 4.57 GB/s 🟢▲ +0.17% 1.00%
bidirectional_lockless/262144 kqueue bytes_per_sec 9.14 GB/s 8.77 GB/s 🔴▼ -4.49% 4.76%
bidirectional_lockless/4096 kqueue bytes_per_sec 1.82 GB/s 1.82 GB/s 🟢▲ +0.10% 1.34%
bidirectional_lockless/65536 kqueue bytes_per_sec 7.67 GB/s 7.63 GB/s 🔴▼ -0.26% 1.47%
multithread/2 kqueue bytes_per_sec 7.67 GB/s 7.50 GB/s 🟢▲ +1.55% 4.19%
multithread/4 kqueue bytes_per_sec 3.76 GB/s 3.72 GB/s 🔴▼ -0.24% 3.49%
multithread/8 kqueue bytes_per_sec 3.45 GB/s 3.27 GB/s 🔴▼ -3.10% 9.26%
unidirectional/1024 kqueue bytes_per_sec 459.6 MB/s 461.0 MB/s 🟢▲ +1.19% 2.73%
unidirectional/1048576 kqueue bytes_per_sec 9.04 GB/s 8.73 GB/s 🔴▼ -1.59% 6.21%
unidirectional/16384 kqueue bytes_per_sec 4.47 GB/s 4.41 GB/s 🟢▲ +0.05% 2.62%
unidirectional/262144 kqueue bytes_per_sec 8.80 GB/s 9.00 GB/s 🟢▲ +2.50% 2.02%
unidirectional/4096 kqueue bytes_per_sec 1.81 GB/s 1.80 GB/s 🟢▲ +0.61% 2.18%
unidirectional/65536 kqueue bytes_per_sec 7.35 GB/s 7.38 GB/s 🔴▼ -0.47% 2.26%
unidirectional_lockless/1024 kqueue bytes_per_sec 481.0 MB/s 478.2 MB/s 🟢▲ +0.18% 2.39%
unidirectional_lockless/1048576 kqueue bytes_per_sec 9.08 GB/s 8.83 GB/s 🔴▼ -0.15% 5.55%
unidirectional_lockless/16384 kqueue bytes_per_sec 4.54 GB/s 4.52 GB/s 🟢▲ +0.65% 2.22%
unidirectional_lockless/262144 kqueue bytes_per_sec 8.86 GB/s 8.98 GB/s 🟢▲ +3.10% 1.94%
unidirectional_lockless/4096 kqueue bytes_per_sec 1.82 GB/s 1.81 GB/s 🔴▼ -0.52% 1.25%
unidirectional_lockless/65536 kqueue bytes_per_sec 7.45 GB/s 7.37 GB/s 🔴▼ -0.71% 2.80%

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

tcp_server::bind built each port through the throwing tcp_acceptor
convenience constructor and caught the exception to return its code.
Both now share one exception-free helper that opens, configures address
reuse, binds, and listens, so bind returns the failing step's code
directly and the constructor throws it. On Windows both still claim the
port exclusively, so a second listener fails with address_in_use on
every platform.
A loopback pair that cannot be built is a runtime outcome like any other, so make_socket_pair and make_mocket_pair now return it, closing the sockets they carry back.
Out-of-range max_events_per_poll and inline_budget_max now fail io_context construction with std::invalid_argument, like thread_pool_size, instead of std::out_of_range from deep inside the reactor. The check runs whichever backend the context uses, so an io_uring context now rejects out-of-range values too. Where epoll is available, max_events_per_poll is also capped at INT_MAX / sizeof(epoll_event), the most one epoll wait accepts, so a larger value fails construction instead of every run().
On the 5.15 and 6.1 kernel lines a ring wait can return EBUSY when the completion queue is full and the kernel cannot flush overflowed completions into it. Reaping makes room, so the scheduler drains the queue and waits again rather than throwing out of run().
The rulebook and guide now say what the code does: runtime failures and closed objects report through the return value, and constructors throw only for root setup, contract violations, and the convenience constructors that compose code-returning calls. run(), poll() and their siblings document the run-loop throw, a demultiplexer the context cannot continue past.
connect_pair is noexcept, but on Windows it built its rendezvous with
calls that throw: the throwing temp_directory_path, random_device,
path and string allocation, and the std::thread that runs the
connecting side. Any of those failing escaped the noexcept and
terminated the process. A random_device failure now falls back to a
seed from the clock, process and thread IDs. The other failures come
back as error codes, with the listener and temporary directory
released, and a refused worker thread returns before the accept loop
could wait on a connection that will never arrive.
The native acceptors' value-returning accept() threw logic_error on a moved-from acceptor, because its awaitable built the peer socket up front from the acceptor's context. The peer is now built only on success, as the virtual-dispatch acceptors already do, so a moved-from acceptor completes with bad_file_descriptor like a closed one and the initiator never throws. The native awaitables also close a peer accepted for an awaiter destroyed before it resumes, which they previously left open. The native acceptor's closed and moved-from accept tests no longer depend on SO_REUSEPORT, so they now run on every platform.
The test and snippet sources silenced unused values with (void) casts. Following rulebook section 6, unused names are now declared [[maybe_unused]], and std::ignore is kept for values deliberately discarded, such as the inotify event a doc snippet reads outside its published region.
When the last handler's completion ran a Windows context out of work, work_finished() stopped it from inside noexcept, so a failed shutdown post called std::terminate. When the thread that ran out of work is running the context, the failure is now recorded, and that thread's run or poll call (run, run_one, run_for, run_until, poll, poll_one) retries the wakeup on its way out and throws std::system_error, the run loop's documented channel, only if the retry fails too. On any other thread, such as one releasing a work guard, nothing would retry the wakeup and threads blocked without a timeout would never wake, so that case still terminates. A failed post no longer leaves the context marking a wakeup as queued, so a later stop() retries it instead of returning silently while blocked threads stay asleep, and a failed post that leaves a zero last error is still reported as a failure. A direct stop() still throws, and also records the failure, so a run call on the stopped context retries the wakeup instead of blocking while work remains. restart() clears a recorded failure.
Fourteen headers included detail/except.hpp without calling any of its throw helpers. win_wait_reactor.hpp, which does throw and only reached the header through win_scheduler.hpp, now includes it directly, and the two IOCP acceptor services include <system_error> themselves instead of through it.
…onstructors

A native type is a drop-in replacement for its base, but the native acceptors lacked the open, bind, and listen constructors and the native signal set lacked the executor forms, so switching a declaration to the native type stopped compiling. The acceptors gain protected base constructors that adopt the native service's handle before opening, so the result stays native and throws the same codes as the base constructor.
@mvandeberg
mvandeberg merged commit 70adbd5 into cppalliance:develop Oct 27, 2026
48 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Beast2 Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Audit synchronous APIs: report runtime failures through capy::results instead of throwing

3 participants