Skip to content

Add may-minihttp — Rust stackful coroutines engine#236

Open
BennyFranciscus wants to merge 2 commits intoMDA2AV:mainfrom
BennyFranciscus:add-may-minihttp
Open

Add may-minihttp — Rust stackful coroutines engine#236
BennyFranciscus wants to merge 2 commits intoMDA2AV:mainfrom
BennyFranciscus:add-may-minihttp

Conversation

@BennyFranciscus
Copy link
Copy Markdown
Collaborator

What

Adds may-minihttp as a new engine entry. may-minihttp is a mini HTTP server built on the May coroutine library — stackful coroutines in Rust with a coroutine-per-connection model.

This is a really interesting approach — instead of async/await (like tokio/hyper), May uses stackful coroutines similar to goroutines. Each connection gets its own coroutine with cooperative scheduling. The API stays synchronous and blocking-style, but underneath it's all non-blocking I/O with work-stealing. Pretty cool design.

Already does well on TechEmpower benchmarks, curious to see how it stacks up in HttpArena against hyper, actix, etc.

Type

Engine — raw HTTP server with no routing, JSON, compression, or DB abstractions.

Test Profiles

  • baseline — GET (query param sum) + POST (body parsing)
  • pipelined — returns ok
  • limited-conn — same endpoints, short-lived connections

Implementation Details

  • may_minihttp 0.1.11 on may 0.3 (stackful coroutines)
  • mimalloc allocator
  • num_cpus workers via may::config().set_workers()
  • Compiled with -C target-cpu=native, thin LTO, single codegen unit
  • Slim Dockerfile: rust:1.88 build → debian:bookworm-slim runtime

Validation

Docker build: ✅
All endpoints tested locally:

  • GET /baseline11?a=10&b=20&c=3060
  • POST /baseline11?a=5&b=10 body=100115
  • GET /pipelineok
  • Unknown routes → 404 ✅

cc @Xudong-Huang — would love your feedback! The stackful coroutine approach is a really unique take on high-concurrency HTTP serving.

may-minihttp is a mini HTTP server built on the May coroutine library,
which uses stackful coroutines for cooperative scheduling. It follows
a coroutine-per-connection model similar to goroutines but in Rust.

Implemented as an engine with baseline, pipelined, and limited-conn
test profiles. Uses mimalloc allocator and thin LTO for performance.

Repo: https://github.com/Xudong-Huang/may_minihttp
may_minihttp's BodyReader only supports Content-Length bodies.
Chunked Transfer-Encoding requests crash the connection parser
since the chunk framing corrupts subsequent request parsing.

Rewritten to use may TCP directly with httparse for header parsing
and manual chunked TE decoding. This fixes the CI validate failure
on the chunked POST baseline test.
@MDA2AV
Copy link
Copy Markdown
Owner

MDA2AV commented Mar 28, 2026

/benchmark baseline

@github-actions
Copy link
Copy Markdown

🚀 Benchmark run triggered for may-minihttp (profile: baseline). Results will be posted here when done.

@github-actions
Copy link
Copy Markdown

Benchmark Results

Framework: may-minihttp | Profile: baseline

may-minihttp / baseline / 512c (p=1, r=0, cpu=64)
  Best: 2858655 req/s (CPU: 6133.3%, Mem: 105.2MiB) ===

may-minihttp / baseline / 4096c (p=1, r=0, cpu=64)
  Best: 2977547 req/s (CPU: 6150.1%, Mem: 184.1MiB) ===

may-minihttp / baseline / 16384c (p=1, r=0, cpu=64)
  Best: 2810015 req/s (CPU: 5950.9%, Mem: 358.6MiB) ===
Full log
[run 3/3]
gcannon — io_uring HTTP load generator
  Target:    localhost:8080/
  Threads:   64
  Conns:     512 (8/thread)
  Pipeline:  1
  Req/conn:  unlimited (keep-alive)
  Templates: 3
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency    178us    146us    300us    664us   1.60ms

  14293281 requests in 5.00s, 14293279 responses
  Throughput: 2.86M req/s
  Bandwidth:  179.85MB/s
  Status codes: 2xx=14293279, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 14293236 / 14293279 responses (100.0%)
  Per-template: 4783264,4781984,4727988
  Per-template-ok: 4783264,4781984,4727988
  CPU: 6133.3% | Mem: 105.2MiB

=== Best: 2858655 req/s (CPU: 6133.3%, Mem: 105.2MiB) ===
  Input BW: 220.82MB/s (avg template: 81 bytes)
[dry-run] Results not saved (use --save to persist)
httparena-bench-may-minihttp
httparena-bench-may-minihttp

==============================================
=== may-minihttp / baseline / 4096c (p=1, r=0, cpu=64) ===
==============================================
4d0f5b82bbb06f5c139b33c5abb2c8a8d762f20d28a5880bffaa5e5d8bada5f7
[wait] Waiting for server...
[ready] Server is up

[run 1/3]
gcannon — io_uring HTTP load generator
  Target:    localhost:8080/
  Threads:   64
  Conns:     4096 (64/thread)
  Pipeline:  1
  Req/conn:  unlimited (keep-alive)
  Templates: 3
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency   1.25ms    933us   2.49ms   4.95ms   8.52ms

  14890123 requests in 5.00s, 14887735 responses
  Throughput: 2.98M req/s
  Bandwidth:  187.33MB/s
  Status codes: 2xx=14887735, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 14887697 / 14887735 responses (100.0%)
  Per-template: 4982529,4949741,4955427
  Per-template-ok: 4982529,4949741,4955427
  CPU: 6150.1% | Mem: 184.1MiB

[run 2/3]
gcannon — io_uring HTTP load generator
  Target:    localhost:8080/
  Threads:   64
  Conns:     4096 (64/thread)
  Pipeline:  1
  Req/conn:  unlimited (keep-alive)
  Templates: 3
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency   1.23ms    903us   2.47ms   4.95ms   8.35ms

  14825573 requests in 5.00s, 14823323 responses
  Throughput: 2.96M req/s
  Bandwidth:  186.43MB/s
  Status codes: 2xx=14823323, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 14823235 / 14823323 responses (100.0%)
  Per-template: 4947343,4956852,4919040
  Per-template-ok: 4947343,4956852,4919040
  CPU: 6328.8% | Mem: 187.4MiB

[run 3/3]
gcannon — io_uring HTTP load generator
  Target:    localhost:8080/
  Threads:   64
  Conns:     4096 (64/thread)
  Pipeline:  1
  Req/conn:  unlimited (keep-alive)
  Templates: 3
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency   1.23ms    904us   2.49ms   4.99ms   8.36ms

  14795826 requests in 5.00s, 14793453 responses
  Throughput: 2.96M req/s
  Bandwidth:  186.12MB/s
  Status codes: 2xx=14793453, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 14793369 / 14793453 responses (100.0%)
  Per-template: 4943176,4927953,4922240
  Per-template-ok: 4943176,4927953,4922240
  CPU: 6116.4% | Mem: 186.1MiB

=== Best: 2977547 req/s (CPU: 6150.1%, Mem: 184.1MiB) ===
  Input BW: 230.01MB/s (avg template: 81 bytes)
[dry-run] Results not saved (use --save to persist)
httparena-bench-may-minihttp
httparena-bench-may-minihttp

==============================================
=== may-minihttp / baseline / 16384c (p=1, r=0, cpu=64) ===
==============================================
15179e9bca3293ee72f59318ebe7b0d743d2701d1676f37ad272faf9f622b763
[wait] Waiting for server...
[ready] Server is up

[run 1/3]
gcannon — io_uring HTTP load generator
  Target:    localhost:8080/
  Threads:   64
  Conns:     16384 (256/thread)
  Pipeline:  1
  Req/conn:  unlimited (keep-alive)
  Templates: 3
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency   3.43ms   2.44ms   5.86ms   10.80ms   19.50ms

  14066459 requests in 5.00s, 14050075 responses
  Throughput: 2.81M req/s
  Bandwidth:  176.77MB/s
  Status codes: 2xx=14050075, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 14050075 / 14050075 responses (100.0%)
  Per-template: 4678471,4681568,4690036
  Per-template-ok: 4678471,4681568,4690036
  CPU: 5950.9% | Mem: 358.6MiB

[run 2/3]
gcannon — io_uring HTTP load generator
  Target:    localhost:8080/
  Threads:   64
  Conns:     16384 (256/thread)
  Pipeline:  1
  Req/conn:  unlimited (keep-alive)
  Templates: 3
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency   5.01ms   3.60ms   8.41ms   16.20ms   28.30ms

  13480797 requests in 5.00s, 13464413 responses
  Throughput: 2.69M req/s
  Bandwidth:  169.43MB/s
  Status codes: 2xx=13464413, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 13464413 / 13464413 responses (100.0%)
  Per-template: 4496642,4482091,4485680
  Per-template-ok: 4496642,4482091,4485680
  CPU: 6314.1% | Mem: 424.1MiB

[run 3/3]
gcannon — io_uring HTTP load generator
  Target:    localhost:8080/
  Threads:   64
  Conns:     16384 (256/thread)
  Pipeline:  1
  Req/conn:  unlimited (keep-alive)
  Templates: 3
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency   5.33ms   3.85ms   9.04ms   17.30ms   33.70ms

  13377689 requests in 5.00s, 13361305 responses
  Throughput: 2.67M req/s
  Bandwidth:  168.05MB/s
  Status codes: 2xx=13361305, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 13361305 / 13361305 responses (100.0%)
  Per-template: 4455760,4455848,4449697
  Per-template-ok: 4455760,4455848,4449697
  CPU: 5718.0% | Mem: 470.0MiB

=== Best: 2810015 req/s (CPU: 5950.9%, Mem: 358.6MiB) ===
  Input BW: 217.07MB/s (avg template: 81 bytes)
[dry-run] Results not saved (use --save to persist)
httparena-bench-may-minihttp
httparena-bench-may-minihttp
[restore] Restoring CPU governor to performance...

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.

2 participants