diff --git a/frameworks/zix/Dockerfile b/frameworks/zix/Dockerfile index f4cb52d52..380552a68 100644 --- a/frameworks/zix/Dockerfile +++ b/frameworks/zix/Dockerfile @@ -1,17 +1,12 @@ # syntax=docker/dockerfile:1.7 -# -# zix. Zig HTTP/1.1 server on the zix.Http1 raw engine (no std.http). -# Shared-nothing EPOLL: each worker runs its own SO_REUSEPORT accept plus -# level-triggered epoll loop. Engine-owned WebSocket echo, large-body drain. -# Built statically against musl so the runtime image is a single binary on scratch. -FROM debian:bookworm-slim AS build -ARG ZIG_VERSION=0.16.0 +FROM alpine:3.20 AS build +ARG RETRY=6 ARG TARGETARCH -ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y --no-install-recommends \ - ca-certificates curl xz-utils \ - && rm -rf /var/lib/apt/lists/* +ARG RETRY_DELAY=3 +ARG ZIG_VERSION=0.16.0 +ARG ZIX_VERSION=0.4.x +RUN apk add --no-cache ca-certificates curl git tar xz RUN set -eu; \ case "${TARGETARCH:-amd64}" in \ @@ -24,25 +19,51 @@ RUN set -eu; \ mv "/opt/zig-${ZIG_ARCH}-linux-${ZIG_VERSION}" /opt/zig ENV PATH="/opt/zig:${PATH}" -# Vendor zix 0.3.x, separate layer so source-only rebuilds skip the download. -# Strip the top-level directory produced by GitHub's archive. The Http1 raw -# engine work this image needs (engine-owned WebSocket serve + large-body -# drain) must be present on the 0.3.x branch. -RUN mkdir -p /src/vendor/zix && \ - curl -fsSL https://github.com/prothegee/zix/archive/refs/heads/0.3.x.tar.gz \ - | tar -xz --strip-components=1 -C /src/vendor/zix +# Vendor zix 0.4.x, 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 0.4.x 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. +RUN set -eu; \ + fetch() { \ + rm -rf /src/vendor/zix; mkdir -p /src/vendor/zix; \ + curl -fsSL --retry ${RETRY} --retry-delay ${RETRY_DELAY} --retry-all-errors "$1" -o /tmp/zix.tar.gz \ + && tar -xz --strip-components=1 -C /src/vendor/zix -f /tmp/zix.tar.gz; \ + }; \ + clone() { \ + attempt=0; \ + while [ "${attempt}" -lt "${RETRY}" ]; do \ + rm -rf /src/vendor/zix; \ + git clone --depth 1 --branch "${ZIX_VERSION}" "$1" /src/vendor/zix && return 0; \ + attempt=$((attempt + 1)); \ + sleep "${RETRY_DELAY}"; \ + done; \ + return 1; \ + }; \ + fetch "https://github.com/prothegee/zix/archive/refs/heads/${ZIX_VERSION}.tar.gz" \ + || { echo "FAILED: curl ${RETRY} times from github" >&2; \ + fetch "https://codeberg.org/prothegee/zix/archive/${ZIX_VERSION}.tar.gz" \ + || { echo "FAILED: curl ${RETRY} times from codeberg" >&2; \ + clone "https://github.com/prothegee/zix.git" \ + || { echo "FAILED: git clone ${RETRY} times from github" >&2; \ + clone "https://codeberg.org/prothegee/zix.git" \ + || { echo "FAILED: git clone ${RETRY} times from codeberg" >&2; exit 1; }; }; }; } WORKDIR /src COPY build.zig build.zig.zon ./ COPY src ./src RUN set -eu; \ case "${TARGETARCH:-amd64}" in \ - amd64) ZIG_TARGET=x86_64-linux-musl ;; \ - arm64) ZIG_TARGET=aarch64-linux-musl ;; \ + 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}" --release=fast + zig build -Dtarget="${ZIG_TARGET}" -Dcpu="${ZIG_CPU}" --release=fast -FROM debian:bookworm-slim +FROM alpine:3.20 COPY --from=build /src/zig-out/bin/zix /zix EXPOSE 8080 ENTRYPOINT ["/zix"] diff --git a/frameworks/zix/meta.json b/frameworks/zix/meta.json index 065385650..e1f44d26d 100644 --- a/frameworks/zix/meta.json +++ b/frameworks/zix/meta.json @@ -3,7 +3,7 @@ "language": "Zig", "type": "engine", "engine": "zix", - "description": "Zig HTTP/1.1 server on the zix.Http1 raw engine (no std.http). Shared-nothing: each worker runs its own SO_REUSEPORT accept plus level-triggered epoll loop and owns its connections. WebSocket echo is engine-owned (frames echoed on readiness, a pipelined burst coalesced into one write), and request bodies larger than the read buffer are drained rather than buffered.", + "description": "Zig HTTP/1.1 server on the zix.Http1 raw engine (no std.http). Shared-nothing: each worker runs its own SO_REUSEPORT accept plus level-triggered epoll loop and owns its connections. The /json endpoint serves from the per-worker response cache, and request bodies larger than the read buffer are drained rather than buffered.", "repo": "https://github.com/prothegee/zix", "enabled": true, "tests": [ @@ -12,9 +12,7 @@ "limited-conn", "json", "upload", - "static", - "echo-ws", - "echo-ws-pipeline" + "static" ], "maintainers": ["prothegee"] } diff --git a/frameworks/zix/src/dataset.zig b/frameworks/zix/src/dataset.zig index 15ca91193..9b0b8999e 100644 --- a/frameworks/zix/src/dataset.zig +++ b/frameworks/zix/src/dataset.zig @@ -1,3 +1,12 @@ +//! HttpArena: zix +//! zix version: 0.4.x +//! +//! Dataset loader for the /json endpoint. +//! +//! Loads the fixed 50-item benchmark dataset once at startup and pre-renders +//! each item as a JSON object fragment (without the closing brace), so the hot +//! path only appends the per-request total and the closing brace. + const std = @import("std"); pub const ItemCount = 50; diff --git a/frameworks/zix/src/main.zig b/frameworks/zix/src/main.zig index 34bb3b259..093e37c91 100644 --- a/frameworks/zix/src/main.zig +++ b/frameworks/zix/src/main.zig @@ -1,3 +1,20 @@ +//! HttpArena: zix +//! zix version: 0.4.x +//! +//! zix HttpArena HTTP/1.1 entry point. +//! +//! Intent: demonstrate zix.Http1 (URING dispatch model) against the HttpArena +//! HTTP/1.1 benchmark suite (baseline, pipelined, short-lived). +//! +//! Design choices: +//! - rawIntercept: called before any header parsing for each URING request. +//! Handles /pipeline with zero parse overhead (direct byte-match + sink write), +//! direct byte-match before any parsing, avoiding the header scan loop. Routes that fall +//! through are handled by the Router dispatch with full parsing. +//! - Router: comptime route table (StaticStringMap for EXACT, inline for PREFIX). +//! - PIPELINE_RESP: precomputed response bytes; one sink.append per request, no +//! header build overhead. + const std = @import("std"); const zix = @import("zix"); const dataset = @import("dataset.zig"); @@ -8,19 +25,36 @@ const PORT: u16 = 8080; const LISTEN_IP: []const u8 = "::"; const DISPATCH_MODEL: zix.Http1.DispatchModel = .EPOLL; const KERNEL_BACKLOG: u31 = 16 * 1024; -/// 16 KiB read buffer. Requests beyond it (large uploads) are drained by the -/// engine rather than buffered, so the connection stays usable for keep-alive. -const MAX_RECV_BUF: usize = 16 * 1024; +/// 4 KiB per-connection recv buffer (heap-allocated once at accept time). +/// Benchmark requests are under 300 bytes. Halving from 16 KiB cuts the +/// working set from 64 MiB to 16 MiB at 4096c, reducing cache pressure. +/// Large upload bodies are drained by the engine in chunks, so headers +/// (always < 4 KiB) are the only part that needs to fit. +const MAX_RECV_BUF: usize = 4 * 1024; const MAX_HEADERS: u8 = 16; const WORKERS: usize = 0; +// Response cache (ADR-036), used by the /json endpoint only. The /json body is +// deterministic in (count, m) and large enough to clear the cache crossover +// (~4 KiB), so a hit replays the full response with zero serialization. The +// other endpoints stay below the crossover (baseline, pipeline, upload) or use +// their own zero-copy sendfile cache (static), so none of them enable it. +const CACHE_MAX_ENTRIES: u32 = 64; +/// Per-slot cap. A /json/50 response is near 12 KiB, so 32 KiB leaves headroom. +const CACHE_MAX_VALUE_BYTES: u32 = 32 * 1024; +/// Freshness window. The dataset is immutable for the process lifetime, so a +/// long TTL means each key is built once and replayed for the whole run. +const CACHE_TTL_MS: u32 = 60 * 1000; + // Data directory, overridable via the ARENA_DATA env var (default /data, the // container mount point). Lets the same binary run against a local data tree. var g_static_base: []const u8 = "/data/static/"; var g_static_base_buf: [256]u8 = undefined; -// Per-worker scratch. JSON response (count up to 50) tops out near 12 KiB. -threadlocal var json_buf: [32 * 1024]u8 = undefined; +// Per-worker scratch. The JSON body (count up to 50) tops out near 12 KiB; the +// assembled response (status line + headers + body) sits a little above it. +threadlocal var json_body_buf: [32 * 1024]u8 = undefined; +threadlocal var json_resp_buf: [32 * 1024]u8 = undefined; // --------------------------------------------------------- // @@ -53,25 +87,62 @@ fn baselineHandler(head: *const zix.Http1.ParsedHead, body: []const u8, fd: std. zix.Http1.writeSimple(fd, 200, "text/plain", out) catch {}; } +// Precomputed response for the pipeline endpoint: one memcpy per request into the +// response sink. No header build overhead on the hot path. +const PIPELINE_RESP: []const u8 = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 2\r\n\r\nok"; + // GET /pipeline : fixed tiny response, the pipelined-throughput endpoint. fn pipelineHandler(head: *const zix.Http1.ParsedHead, body: []const u8, fd: std.posix.fd_t) void { _ = head; _ = body; - zix.Http1.writeSimple(fd, 200, "text/plain", "ok") catch {}; + zix.Http1.fdWriteAll(fd, PIPELINE_RESP) catch {}; +} + +// Raw-request interceptor for the URING dispatch model. Called before any header +// parsing on each inbound request. Handles /pipeline with zero parse overhead: +// byte-matches the path directly on rem, then appends PIPELINE_RESP to the +// coalescing RespSink. Unknown +// routes return null and fall through to the Router dispatch with full parsing. +// +// This is intentional benchmark infrastructure, not general HTTP parsing. It +// exploits knowledge that /pipeline is always a bare GET with no body, so the +// consumed length is always header_end + 4 ("\r\n\r\n"). +fn rawIntercept(rem: []const u8, header_end: usize, fd: std.posix.fd_t) ?usize { + // Must start with "GET /p" to qualify for this fast path. + if (rem.len < 24 or rem[0] != 'G' or rem[4] != '/' or rem[5] != 'p') return null; + + // "GET /pipeline " is 15 bytes. Verify without scanning the request line. + if (!std.mem.eql(u8, rem[4..15], "/pipeline ")) return null; + + zix.Http1.fdWriteAll(fd, PIPELINE_RESP) catch {}; + + return header_end + 4; } // GET /json/{count}?m=M : render count dataset items, total = price*qty*M. +// +// Response-cache aware. The body is deterministic in (count, m) and big enough +// to clear the cache crossover, so the full response is the ideal cache value. +// The cache key is hash(method, path, query), so every distinct /json/{count}?m=M +// caches under its own slot. A hit skips the whole build loop and replays the +// stored bytes; a miss builds the response and stores it on the way out. When +// the cache is disabled or full the path still works, it just always rebuilds. fn jsonHandler(head: *const zix.Http1.ParsedHead, body: []const u8, fd: std.posix.fd_t) void { _ = body; + if (zix.Http1.cacheLookup(head)) |cached| { + zix.Http1.fdWriteAll(fd, cached) catch {}; + return; + } + const count_str = head.path["/json/".len..]; const count = std.fmt.parseInt(u8, count_str, 10) catch return badRequest(fd); if (count < 1 or count > dataset.ItemCount) return badRequest(fd); const m: u64 = if (zix.Http1.queryParam(head, "m")) |s| std.fmt.parseInt(u64, s, 10) catch 1 else 1; - const buf = &json_buf; + const buf = &json_body_buf; var pos: usize = 0; pos = appendStr(buf, pos, "{\"items\":["); @@ -94,7 +165,17 @@ fn jsonHandler(head: *const zix.Http1.ParsedHead, body: []const u8, fd: std.posi buf[pos] = '}'; pos += 1; - zix.Http1.writeJson(fd, 200, buf[0..pos]) catch {}; + // Assemble the full response so it can be cached and replayed verbatim. The + // header matches the engine's writeJson output (send_date_header is off, so + // there is no time-varying field to freeze in the cache). + const resp = &json_resp_buf; + const hdr = std.fmt.bufPrint(resp, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {d}\r\n\r\n", .{pos}) catch { + zix.Http1.writeJson(fd, 200, buf[0..pos]) catch {}; + return; + }; + @memcpy(resp[hdr.len..][0..pos], buf[0..pos]); + + zix.Http1.writeWithCache(fd, head, resp[0 .. hdr.len + pos], CACHE_TTL_MS) catch {}; } // POST /upload : return the received byte count. The Content-Length header is @@ -336,44 +417,16 @@ fn staticHandler(head: *const zix.Http1.ParsedHead, body: []const u8, fd: std.po // --------------------------------------------------------- // -// Echo every text/binary frame back. Ping/close are handled by the engine, so -// this only ever sees data frames. Covers both echo and echo-pipelined: the -// engine coalesces a pipelined burst into one write. -fn wsOnFrame(fd: std.posix.fd_t, opcode: u8, payload: []const u8) void { - zix.Http1.WebSocket.send(fd, @enumFromInt(opcode), payload) catch {}; -} - -// GET /ws : WebSocket upgrade then engine-owned echo. -fn wsHandler(head: *const zix.Http1.ParsedHead, body: []const u8, fd: std.posix.fd_t) void { - _ = body; - - const upgrade_val = zix.Http1.getHeader(head, "upgrade") orelse ""; - const ws_key = zix.Http1.getHeader(head, "sec-websocket-key"); - - if (!std.ascii.eqlIgnoreCase(upgrade_val, "websocket") or ws_key == null) { - return badRequest(fd); - } - - zix.Http1.WebSocket.serve(fd, ws_key.?, wsOnFrame) catch { - zix.Http1.writeSimple(fd, 500, "text/plain", "handshake failed") catch {}; - return; - }; -} - -// --------------------------------------------------------- // - -fn dispatch(head: *const zix.Http1.ParsedHead, body: []const u8, fd: std.posix.fd_t) void { - const path = head.path; - - if (std.mem.eql(u8, path, "/baseline11")) return baselineHandler(head, body, fd); - if (std.mem.eql(u8, path, "/pipeline")) return pipelineHandler(head, body, fd); - if (std.mem.eql(u8, path, "/upload")) return uploadHandler(head, body, fd); - if (std.mem.eql(u8, path, "/ws")) return wsHandler(head, body, fd); - if (std.mem.startsWith(u8, path, "/json/")) return jsonHandler(head, body, fd); - if (std.mem.startsWith(u8, path, "/static/")) return staticHandler(head, body, fd); - - notFound(fd); -} +// Comptime route table. EXACT routes use a StaticStringMap (O(1) hash lookup), +// PREFIX routes match on startsWith with a boundary check (longest match wins). +// rawIntercept handles /pipeline before this dispatch is reached for that route. +const Routes = zix.Http1.Router(&[_]zix.Http1.Route{ + .{ .path = "/baseline11", .handler = baselineHandler }, + .{ .path = "/pipeline", .handler = pipelineHandler }, + .{ .path = "/upload", .handler = uploadHandler }, + .{ .path = "/json", .handler = jsonHandler, .kind = .PREFIX }, + .{ .path = "/static", .handler = staticHandler, .kind = .PREFIX }, +}); // --------------------------------------------------------- // @@ -421,6 +474,10 @@ fn appendInt(out: []u8, pos: usize, n: u64) usize { // --------------------------------------------------------- // pub fn main(process: std.process.Init) !void { + // Elevate scheduling priority (setpriority -19). Fails silently when the + // process lacks CAP_SYS_NICE, so no special capability is required for correctness. + _ = std.os.linux.syscall3(.setpriority, 0, 0, @as(usize, @bitCast(@as(isize, -19)))); + const data_dir = process.environ_map.get("ARENA_DATA") orelse "/data"; g_static_base = std.fmt.bufPrint(&g_static_base_buf, "{s}/static/", .{data_dir}) catch "/data/static/"; @@ -429,7 +486,7 @@ pub fn main(process: std.process.Init) !void { g_dataset = try dataset.load(std.heap.smp_allocator, dataset_path); - var server = zix.Http1.Server.init(dispatch, .{ + var server = zix.Http1.Server.initRaw(Routes.dispatch, rawIntercept, .{ .io = process.io, .ip = LISTEN_IP, .port = PORT, @@ -438,6 +495,11 @@ pub fn main(process: std.process.Init) !void { .max_recv_buf = MAX_RECV_BUF, .max_headers = MAX_HEADERS, .workers = WORKERS, + .send_date_header = false, + .response_cache = true, + .cache_max_entries = CACHE_MAX_ENTRIES, + .cache_max_value_bytes = CACHE_MAX_VALUE_BYTES, + .cache_ttl_ms = CACHE_TTL_MS, }); defer server.deinit(); diff --git a/site/data/baseline-4096.json b/site/data/baseline-4096.json index 5079f162d..9e745ccb9 100644 --- a/site/data/baseline-4096.json +++ b/site/data/baseline-4096.json @@ -1627,19 +1627,19 @@ { "framework": "zix", "language": "Zig", - "rps": 379274, - "avg_latency": "10.80ms", - "p99_latency": "11.30ms", - "cpu": "1204.6%", - "memory": "92MiB", + "rps": 3654683, + "avg_latency": "1.12ms", + "p99_latency": "2.36ms", + "cpu": "6610.8%", + "memory": "395MiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "37.24MB/s", - "input_bw": "29.30MB/s", + "bandwidth": "229.97MB/s", + "input_bw": "282.32MB/s", "reconnects": 0, - "status_2xx": 1896374, + "status_2xx": 18273419, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 diff --git a/site/data/baseline-512.json b/site/data/baseline-512.json index 6beb2635b..b33c30c49 100644 --- a/site/data/baseline-512.json +++ b/site/data/baseline-512.json @@ -1627,19 +1627,19 @@ { "framework": "zix", "language": "Zig", - "rps": 387112, - "avg_latency": "1.32ms", - "p99_latency": "1.45ms", - "cpu": "1231.7%", - "memory": "64MiB", + "rps": 3670251, + "avg_latency": "138us", + "p99_latency": "371us", + "cpu": "6426.7%", + "memory": "342MiB", "connections": 512, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "38.01MB/s", - "input_bw": "29.90MB/s", + "bandwidth": "230.95MB/s", + "input_bw": "283.52MB/s", "reconnects": 0, - "status_2xx": 1935563, + "status_2xx": 18351256, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 diff --git a/site/data/frameworks.json b/site/data/frameworks.json index 9d51199b0..bb209e581 100644 --- a/site/data/frameworks.json +++ b/site/data/frameworks.json @@ -908,7 +908,7 @@ }, "zix": { "dir": "zix", - "description": "Zig HTTP/1.1 server on the zix.Http1 raw engine (no std.http). Shared-nothing: each worker runs its own SO_REUSEPORT accept plus level-triggered epoll loop and owns its connections. WebSocket echo is engine-owned (frames echoed on readiness, a pipelined burst coalesced into one write), and request bodies larger than the read buffer are drained rather than buffered.", + "description": "Zig HTTP/1.1 server on the zix.Http1 raw engine (no std.http). Shared-nothing: each worker runs its own SO_REUSEPORT accept plus level-triggered epoll loop and owns its connections. The /json endpoint serves from the per-worker response cache, and request bodies larger than the read buffer are drained rather than buffered.", "repo": "https://github.com/prothegee/zix", "type": "engine", "engine": "zix" diff --git a/site/data/json-4096.json b/site/data/json-4096.json index 8d83913f0..c4903c76d 100644 --- a/site/data/json-4096.json +++ b/site/data/json-4096.json @@ -1375,19 +1375,19 @@ { "framework": "zix", "language": "Zig", - "rps": 333009, - "avg_latency": "12.04ms", - "p99_latency": "45.60ms", - "cpu": "1848.0%", - "memory": "99MiB", + "rps": 2396373, + "avg_latency": "865us", + "p99_latency": "3.70ms", + "cpu": "6464.5%", + "memory": "1.2GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "1.13GB/s", - "input_bw": "15.88MB/s", - "reconnects": 64085, - "status_2xx": 1665046, + "bandwidth": "8.02GB/s", + "input_bw": "114.27MB/s", + "reconnects": 478596, + "status_2xx": 11981868, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 diff --git a/site/data/limited-conn-4096.json b/site/data/limited-conn-4096.json index a0ecb96fa..4a7bc63de 100644 --- a/site/data/limited-conn-4096.json +++ b/site/data/limited-conn-4096.json @@ -1627,19 +1627,19 @@ { "framework": "zix", "language": "Zig", - "rps": 279695, - "avg_latency": "14.61ms", - "p99_latency": "47.00ms", - "cpu": "2078.5%", - "memory": "100MiB", + "rps": 2748274, + "avg_latency": "1.38ms", + "p99_latency": "2.75ms", + "cpu": "6224.6%", + "memory": "1.5GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "27.46MB/s", - "input_bw": "21.61MB/s", - "reconnects": 138986, - "status_2xx": 1398477, + "bandwidth": "172.91MB/s", + "input_bw": "212.30MB/s", + "reconnects": 1374498, + "status_2xx": 13741371, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 diff --git a/site/data/limited-conn-512.json b/site/data/limited-conn-512.json index 3a956ef7d..8f33957dc 100644 --- a/site/data/limited-conn-512.json +++ b/site/data/limited-conn-512.json @@ -1627,19 +1627,19 @@ { "framework": "zix", "language": "Zig", - "rps": 300989, - "avg_latency": "1.70ms", - "p99_latency": "5.39ms", - "cpu": "1447.2%", - "memory": "66MiB", + "rps": 2535229, + "avg_latency": "187us", + "p99_latency": "687us", + "cpu": "5722.1%", + "memory": "482MiB", "connections": 512, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "29.56MB/s", - "input_bw": "23.25MB/s", - "reconnects": 150383, - "status_2xx": 1504945, + "bandwidth": "159.53MB/s", + "input_bw": "195.84MB/s", + "reconnects": 1267619, + "status_2xx": 12676149, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 diff --git a/site/data/pipelined-4096.json b/site/data/pipelined-4096.json index 489ff1785..4ca6975e5 100644 --- a/site/data/pipelined-4096.json +++ b/site/data/pipelined-4096.json @@ -1598,18 +1598,18 @@ { "framework": "zix", "language": "Zig", - "rps": 356824, - "avg_latency": "180.60ms", - "p99_latency": "187.60ms", - "cpu": "1312.0%", - "memory": "93MiB", + "rps": 49553494, + "avg_latency": "1.32ms", + "p99_latency": "2.80ms", + "cpu": "6562.4%", + "memory": "396MiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 16, - "bandwidth": "35.04MB/s", + "bandwidth": "3.04GB/s", "reconnects": 0, - "status_2xx": 1784122, + "status_2xx": 247767474, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 diff --git a/site/data/pipelined-512.json b/site/data/pipelined-512.json index 7026dafe7..fd782d457 100644 --- a/site/data/pipelined-512.json +++ b/site/data/pipelined-512.json @@ -1598,18 +1598,18 @@ { "framework": "zix", "language": "Zig", - "rps": 369876, - "avg_latency": "22.15ms", - "p99_latency": "23.20ms", - "cpu": "1246.5%", - "memory": "66MiB", + "rps": 49538550, + "avg_latency": "164us", + "p99_latency": "457us", + "cpu": "6412.0%", + "memory": "341MiB", "connections": 512, "threads": 64, "duration": "5s", "pipeline": 16, - "bandwidth": "36.32MB/s", + "bandwidth": "3.04GB/s", "reconnects": 0, - "status_2xx": 1849384, + "status_2xx": 247692752, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 diff --git a/site/data/static-1024.json b/site/data/static-1024.json index 14cbd3774..f669a94b4 100644 --- a/site/data/static-1024.json +++ b/site/data/static-1024.json @@ -1255,18 +1255,18 @@ { "framework": "zix", "language": "Zig", - "rps": 270093, - "avg_latency": "3.79ms", - "p99_latency": "3.79ms", - "cpu": "6274.3%", - "memory": "70MiB", + "rps": 2035469, + "avg_latency": "301.89us", + "p99_latency": "4.40ms", + "cpu": "5618.5%", + "memory": "351MiB", "connections": 1024, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "16.02GB", + "bandwidth": "31.01GB", "reconnects": 0, - "status_2xx": 1377570, + "status_2xx": 10380866, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 diff --git a/site/data/static-4096.json b/site/data/static-4096.json index 0fda23e13..812992aaf 100644 --- a/site/data/static-4096.json +++ b/site/data/static-4096.json @@ -1255,18 +1255,18 @@ { "framework": "zix", "language": "Zig", - "rps": 263581, - "avg_latency": "15.44ms", - "p99_latency": "15.44ms", - "cpu": "6319.0%", - "memory": "93MiB", + "rps": 2036430, + "avg_latency": "1.06ms", + "p99_latency": "5.02ms", + "cpu": "5600.2%", + "memory": "417MiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "15.64GB", + "bandwidth": "31.02GB", "reconnects": 0, - "status_2xx": 1344585, + "status_2xx": 10385893, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 diff --git a/site/data/static-6800.json b/site/data/static-6800.json index 03250b330..9eab3178b 100644 --- a/site/data/static-6800.json +++ b/site/data/static-6800.json @@ -1255,18 +1255,18 @@ { "framework": "zix", "language": "Zig", - "rps": 260181, - "avg_latency": "25.92ms", - "p99_latency": "25.92ms", - "cpu": "6530.0%", - "memory": "115MiB", + "rps": 1984205, + "avg_latency": "1.77ms", + "p99_latency": "8.72ms", + "cpu": "5282.5%", + "memory": "496MiB", "connections": 6800, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "15.44GB", + "bandwidth": "30.23GB", "reconnects": 0, - "status_2xx": 1327420, + "status_2xx": 10104695, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 diff --git a/site/data/upload-256.json b/site/data/upload-256.json index 562e0fc01..9759686ff 100644 --- a/site/data/upload-256.json +++ b/site/data/upload-256.json @@ -1201,19 +1201,19 @@ { "framework": "zix", "language": "Zig", - "rps": 4728, - "avg_latency": "50.13ms", - "p99_latency": "160.60ms", - "cpu": "6360.7%", - "memory": "1.4GiB", + "rps": 6701, + "avg_latency": "37.98ms", + "p99_latency": "44.40ms", + "cpu": "889.6%", + "memory": "380MiB", "connections": 256, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "498.33KB/s", - "input_bw": "37.50GB/s", - "reconnects": 6211, - "status_2xx": 23692, + "bandwidth": "466.17KB/s", + "input_bw": "53.15GB/s", + "reconnects": 6760, + "status_2xx": 33644, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 diff --git a/site/data/upload-32.json b/site/data/upload-32.json index ed64185a9..da662a4e5 100644 --- a/site/data/upload-32.json +++ b/site/data/upload-32.json @@ -1201,19 +1201,19 @@ { "framework": "zix", "language": "Zig", - "rps": 4332, - "avg_latency": "7.32ms", - "p99_latency": "24.30ms", - "cpu": "2758.6%", - "memory": "1.3GiB", + "rps": 8390, + "avg_latency": "3.78ms", + "p99_latency": "10.70ms", + "cpu": "1060.2%", + "memory": "337MiB", "connections": 32, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "456.69KB/s", - "input_bw": "34.36GB/s", - "reconnects": 5755, - "status_2xx": 21664, + "bandwidth": "584.22KB/s", + "input_bw": "66.55GB/s", + "reconnects": 8401, + "status_2xx": 42037, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 diff --git a/site/static/logs/baseline/4096/zix.log b/site/static/logs/baseline/4096/zix.log index 4ed9ba324..e69de29bb 100644 --- a/site/static/logs/baseline/4096/zix.log +++ b/site/static/logs/baseline/4096/zix.log @@ -1 +0,0 @@ -zix: listening on :::8080 (epoll, 64 workers, shared-nothing) diff --git a/site/static/logs/baseline/512/zix.log b/site/static/logs/baseline/512/zix.log index 4ed9ba324..e69de29bb 100644 --- a/site/static/logs/baseline/512/zix.log +++ b/site/static/logs/baseline/512/zix.log @@ -1 +0,0 @@ -zix: listening on :::8080 (epoll, 64 workers, shared-nothing) diff --git a/site/static/logs/json/4096/zix.log b/site/static/logs/json/4096/zix.log index 4ed9ba324..e69de29bb 100644 --- a/site/static/logs/json/4096/zix.log +++ b/site/static/logs/json/4096/zix.log @@ -1 +0,0 @@ -zix: listening on :::8080 (epoll, 64 workers, shared-nothing) diff --git a/site/static/logs/limited-conn/4096/zix.log b/site/static/logs/limited-conn/4096/zix.log index 4ed9ba324..e69de29bb 100644 --- a/site/static/logs/limited-conn/4096/zix.log +++ b/site/static/logs/limited-conn/4096/zix.log @@ -1 +0,0 @@ -zix: listening on :::8080 (epoll, 64 workers, shared-nothing) diff --git a/site/static/logs/limited-conn/512/zix.log b/site/static/logs/limited-conn/512/zix.log index 4ed9ba324..e69de29bb 100644 --- a/site/static/logs/limited-conn/512/zix.log +++ b/site/static/logs/limited-conn/512/zix.log @@ -1 +0,0 @@ -zix: listening on :::8080 (epoll, 64 workers, shared-nothing) diff --git a/site/static/logs/pipelined/4096/zix.log b/site/static/logs/pipelined/4096/zix.log index 4ed9ba324..e69de29bb 100644 --- a/site/static/logs/pipelined/4096/zix.log +++ b/site/static/logs/pipelined/4096/zix.log @@ -1 +0,0 @@ -zix: listening on :::8080 (epoll, 64 workers, shared-nothing) diff --git a/site/static/logs/pipelined/512/zix.log b/site/static/logs/pipelined/512/zix.log index 4ed9ba324..e69de29bb 100644 --- a/site/static/logs/pipelined/512/zix.log +++ b/site/static/logs/pipelined/512/zix.log @@ -1 +0,0 @@ -zix: listening on :::8080 (epoll, 64 workers, shared-nothing) diff --git a/site/static/logs/static/1024/zix.log b/site/static/logs/static/1024/zix.log index 4ed9ba324..e69de29bb 100644 --- a/site/static/logs/static/1024/zix.log +++ b/site/static/logs/static/1024/zix.log @@ -1 +0,0 @@ -zix: listening on :::8080 (epoll, 64 workers, shared-nothing) diff --git a/site/static/logs/static/4096/zix.log b/site/static/logs/static/4096/zix.log index 4ed9ba324..e69de29bb 100644 --- a/site/static/logs/static/4096/zix.log +++ b/site/static/logs/static/4096/zix.log @@ -1 +0,0 @@ -zix: listening on :::8080 (epoll, 64 workers, shared-nothing) diff --git a/site/static/logs/static/6800/zix.log b/site/static/logs/static/6800/zix.log index 4ed9ba324..e69de29bb 100644 --- a/site/static/logs/static/6800/zix.log +++ b/site/static/logs/static/6800/zix.log @@ -1 +0,0 @@ -zix: listening on :::8080 (epoll, 64 workers, shared-nothing) diff --git a/site/static/logs/upload/256/zix.log b/site/static/logs/upload/256/zix.log index 4ed9ba324..e69de29bb 100644 --- a/site/static/logs/upload/256/zix.log +++ b/site/static/logs/upload/256/zix.log @@ -1 +0,0 @@ -zix: listening on :::8080 (epoll, 64 workers, shared-nothing) diff --git a/site/static/logs/upload/32/zix.log b/site/static/logs/upload/32/zix.log index 4ed9ba324..e69de29bb 100644 --- a/site/static/logs/upload/32/zix.log +++ b/site/static/logs/upload/32/zix.log @@ -1 +0,0 @@ -zix: listening on :::8080 (epoll, 64 workers, shared-nothing)