Skip to content

[C#] Add shrike-minima - epoll, SPSC recv ring (Minima model)#835

Open
MDA2AV wants to merge 1 commit into
mainfrom
add-shrike-minima
Open

[C#] Add shrike-minima - epoll, SPSC recv ring (Minima model)#835
MDA2AV wants to merge 1 commit into
mainfrom
add-shrike-minima

Conversation

@MDA2AV
Copy link
Copy Markdown
Owner

@MDA2AV MDA2AV commented Jun 7, 2026

Description

shrike-minima — a C# epoll engine with an IVTS-backed, RCA=true async handler, fixed the Minima way: an SPSC recv ring decouples the worker from the handler. engine-tier; baseline / pipelined / limited-conn.

The model (no driver/handler race)

  • The worker recv's into pooled buffers and enqueues (ptr, len) on a per-connection single-producer / single-consumer ring (SpscRing), then signals.
  • The handler resumes on the thread pool, dequeues the chunks, copies each into its own parse buffer, returns the buffer to the pool, and parses.

Worker and handler touch disjoint ends of the ring (release/acquire) and each recv buffer is owned by one side at a time → the recv buffer is never shared. Unlike the Tokio-style sibling, recv pipelines with parse (the worker keeps pumping while the handler works); the cost is one extra copy (chunk → parse buffer) + the pool/ring bookkeeping. It's the epoll analogue of Minima's SpscRecvRing.

Siblings (same race, two fixes)

Verification

validate.sh 14/14 (every TCP-fragmentation case), 0/100 fragmented POST, 8000 keep-alive with 0 drops.

A C# epoll engine with an IVTS-backed, RCA=true async handler, fixed the
Minima way: an SPSC recv ring decouples the worker from the handler. The
worker recv's into pooled buffers and enqueues (ptr, len) on a per-connection
single-producer / single-consumer ring; the handler resumes on the thread
pool, dequeues the chunks into its own parse buffer, and returns the buffers.
Worker and handler never share a buffer (no driver/handler race), and recv
pipelines with parse. The epoll analogue of Minima's SpscRecvRing.

Sibling of shrike-tokio (#832), which fixes the same race the Tokio way (the
handler does its own recv). Serves baseline, pipelined, limited-conn;
hand-rolled HTTP/1.1; Connection: close sends a FIN. Validated 14/14 (every
TCP-fragmentation case), 0/100 fragmented POST, 8000 keep-alive with zero drops.
@MDA2AV
Copy link
Copy Markdown
Owner Author

MDA2AV commented Jun 8, 2026

/benchmark -f shrike-minima

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 8, 2026

👋 /benchmark request received. A collaborator will review and approve the run.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 8, 2026

Benchmark Results

Framework: shrike-minima | Test: all tests

Test Conn RPS CPU Mem Δ RPS Δ Mem
baseline 512 1,128,137 6428.0% 100MiB NEW NEW
baseline 4096 1,186,206 6547.4% 211MiB NEW NEW
pipelined 512 17,854,854 6648.3% 69MiB NEW NEW
pipelined 4096 17,341,657 6462.3% 228MiB NEW NEW
limited-conn 512 0 0.0% 0MiB NEW NEW
limited-conn 4096 12,241 0.0% 0MiB NEW NEW
Full log
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency      0us      0us      0us      0us      0us

  2023 requests in 5.00s, 0 responses
  Throughput: 0 req/s
  Bandwidth:  20B/s
  Status codes: 2xx=0, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 0 / 0 responses (0.0%)
  Reconnects: 5004901
  Errors: connect 5002367, read 0, timeout 0
  Per-template: 0,0,0
  Per-template-ok: 0,0,0
[info] CPU 0.0% | Mem 0MiB

[run 2/3]
gcannon v0.5.3
  Target:    localhost:8080/
  Threads:   64
  Conns:     512 (8/thread)
  Pipeline:  1
  Req/conn:  10
  Templates: 3
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency      0us      0us      0us      0us      0us

  0 requests in 5.00s, 0 responses
  Throughput: 0 req/s
  Bandwidth:  0B/s
  Status codes: 2xx=0, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 0 / 0 responses (0.0%)
  Reconnects: 4744661
  Errors: connect 4744649, read 0, timeout 0
  Per-template: 0,0,0
  Per-template-ok: 0,0,0
[info] CPU 0.0% | Mem 0MiB

[run 3/3]
gcannon v0.5.3
  Target:    localhost:8080/
  Threads:   64
  Conns:     512 (8/thread)
  Pipeline:  1
  Req/conn:  10
  Templates: 3
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency      0us      0us      0us      0us      0us

  0 requests in 5.00s, 0 responses
  Throughput: 0 req/s
  Bandwidth:  0B/s
  Status codes: 2xx=0, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 0 / 0 responses (0.0%)
  Reconnects: 5281183
  Errors: connect 5281166, read 0, timeout 0
  Per-template: 0,0,0
  Per-template-ok: 0,0,0
[info] CPU 0.0% | Mem 0MiB

=== Best: 0 req/s (CPU: 0.0%, Mem: 0MiB) ===
[info] saved results/limited-conn/512/shrike-minima.json
httparena-bench-shrike-minima
httparena-bench-shrike-minima

==============================================
=== shrike-minima / limited-conn / 4096c (tool=gcannon) ===
==============================================
[info] waiting for server...
[info] server ready

[run 1/3]
gcannon v0.5.3
  Target:    localhost:8080/
  Threads:   64
  Conns:     4096 (64/thread)
  Pipeline:  1
  Req/conn:  10
  Templates: 3
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency   12.48ms   3.81ms   25.20ms   144.40ms   162.30ms

  79152 requests in 5.00s, 61207 responses
  Throughput: 12.24K req/s
  Bandwidth:  788.74KB/s
  Status codes: 2xx=61207, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 61207 / 61207 responses (100.0%)
  Reconnects: 4243282
  Errors: connect 4216889, read 0, timeout 0
  Per-template: 20571,20327,20309
  Per-template-ok: 20571,20327,20309
[info] CPU 0.0% | Mem 0MiB

[run 2/3]
gcannon v0.5.3
  Target:    localhost:8080/
  Threads:   64
  Conns:     4096 (64/thread)
  Pipeline:  1
  Req/conn:  10
  Templates: 3
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency      0us      0us      0us      0us      0us

  1 requests in 5.00s, 0 responses
  Throughput: 0 req/s
  Bandwidth:  16B/s
  Status codes: 2xx=0, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 0 / 0 responses (0.0%)
  Reconnects: 5197621
  Errors: connect 5197611, read 0, timeout 0
  Per-template: 0,0,0
  Per-template-ok: 0,0,0
[info] CPU 0.0% | Mem 0MiB

[run 3/3]
gcannon v0.5.3
  Target:    localhost:8080/
  Threads:   64
  Conns:     4096 (64/thread)
  Pipeline:  1
  Req/conn:  10
  Templates: 3
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency      0us      0us      0us      0us      0us

  1 requests in 5.00s, 0 responses
  Throughput: 0 req/s
  Bandwidth:  20B/s
  Status codes: 2xx=0, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 0 / 0 responses (0.0%)
  Reconnects: 4985264
  Errors: connect 4985247, read 0, timeout 0
  Per-template: 0,0,0
  Per-template-ok: 0,0,0
[info] CPU 0.0% | Mem 0MiB

=== Best: 12241 req/s (CPU: 0.0%, Mem: 0MiB) ===
[info] input BW: 968.28KB/s (avg template: 81 bytes)
[info] saved results/limited-conn/4096/shrike-minima.json
httparena-bench-shrike-minima
httparena-bench-shrike-minima
[info] skip: shrike-minima does not subscribe to json
[info] skip: shrike-minima does not subscribe to json-comp
[info] skip: shrike-minima does not subscribe to json-tls
[info] skip: shrike-minima does not subscribe to upload
[info] skip: shrike-minima does not subscribe to api-4
[info] skip: shrike-minima does not subscribe to api-16
[info] skip: shrike-minima does not subscribe to static
[info] skip: shrike-minima does not subscribe to async-db
[info] skip: shrike-minima does not subscribe to crud
[info] skip: shrike-minima does not subscribe to fortunes
[info] skip: shrike-minima does not subscribe to baseline-h2
[info] skip: shrike-minima does not subscribe to static-h2
[info] skip: shrike-minima does not subscribe to baseline-h2c
[info] skip: shrike-minima does not subscribe to json-h2c
[info] skip: shrike-minima does not subscribe to baseline-h3
[info] skip: shrike-minima does not subscribe to static-h3
[info] skip: shrike-minima does not subscribe to gateway-64
[info] skip: shrike-minima does not subscribe to gateway-h3
[info] skip: shrike-minima does not subscribe to production-stack
[info] skip: shrike-minima does not subscribe to unary-grpc
[info] skip: shrike-minima does not subscribe to unary-grpc-tls
[info] skip: shrike-minima does not subscribe to stream-grpc
[info] skip: shrike-minima does not subscribe to stream-grpc-tls
[info] skip: shrike-minima does not subscribe to echo-ws
[info] skip: shrike-minima does not subscribe to echo-ws-pipeline
[info] rebuilding site/data/*.json
[updated] /home/diogo/actions-runner/_work/HttpArena/HttpArena/site/data/frameworks.json
[updated] /home/diogo/actions-runner/_work/HttpArena/HttpArena/site/data/baseline-4096.json
[updated] /home/diogo/actions-runner/_work/HttpArena/HttpArena/site/data/baseline-512.json
[updated] /home/diogo/actions-runner/_work/HttpArena/HttpArena/site/data/limited-conn-4096.json
[updated] /home/diogo/actions-runner/_work/HttpArena/HttpArena/site/data/limited-conn-512.json
[updated] /home/diogo/actions-runner/_work/HttpArena/HttpArena/site/data/pipelined-4096.json
[updated] /home/diogo/actions-runner/_work/HttpArena/HttpArena/site/data/pipelined-512.json
[updated] /home/diogo/actions-runner/_work/HttpArena/HttpArena/site/data/current.json
[info] done
[info] restoring loopback MTU to 65536

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant