Skip to content

Instantly share code, notes, and snippets.

@anuragsoni
Last active February 5, 2026 01:27
Show Gist options
  • Select an option

  • Save anuragsoni/79c9bb1c7b7da71e1998d1b748211d60 to your computer and use it in GitHub Desktop.

Select an option

Save anuragsoni/79c9bb1c7b7da71e1998d1b748211d60 to your computer and use it in GitHub Desktop.
httpz vs shuttle
Benchmark was run via ./_build/default/bench/bench_compare.exe
============================================================
HTTP Parser Comparison: httpz (OxCaml) vs httpe (Eio)
============================================================
httpz: Stack-allocated parser using OxCaml unboxed types
httpe: Eio-based parser using Buf_read streaming
SMALL REQUEST (35 bytes, 500000 iterations)
------------------------------------------------------------
httpz (OxCaml) 116 ns/op 8596999 ops/s 0 words/op
Shuttle_http 51 ns/op 19797340 ops/s 23 words/op
-> Shuttle_http is 2.30x faster, 0.0x more allocations
MEDIUM REQUEST (439 bytes, 200000 iterations)
------------------------------------------------------------
httpz (OxCaml) 1166 ns/op 857471 ops/s 0 words/op
Shuttle_http 353 ns/op 2836644 ops/s 147 words/op
-> Shuttle_http is 3.31x faster, 0.0x more allocations
LARGE REQUEST (1155 bytes, 100000 iterations)
------------------------------------------------------------
httpz (OxCaml) 2768 ns/op 361243 ops/s 0 words/op
Shuttle_http 788 ns/op 1269359 ops/s 336 words/op
-> Shuttle_http is 3.51x faster, 0.0x more allocations
THROUGHPUT TEST (1000 iterations per call)
============================================================
Small request throughput:
httpz: 11412793 requests/sec
shuttle_http: 19861369 requests/sec
-> httpz is 0.57x slower
SUMMARY
============================================================
Size httpz ns/op shuttle ns/op Speedup Alloc Ratio
------------------------------------------------------------
Small 116 51 0.43x 23.1x
Medium 1166 353 0.30x 146.8x
Large 2768 788 0.28x 335.6x
============================================================
Benchmark Complete
============================================================
commit 120aa6726f03e5bf4abd4195393378ae4921d717
Author: Anurag Soni <anurag@sonianurag.com>
Date: Wed Feb 4 20:26:32 2026 -0500
test with shuttle
diff --git a/bench/bench_compare.ml b/bench/bench_compare.ml
index bd2108f..859e1f0 100644
--- a/bench/bench_compare.ml
+++ b/bench/bench_compare.ml
@@ -179,14 +179,16 @@ end
Httpe (Eio) Benchmarks
============================================ *)
-module Httpe_bench = struct
+module Shuttle_bench = struct
let parse_request data =
- let reader = Eio.Buf_read.of_string data in
- let req = Httpe.Read.request reader in
- (* Touch results to prevent optimization *)
- let _ = req.Httpe.Request.target in
- let _ = req.Httpe.Request.headers in
- req
+ match Shuttle_http.Parser.parse_request data with
+ | Ok (req, _) ->
+ (* Touch results to prevent optimization *)
+ let _ = Shuttle_http.Request.meth req in
+ let _ = Shuttle_http.Request.headers req in
+ req
+ | Error Shuttle_http.Parser.Partial -> assert false
+ | Error (Shuttle_http.Parser.Fail error) -> Error.raise error
;;
end
@@ -203,12 +205,14 @@ let run_size_benchmark ~name ~data ~iterations =
Httpz_bench.parse_request data)
in
Bench.print_result httpz_result;
- let httpe_result =
- Bench.run ~name:"httpe (Eio)" ~iterations (fun () -> Httpe_bench.parse_request data)
+ let data_bstr = Core.Bigstring.of_string data in
+ let shuttle_result =
+ Bench.run ~name:"Shuttle_http" ~iterations (fun () ->
+ Shuttle_bench.parse_request data_bstr)
in
- Bench.print_result httpe_result;
- Bench.print_comparison ~baseline:httpe_result ~test:httpz_result;
- httpz_result, httpe_result
+ Bench.print_result shuttle_result;
+ Bench.print_comparison ~baseline:httpz_result ~test:shuttle_result;
+ httpz_result, shuttle_result
;;
let run_throughput_benchmark () =
@@ -227,15 +231,16 @@ let run_throughput_benchmark () =
let httpz_total_ops = Float.of_int (outer_iterations * iterations) in
let httpz_ops_per_sec = httpz_total_ops /. httpz_tp.total_time in
Stdio.printf " httpz: %.0f requests/sec\n" httpz_ops_per_sec;
+ let small_request_bstr = Core.Bigstring.of_string small_request in
let httpe_tp =
- Bench.run ~name:"httpe throughput" ~iterations:outer_iterations (fun () ->
+ Bench.run ~name:"shuttle throughput" ~iterations:outer_iterations (fun () ->
for _ = 1 to iterations do
- ignore (Httpe_bench.parse_request small_request)
+ ignore (Shuttle_bench.parse_request small_request_bstr)
done)
in
let httpe_total_ops = Float.of_int (outer_iterations * iterations) in
let httpe_ops_per_sec = httpe_total_ops /. httpe_tp.total_time in
- Stdio.printf " httpe: %.0f requests/sec\n" httpe_ops_per_sec;
+ Stdio.printf " shuttle_http: %.0f requests/sec\n" httpe_ops_per_sec;
let ratio = httpz_ops_per_sec /. httpe_ops_per_sec in
Stdio.printf
" -> httpz is %.2fx %s\n"
@@ -251,7 +256,7 @@ let print_summary results =
"\n%-15s %12s %12s %10s %10s\n"
"Size"
"httpz ns/op"
- "httpe ns/op"
+ "shuttle ns/op"
"Speedup"
"Alloc Ratio";
Stdio.print_string (String.make 60 '-');
diff --git a/bench/dune b/bench/dune
index 5d61834..033f1cb 100644
--- a/bench/dune
+++ b/bench/dune
@@ -1,6 +1,6 @@
(executable
(name bench_httpz)
- (libraries httpz base core core_bench)
+ (libraries httpz base core core_bench shuttle_http)
(preprocess
(pps ppx_jane)))
@@ -9,4 +9,4 @@
(executable
(name bench_compare)
- (libraries httpz httpe eio eio_main base))
+ (libraries httpz httpe eio eio_main base shuttle_http))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment