diff --git a/frameworks/zix-ws/.gitignore b/frameworks/zix-ws/.gitignore new file mode 100644 index 000000000..595d20d1a --- /dev/null +++ b/frameworks/zix-ws/.gitignore @@ -0,0 +1,4 @@ +.zig-cache +zig-out +zig-package +vendor diff --git a/frameworks/zix-ws/Dockerfile b/frameworks/zix-ws/Dockerfile index 13da3e499..b5c27bebd 100644 --- a/frameworks/zix-ws/Dockerfile +++ b/frameworks/zix-ws/Dockerfile @@ -5,7 +5,7 @@ ARG RETRY=6 ARG TARGETARCH ARG RETRY_DELAY=3 ARG ZIG_VERSION=0.16.0 -ARG ZIX_VERSION=0.4.x-rc3 +ARG ZIX_VERSION=0.5.x-rc1 RUN apk add --no-cache ca-certificates curl git tar xz RUN set -eu; \ @@ -19,15 +19,8 @@ RUN set -eu; \ mv "/opt/zig-${ZIG_ARCH}-linux-${ZIG_VERSION}" /opt/zig ENV PATH="/opt/zig:${PATH}" -# Vendor zix X.Y.Z, separate layer so source-only rebuilds skip the fetch. -# The Http1 raw engine work this image needs (large-body drain plus the per-worker -# response cache used by the /json endpoint) must be present on the X.Y.Z branch. -# Four ordered attempts before giving up: curl the archive tarball from github then -# codeberg, then a shallow git clone from github then codeberg. The github archive -# redirects to codeload.github.com (which the benchmark runner may not resolve), so -# curl can fall through to the codeberg tarball, and git clone talks to github.com -# and codeberg.org directly as the deeper fallback. RETRY and RETRY_DELAY bound -# every attempt. +# Vendor zix ${ZIX_VERSION} in its own layer so source-only rebuilds skip the fetch. Tries curl +# tarball then git clone, github before codeberg. RETRY / RETRY_DELAY bound every attempt. RUN set -eu; \ fetch() { \ rm -rf /src/vendor/zix; mkdir -p /src/vendor/zix; \ @@ -61,7 +54,7 @@ RUN set -eu; \ amd64) ZIG_TARGET=x86_64-linux-musl; ZIG_CPU=x86_64_v3 ;; \ arm64) ZIG_TARGET=aarch64-linux-musl; ZIG_CPU=baseline ;; \ esac; \ - zig build -Dtarget="${ZIG_TARGET}" -Dcpu="${ZIG_CPU}" --release=fast + zig build -Dtarget="${ZIG_TARGET}" -Dcpu="${ZIG_CPU}+aes+pclmul+adx" --release=fast FROM alpine:3.20 COPY --from=build /src/zig-out/bin/zix-ws /zix-ws diff --git a/frameworks/zix-ws/meta.json b/frameworks/zix-ws/meta.json index aa33e4c45..e3380b649 100644 --- a/frameworks/zix-ws/meta.json +++ b/frameworks/zix-ws/meta.json @@ -2,9 +2,9 @@ "display_name": "zix-ws", "language": "Zig", "type": "engine", - "engine": "zix", - "description": "Zig WebSocket echo server on the zix.Http1 raw engine (no std.http). Shared-nothing by design: each worker owns its own SO_REUSEPORT multishot accept, io_uring completion ring, and connections, with no shared state or locking across cores. The upgrade and echo are engine-owned: frames are read from a shared per-worker provided-buffer ring (an idle connection holds no buffer), and a pipelined burst is coalesced into one write.", - "repo": "https://codeberg.org/prothegee/zix", + "engine": "zix uring", + "description": "Zig WebSocket echo server on the zix.Http1 raw engine (no std.http). Shared-nothing: each worker owns its SO_REUSEPORT accept, io_uring loop, and connections. The upgrade and echo are engine-owned: frames are read from a per-worker buffer ring (an idle connection holds no buffer), and a pipelined burst is coalesced into one write.", + "repo": "https://github.com/prothegee/zix", "enabled": true, "tests": [ "echo-ws", diff --git a/frameworks/zix-ws/src/main.zig b/frameworks/zix-ws/src/main.zig index 05adac321..a25aaf34c 100644 --- a/frameworks/zix-ws/src/main.zig +++ b/frameworks/zix-ws/src/main.zig @@ -1,16 +1,9 @@ //! HttpArena: zix-ws //! -//! zix HttpArena WebSocket entry point. -//! -//! Intent: demonstrate the engine-owned WebSocket path of zix.Http1 (EPOLL -//! dispatch model) against the HttpArena echo and echo-pipeline suites. -//! -//! Design choices: -//! - GET /ws upgrades, then zix.Http1.WebSocket.serve drives the echo loop -//! inside the engine: frames are echoed on readiness and a pipelined burst is -//! coalesced into a single write. -//! - No response cache: echo is per-connection, not a broadcast fanout, so there -//! is nothing to precompute or share across connections. +//! zix.Http1 engine-owned WebSocket (.URING) against the HttpArena echo and echo-pipeline suites. +//! GET /ws upgrades, then WebSocket.serve drives the echo loop inside the engine (frames echoed on +//! readiness, a pipelined burst coalesced into one write). No response cache: echo is per-connection, +//! nothing to precompute or share. const std = @import("std"); const zix = @import("zix"); @@ -22,12 +15,12 @@ const LISTEN_IP: []const u8 = "::"; const DISPATCH_MODEL: zix.Http1.DispatchModel = .URING; const KERNEL_BACKLOG: u31 = 16 * 1024; -/// Per-machine tuning profile (ADR-041 increment 5): .lean for the 12-thread / -/// 32 GB dev box, .throughput for the 64-core / 251 GB competition box. Only the -/// HTTP handshake recv buffer differs (the WS frame buffer is already 32 KiB). -/// Select .throughput for the 64-core deployment. +/// Per-machine tuning profile (ADR-041 incr 5): .lean for the 12-thread dev box, .throughput for +/// the 64-core box. Under .URING the engine now honors ws_recv_buf (sizes conn.buf and the unmask +/// scratch, independent of max_recv_buf), so a deep pipelined echo burst accumulates in one +/// WS_RECV_BUF (32 KiB) buffer. max_recv_buf only sizes the brief HTTP handshake recv. const Profile = enum { lean, throughput }; -const PROFILE: Profile = .lean; +const PROFILE: Profile = .throughput; const MAX_RECV_BUF: usize = switch (PROFILE) { .lean => 4 * 1024,