Skip to content

Commit 0bf06a5

Browse files
authored
Merge pull request #8 from MDA2AV/amd2-pr
AMD2 benchmark round: add nginx-openresty, rename h2o-h3 to h2o-mruby…
2 parents 7c7b14c + 45f07f8 commit 0bf06a5

234 files changed

Lines changed: 142175 additions & 26419 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"display_name": "h2o-h3",
2+
"display_name": "h2o-mruby",
33
"language": "C",
44
"type": "realistic",
55
"engine": "h2o",
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM openresty/openresty:alpine
2+
3+
COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
4+
COPY handler.lua /usr/local/openresty/lualib/handler.lua
5+
6+
EXPOSE 8080 8443
7+
8+
CMD ["openresty", "-g", "daemon off;"]
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
local cjson = require "cjson"
2+
3+
local _M = {}
4+
5+
local json_resp = ""
6+
local large_resp = ""
7+
local static_files = {}
8+
9+
function _M.init()
10+
local mime = {
11+
css = "text/css", js = "application/javascript", html = "text/html",
12+
woff2 = "font/woff2", svg = "image/svg+xml", webp = "image/webp",
13+
json = "application/json",
14+
}
15+
16+
-- Load small dataset
17+
local f = io.open(os.getenv("DATASET_PATH") or "/data/dataset.json", "r")
18+
if f then
19+
local data = cjson.decode(f:read("*a"))
20+
f:close()
21+
for _, item in ipairs(data) do
22+
item.total = math.floor(item.price * item.quantity * 100 + 0.5) / 100
23+
end
24+
json_resp = cjson.encode({items = data, count = #data})
25+
end
26+
27+
-- Load large dataset
28+
f = io.open("/data/dataset-large.json", "r")
29+
if f then
30+
local data = cjson.decode(f:read("*a"))
31+
f:close()
32+
for _, item in ipairs(data) do
33+
item.total = math.floor(item.price * item.quantity * 100 + 0.5) / 100
34+
end
35+
large_resp = cjson.encode({items = data, count = #data})
36+
end
37+
38+
-- Load static files
39+
local handle = io.popen("ls /data/static 2>/dev/null")
40+
if handle then
41+
for name in handle:lines() do
42+
local file = io.open("/data/static/" .. name, "rb")
43+
if file then
44+
local ext = name:match("%.(%w+)$")
45+
static_files[name] = {
46+
data = file:read("*a"),
47+
ct = mime[ext] or "application/octet-stream",
48+
}
49+
file:close()
50+
end
51+
end
52+
handle:close()
53+
end
54+
end
55+
56+
local function sum_args()
57+
local args = ngx.req.get_uri_args()
58+
local sum = 0
59+
for _, v in pairs(args) do
60+
if type(v) == "table" then
61+
for _, val in ipairs(v) do
62+
sum = sum + (tonumber(val) or 0)
63+
end
64+
else
65+
sum = sum + (tonumber(v) or 0)
66+
end
67+
end
68+
return sum
69+
end
70+
71+
function _M.pipeline()
72+
ngx.header["Content-Type"] = "text/plain"
73+
ngx.print("ok")
74+
end
75+
76+
function _M.baseline11()
77+
local sum = sum_args()
78+
if ngx.req.get_method() == "POST" then
79+
ngx.req.read_body()
80+
local body = ngx.req.get_body_data()
81+
if body then
82+
sum = sum + (tonumber(body) or 0)
83+
end
84+
end
85+
ngx.header["Content-Type"] = "text/plain"
86+
ngx.print(string.format("%d", sum))
87+
end
88+
89+
function _M.baseline2()
90+
ngx.header["Content-Type"] = "text/plain"
91+
ngx.print(string.format("%d", sum_args()))
92+
end
93+
94+
function _M.json()
95+
if json_resp == "" then
96+
ngx.status = 500
97+
ngx.print("dataset not loaded")
98+
return
99+
end
100+
ngx.header["Content-Type"] = "application/json"
101+
ngx.print(json_resp)
102+
end
103+
104+
function _M.compression()
105+
if large_resp == "" then
106+
ngx.status = 500
107+
ngx.print("dataset not loaded")
108+
return
109+
end
110+
ngx.header["Content-Type"] = "application/json"
111+
ngx.print(large_resp)
112+
end
113+
114+
function _M.upload()
115+
ngx.req.read_body()
116+
local body = ngx.req.get_body_data()
117+
if not body then
118+
local fname = ngx.req.get_body_file()
119+
if fname then
120+
local f = io.open(fname, "rb")
121+
if f then
122+
body = f:read("*a")
123+
f:close()
124+
end
125+
end
126+
end
127+
if not body then
128+
ngx.status = 400
129+
ngx.print("no body")
130+
return
131+
end
132+
ngx.header["Content-Type"] = "text/plain"
133+
ngx.print(string.format("%08x", ngx.crc32_long(body)))
134+
end
135+
136+
function _M.static_file()
137+
local name = ngx.var.uri:match("/static/(.+)")
138+
if not name then
139+
ngx.status = 404
140+
ngx.print("not found")
141+
return
142+
end
143+
local sf = static_files[name]
144+
if not sf then
145+
ngx.status = 404
146+
ngx.print("not found")
147+
return
148+
end
149+
ngx.header["Content-Type"] = sf.ct
150+
ngx.print(sf.data)
151+
end
152+
153+
return _M
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"display_name": "nginx-openresty",
3+
"language": "Lua",
4+
"type": "realistic",
5+
"engine": "openresty",
6+
"description": "OpenResty (Nginx + LuaJIT) with Lua content handlers for all benchmark endpoints.",
7+
"repo": "https://github.com/openresty/openresty",
8+
"enabled": true,
9+
"tests": [
10+
"baseline",
11+
"pipelined",
12+
"limited-conn",
13+
"json",
14+
"upload",
15+
"compression",
16+
"noisy",
17+
"baseline-h2",
18+
"static-h2"
19+
]
20+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
worker_processes auto;
2+
worker_rlimit_nofile 65536;
3+
4+
events {
5+
worker_connections 65536;
6+
multi_accept on;
7+
}
8+
9+
http {
10+
access_log off;
11+
error_log /dev/null crit;
12+
13+
sendfile on;
14+
tcp_nopush on;
15+
tcp_nodelay on;
16+
keepalive_timeout 65;
17+
keepalive_requests 1000000;
18+
server_tokens off;
19+
client_max_body_size 25m;
20+
client_body_buffer_size 25m;
21+
22+
gzip on;
23+
gzip_types application/json;
24+
gzip_min_length 100;
25+
gzip_comp_level 1;
26+
27+
init_by_lua_block {
28+
require("handler").init()
29+
}
30+
31+
server {
32+
listen 8080 reuseport;
33+
34+
location /pipeline { content_by_lua_block { require("handler").pipeline() } }
35+
location /baseline11 { content_by_lua_block { require("handler").baseline11() } }
36+
location /baseline2 { content_by_lua_block { require("handler").baseline2() } }
37+
location /json { content_by_lua_block { require("handler").json() } }
38+
location /compression { content_by_lua_block { require("handler").compression() } }
39+
location /upload { content_by_lua_block { require("handler").upload() } }
40+
location /static/ { content_by_lua_block { require("handler").static_file() } }
41+
}
42+
43+
server {
44+
listen 8443 ssl reuseport;
45+
http2 on;
46+
47+
ssl_certificate /certs/server.crt;
48+
ssl_certificate_key /certs/server.key;
49+
ssl_protocols TLSv1.3;
50+
51+
location /baseline2 { content_by_lua_block { require("handler").baseline2() } }
52+
location /static/ { content_by_lua_block { require("handler").static_file() } }
53+
}
54+
}

frameworks/ringzero/Dockerfile

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
FROM ubuntu:24.04 AS build
2-
RUN apt-get update && apt-get install -y gcc make liburing-dev
2+
RUN apt-get update && apt-get install -y gcc make git
3+
RUN git clone --depth 1 --branch liburing-2.9 https://github.com/axboe/liburing.git /tmp/liburing \
4+
&& cd /tmp/liburing && ./configure && make -C src -j$(nproc) && make -C src install && ldconfig \
5+
&& rm -rf /tmp/liburing
36
WORKDIR /app
47

58
# Copy ringzero library source (provided via build context)
@@ -19,7 +22,8 @@ RUN gcc -O2 -Wall -march=native -pthread -Iinclude -c main.c -o main.o
1922
RUN gcc -o server main.o acceptor.o connection.o engine.o listener.o reactor.o -luring -lpthread
2023

2124
FROM ubuntu:24.04
22-
RUN apt-get update && apt-get install -y liburing2 && rm -rf /var/lib/apt/lists/*
25+
COPY --from=build /usr/lib/liburing.so.2.9 /usr/lib/
26+
RUN ln -s /usr/lib/liburing.so.2.9 /usr/lib/liburing.so.2 && ldconfig
2327
COPY --from=build /app/server /server
2428
EXPOSE 8080
25-
CMD ["/server", "12"]
29+
CMD ["/server", "64"]

scripts/benchmark.sh

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
55
ROOT_DIR="$SCRIPT_DIR/.."
66
cd "$ROOT_DIR"
77

8-
GCANNON="${GCANNON:-/home/diogo/Desktop/Socket/gcannon/gcannon}"
8+
GCANNON="${GCANNON:-gcannon}"
99
H2LOAD="${H2LOAD:-h2load}"
10-
OHA="${OHA:-oha}"
10+
OHA="${OHA:-$HOME/.cargo/bin/oha}"
1111
HARD_NOFILE=$(ulimit -Hn)
1212
ulimit -n "$HARD_NOFILE"
13-
THREADS=12
13+
THREADS="${THREADS:-12}"
1414
DURATION=5s
1515
RUNS=3
1616
PORT=8080
@@ -26,14 +26,14 @@ declare -A PROFILES=(
2626
[baseline]="1|0||512,4096,16384|"
2727
[pipelined]="16|0||512,4096,16384|pipeline"
2828
[limited-conn]="1|10||512,4096|"
29-
[json]="1|0||4096,16384,32768|json"
29+
[json]="1|0||4096,16384|json"
3030
[upload]="1|0||64,256,512|upload"
3131
[compression]="1|0||4096,16384|compression"
3232
[noisy]="1|0||512,4096,16384|noisy"
3333
[baseline-h2]="1|0||64,256,1024|h2"
3434
[static-h2]="1|0||64,256,1024|static-h2"
35-
[baseline-h3]="128|0||64,512|h3"
36-
[static-h3]="128|0||64,512|static-h3"
35+
[baseline-h3]="32|0||256,512|h3"
36+
[static-h3]="32|0||256,512|static-h3"
3737
)
3838
PROFILE_ORDER=(baseline pipelined limited-conn json upload compression noisy baseline-h2 static-h2 baseline-h3 static-h3)
3939

@@ -194,7 +194,7 @@ if [ -f "$META_FILE" ]; then
194194
dn=$(grep -oP '"display_name"\s*:\s*"\K[^"]+' "$META_FILE" 2>/dev/null || echo "")
195195
[ -n "$dn" ] && DISPLAY_NAME="$dn"
196196
# Read tests array — extract as comma-separated list
197-
FRAMEWORK_TESTS=$(grep -oP '"tests"\s*:\s*\[\K[^\]]+' "$META_FILE" 2>/dev/null | tr -d ' "' || echo "")
197+
FRAMEWORK_TESTS=$(python3 -c "import json,sys; print(','.join(json.load(open(sys.argv[1])).get('tests',[])))" "$META_FILE" 2>/dev/null || echo "")
198198

199199
# Check enabled
200200
enabled=$(grep -oP '"enabled"\s*:\s*\K(true|false)' "$META_FILE" 2>/dev/null || echo "true")
@@ -294,8 +294,10 @@ for profile in "${profiles_to_run[@]}"; do
294294
break
295295
fi
296296
if [ "$i" -eq 30 ]; then
297-
echo "FAIL: Server did not start within 30s"
298-
exit 1
297+
echo "FAIL: Server did not start within 30s — skipping"
298+
docker stop -t 5 "$CONTAINER_NAME" 2>/dev/null || true
299+
docker rm -f "$CONTAINER_NAME" 2>/dev/null || true
300+
continue 2
299301
fi
300302
sleep 1
301303
done
@@ -375,7 +377,7 @@ for profile in "${profiles_to_run[@]}"; do
375377
stats_pid=$!
376378

377379
if [ "$USE_OHA" = "true" ]; then
378-
"${gc_args[@]}" || true
380+
timeout --foreground 45 "${gc_args[@]}" || true
379381
output=$(cat "$oha_out" 2>/dev/null)
380382
rm -f "$oha_out"
381383
elif [ "$USE_H2LOAD" = "true" ]; then

site/content/docs/running-locally/prerequisites.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ Required tools and system dependencies to run HttpArena benchmarks.
2020
sudo apt install nghttp2-client
2121
```
2222

23+
## Installing gcannon
24+
25+
```bash
26+
git clone https://github.com/MDA2AV/gcannon.git
27+
cd gcannon
28+
make
29+
sudo cp gcannon /usr/local/bin/
30+
```
31+
2332
## Installing oha
2433

2534
```bash

0 commit comments

Comments
 (0)