From c8e952d0c93903c56ca3f077a31c992b8ef9aee5 Mon Sep 17 00:00:00 2001 From: Uday Khare Date: Tue, 22 Sep 2026 11:18:34 +0530 Subject: [PATCH 01/14] Add Aegon (C++26) framework entry --- frameworks/aegon/CMakeLists.txt | 19 +++ frameworks/aegon/Dockerfile | 53 ++++++++ frameworks/aegon/README.md | 12 ++ frameworks/aegon/main.cpp | 206 ++++++++++++++++++++++++++++++++ frameworks/aegon/meta.json | 32 +++++ site/data/tls/aegon.json | 5 + 6 files changed, 327 insertions(+) create mode 100644 frameworks/aegon/CMakeLists.txt create mode 100644 frameworks/aegon/Dockerfile create mode 100644 frameworks/aegon/README.md create mode 100644 frameworks/aegon/main.cpp create mode 100644 frameworks/aegon/meta.json create mode 100644 site/data/tls/aegon.json diff --git a/frameworks/aegon/CMakeLists.txt b/frameworks/aegon/CMakeLists.txt new file mode 100644 index 000000000..1be02c4a4 --- /dev/null +++ b/frameworks/aegon/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.25) +project(aegon_arena LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 26) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Aegon REQUIRED) +find_package(glaze REQUIRED) +find_package(Threads REQUIRED) + +add_executable(aegon-arena main.cpp) + +target_link_libraries(aegon-arena PRIVATE + Aegon::http + Aegon::core + Aegon::config + glaze::glaze + Threads::Threads +) diff --git a/frameworks/aegon/Dockerfile b/frameworks/aegon/Dockerfile new file mode 100644 index 000000000..011009681 --- /dev/null +++ b/frameworks/aegon/Dockerfile @@ -0,0 +1,53 @@ +FROM archlinux:latest AS build + +RUN pacman -Syu --noconfirm --needed \ + base-devel \ + cmake \ + ninja \ + git \ + liburing \ + glaze \ + openssl \ + libdeflate \ + sqlite \ + postgresql-libs + +ARG AEGON_REPO=https://github.com/UdayKhare09/Aegon.git +ARG AEGON_REF=main + +WORKDIR /src +RUN git clone --depth 1 --branch "${AEGON_REF}" "${AEGON_REPO}" aegon-src + +WORKDIR /src/aegon-src +RUN cmake -B build -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr/local && \ + cmake --build build --target aegon_core aegon_config aegon_redis aegon_memory aegon_http aegon_gateway aegon_cli -j$(nproc) && \ + cmake --install build + +WORKDIR /app +COPY CMakeLists.txt main.cpp ./ +RUN cmake -B build -G Ninja \ + -DCMAKE_BUILD_TYPE=Release && \ + cmake --build build -j$(nproc) + +FROM archlinux:latest + +RUN pacman -Syu --noconfirm --needed \ + liburing \ + openssl \ + libdeflate \ + sqlite \ + postgresql-libs \ + jemalloc && \ + pacman -Scc --noconfirm + +ENV LD_PRELOAD=/usr/lib/libjemalloc.so +ENV LD_LIBRARY_PATH=/usr/local/lib + +COPY --from=build /usr/local/lib/ /usr/local/lib/ +COPY --from=build /app/build/aegon-arena /usr/local/bin/aegon-arena + +EXPOSE 8080 8081 8443 + +CMD ["/usr/local/bin/aegon-arena"] diff --git a/frameworks/aegon/README.md b/frameworks/aegon/README.md new file mode 100644 index 000000000..31f1e60a4 --- /dev/null +++ b/frameworks/aegon/README.md @@ -0,0 +1,12 @@ +# Aegon HttpArena Entry + +[Aegon](https://github.com/UdayKhare09/Aegon) is a Linux-native C++26 asynchronous web framework powered by `io_uring` multishot primitives, coroutines, stepped SIMD vectorization, and compile-time data engines. + +## Endpoints + +- `GET /pipeline`: Plaintext response ("ok") +- `GET /baseline11` & `POST /baseline11`: Sum of query parameters + POST body +- `GET /baseline2` & `POST /baseline2`: HTTP/2 baseline endpoints +- `GET /delay/:ms`: Asynchronous non-blocking delayed response +- `GET /json/:count`: Glaze JSON serialization with libdeflate gzip compression +- `POST /echo`: 8Gbit verbatim binary echo over TLS diff --git a/frameworks/aegon/main.cpp b/frameworks/aegon/main.cpp new file mode 100644 index 000000000..f5ad0630f --- /dev/null +++ b/frameworks/aegon/main.cpp @@ -0,0 +1,206 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace aegon::http; + +namespace { + +struct Rating { + int64_t score{0}; + int64_t count{0}; +}; + +struct DatasetItem { + int64_t id{0}; + std::string name; + std::string category; + int64_t price{0}; + int64_t quantity{0}; + int64_t total{0}; + bool active{false}; + std::vector tags; + Rating rating; +}; + +struct JsonPayload { + int count{0}; + std::vector items; +}; + +std::vector g_dataset; + +void load_dataset() { + const char* env = std::getenv("DATASET_PATH"); + std::string path = env ? env : "/data/dataset.json"; + std::ifstream file(path); + if (!file) { + std::cerr << "Warning: Could not open dataset at " << path << "\n"; + return; + } + std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + auto err = glz::read(g_dataset, content); + if (err) { + std::cerr << "Warning: Failed to parse dataset: " << glz::format_error(err, content) << "\n"; + } else { + std::cout << "Loaded dataset with " << g_dataset.size() << " items\n"; + } +} + +long long parse_long(std::string_view sv) noexcept { + long long val = 0; + if (sv.empty()) return 0; + std::from_chars(sv.data(), sv.data() + sv.size(), val); + return val; +} + +long long compute_baseline_sum(const Request& req) { + long long sum = 0; + std::string_view q = req.query(); + while (!q.empty()) { + size_t amp = q.find('&'); + std::string_view pair = (amp != std::string_view::npos) ? q.substr(0, amp) : q; + size_t eq = pair.find('='); + if (eq != std::string_view::npos) { + std::string_view v = pair.substr(eq + 1); + sum += parse_long(v); + } + if (amp == std::string_view::npos) break; + q.remove_prefix(amp + 1); + } + if (req.method() == Method::POST && !req.body().empty()) { + sum += parse_long(req.body()); + } + return sum; +} + +void register_routes(Router& router) { + // 1. Pipeline endpoint + router.get("/pipeline", [](Context& ctx) { + ctx.res().text("ok"); + }); + + // 2. Baseline endpoints (HTTP/1.1) + router.get("/baseline11", [](Context& ctx) { + ctx.res().text(std::to_string(compute_baseline_sum(ctx.req()))); + }); + router.post("/baseline11", [](Context& ctx) { + ctx.res().text(std::to_string(compute_baseline_sum(ctx.req()))); + }); + + // 3. Baseline endpoints (HTTP/2) + router.get("/baseline2", [](Context& ctx) { + ctx.res().text(std::to_string(compute_baseline_sum(ctx.req()))); + }); + router.post("/baseline2", [](Context& ctx) { + ctx.res().text(std::to_string(compute_baseline_sum(ctx.req()))); + }); + + // 4. Delay endpoint (async wait) + router.get("/delay/:ms", [](Context& ctx) { + auto ms_param = ctx.req().param("ms").value_or("0"); + long long ms = parse_long(ms_param); + if (ms <= 0) { + ctx.res().text("0"); + return; + } + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + ctx.res().text(std::to_string(ms)); + }); + + // 5. JSON serialization & compression endpoint + router.get("/json/:count", [](Context& ctx) { + auto count_str = ctx.req().param("count").value_or("0"); + int count = static_cast(parse_long(count_str)); + if (count < 0) count = 0; + if (count > static_cast(g_dataset.size())) count = static_cast(g_dataset.size()); + + long long m = 1; + if (auto m_str = ctx.req().query_param("m")) { + m = parse_long(*m_str); + } + + JsonPayload payload; + payload.count = count; + payload.items.reserve(static_cast(count)); + + for (int i = 0; i < count; ++i) { + DatasetItem item = g_dataset[static_cast(i)]; + item.total = item.price * item.quantity * m; + payload.items.push_back(std::move(item)); + } + + ctx.res().json(payload); + }); + + // 6. Echo endpoint (8gbit) + router.post("/echo", [](Context& ctx) { + ctx.res().header("Content-Type", "application/octet-stream"); + ctx.res().body(std::string(ctx.req().body())); + }); +} + +} // namespace + +int main() { + load_dataset(); + + unsigned int threads = std::thread::hardware_concurrency(); + if (threads == 0) threads = 4; + + const std::string certFile = "/certs/server.crt"; + const std::string keyFile = "/certs/server.key"; + bool has_certs = std::filesystem::exists(certFile) && std::filesystem::exists(keyFile); + + std::vector server_threads; + std::unique_ptr server8081; + std::unique_ptr server8443; + + if (has_certs) { + // Port 8081: TLS HTTP/1.1 (for json-tls, 8gbit) + server8081 = std::make_unique(); + register_routes(server8081->router()); + server8081->enable_tls(certFile, keyFile); + server8081->listen(8081); + server_threads.emplace_back([&]() { + server8081->run(threads); + }); + + // Port 8443: TLS HTTP/2 (for baseline-h2) + server8443 = std::make_unique(); + register_routes(server8443->router()); + server8443->enable_tls(certFile, keyFile); + server8443->listen(8443); + server_threads.emplace_back([&]() { + server8443->run(threads); + }); + } + + // Port 8080: HTTP/1.1 (main server) + Server server8080; + server8080.use(middleware::Compress(middleware::CompressOptions{ + .min_size = 64, + .gzip = true, + .deflate = true, + .prefer_deflate = false + })); + register_routes(server8080.router()); + server8080.listen(8080); + server8080.run(threads); + + for (auto& t : server_threads) { + if (t.joinable()) t.join(); + } + + return 0; +} diff --git a/frameworks/aegon/meta.json b/frameworks/aegon/meta.json new file mode 100644 index 000000000..4c85ad4fe --- /dev/null +++ b/frameworks/aegon/meta.json @@ -0,0 +1,32 @@ +{ + "display_name": "aegon", + "language": "C++", + "type": "experimental", + "mode": "standard", + "engine": "io_uring", + "completeness": { + "routing": true, + "middleware": true, + "request": true, + "response": true + }, + "description": "Linux-native C++26 asynchronous web framework powered by io_uring multishot primitives, coroutines, stepped SIMD vectorization, and Glaze JSON serialization.", + "repo": "https://github.com/UdayKhare09/Aegon", + "enabled": true, + "tests": [ + "baseline", + "async", + "latency-1m", + "latency-10k", + "latency-500k-8cpu", + "pipelined", + "limited-conn", + "json-tls", + "json-comp", + "8gbit", + "baseline-h2" + ], + "maintainers": [ + "UdayKhare09" + ] +} diff --git a/site/data/tls/aegon.json b/site/data/tls/aegon.json new file mode 100644 index 000000000..99d985481 --- /dev/null +++ b/site/data/tls/aegon.json @@ -0,0 +1,5 @@ +{ + "framework": "aegon", + "tls": "pass", + "check": "none" +} From 6b3ed6e75a94cdd7d7a4c35a91eedd65525c760f Mon Sep 17 00:00:00 2001 From: Uday Khare Date: Tue, 22 Sep 2026 11:32:54 +0530 Subject: [PATCH 02/14] aegon: size worker count using cgroup CPU quota and affinity --- frameworks/aegon/README.md | 7 +++++ frameworks/aegon/main.cpp | 62 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/frameworks/aegon/README.md b/frameworks/aegon/README.md index 31f1e60a4..b5c0fdca3 100644 --- a/frameworks/aegon/README.md +++ b/frameworks/aegon/README.md @@ -10,3 +10,10 @@ - `GET /delay/:ms`: Asynchronous non-blocking delayed response - `GET /json/:count`: Glaze JSON serialization with libdeflate gzip compression - `POST /echo`: 8Gbit verbatim binary echo over TLS + +## Concurrency & CPU Sizing + +Worker thread allocation respects container CPU constraints: +- Evaluates cgroup v2 (`/sys/fs/cgroup/cpu.max`) and cgroup v1 CFS bandwidth quotas. +- Evaluates CPU affinity masks (`sched_getaffinity`). +- Falls back to hardware concurrency, guaranteeing at least one worker and avoiding thread over-subscription under restricted CPU quotas (e.g. `latency-500k-8cpu`). diff --git a/frameworks/aegon/main.cpp b/frameworks/aegon/main.cpp index f5ad0630f..278363377 100644 --- a/frameworks/aegon/main.cpp +++ b/frameworks/aegon/main.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include using namespace aegon::http; @@ -150,13 +152,69 @@ void register_routes(Router& router) { }); } + +unsigned int cgroup_cpus() { + unsigned int quota_limit = 0; + + // 1. cgroup v2: /sys/fs/cgroup/cpu.max contains " " or "max " + { + std::ifstream f("/sys/fs/cgroup/cpu.max"); + if (f.is_open()) { + std::string quota, period; + if (f >> quota >> period && quota != "max" && !period.empty()) { + long long q = std::strtoll(quota.c_str(), nullptr, 10); + long long p = std::strtoll(period.c_str(), nullptr, 10); + if (p > 0 && q > 0) { + quota_limit = static_cast(q / p); + } + } + } + } + + // 2. cgroup v1: /sys/fs/cgroup/cpu/cpu.cfs_quota_us and cpu.cfs_period_us + if (quota_limit == 0) { + std::ifstream qf("/sys/fs/cgroup/cpu/cpu.cfs_quota_us"); + std::ifstream pf("/sys/fs/cgroup/cpu/cpu.cfs_period_us"); + if (qf.is_open() && pf.is_open()) { + long long q = -1, p = -1; + if (qf >> q && pf >> p && q > 0 && p > 0) { + quota_limit = static_cast(q / p); + } + } + } + + // 3. CPU affinity mask (e.g. taskset or container cpuset) + unsigned int affinity_limit = 0; + cpu_set_t cs; + CPU_ZERO(&cs); + if (sched_getaffinity(0, sizeof(cs), &cs) == 0) { + int count = CPU_COUNT(&cs); + if (count > 0) { + affinity_limit = static_cast(count); + } + } + + // 4. Fallback to hardware concurrency + unsigned int hw = std::thread::hardware_concurrency(); + if (hw == 0) hw = 1; + + unsigned int effective = hw; + if (affinity_limit > 0 && affinity_limit < effective) { + effective = affinity_limit; + } + if (quota_limit > 0 && quota_limit < effective) { + effective = quota_limit; + } + + return std::max(1u, effective); +} + } // namespace int main() { load_dataset(); - unsigned int threads = std::thread::hardware_concurrency(); - if (threads == 0) threads = 4; + unsigned int threads = cgroup_cpus(); const std::string certFile = "/certs/server.crt"; const std::string keyFile = "/certs/server.key"; From 56975fa74916dca6e905750aa4e862ec47abaa1b Mon Sep 17 00:00:00 2001 From: Uday Khare Date: Tue, 22 Sep 2026 11:39:19 +0530 Subject: [PATCH 03/14] aegon: incorporate appstack zero-copy, non-blocking timer, and ring buffer tuning --- frameworks/aegon/CMakeLists.txt | 5 + frameworks/aegon/main.cpp | 213 +++++++++++++++++++++----------- 2 files changed, 143 insertions(+), 75 deletions(-) diff --git a/frameworks/aegon/CMakeLists.txt b/frameworks/aegon/CMakeLists.txt index 1be02c4a4..a71ea7117 100644 --- a/frameworks/aegon/CMakeLists.txt +++ b/frameworks/aegon/CMakeLists.txt @@ -3,6 +3,11 @@ project(aegon_arena LANGUAGES CXX) set(CMAKE_CXX_STANDARD 26) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + add_compile_options(-O3 -march=native -Wall -Wextra) +endif() find_package(Aegon REQUIRED) find_package(glaze REQUIRED) diff --git a/frameworks/aegon/main.cpp b/frameworks/aegon/main.cpp index 278363377..98c8ff3f2 100644 --- a/frameworks/aegon/main.cpp +++ b/frameworks/aegon/main.cpp @@ -1,12 +1,18 @@ #include #include +#include +#include #include #include #include +#include #include #include +#include +#include #include #include +#include #include #include #include @@ -29,61 +35,122 @@ struct DatasetItem { std::string category; int64_t price{0}; int64_t quantity{0}; - int64_t total{0}; bool active{false}; std::vector tags; Rating rating; }; +// Zero-copy view into dataset item with per-request total calculation +struct ProcessedItem { + int64_t id{0}; + std::string_view name; + std::string_view category; + int64_t price{0}; + int64_t quantity{0}; + int64_t total{0}; + bool active{false}; + std::span tags; + Rating rating; +}; + struct JsonPayload { int count{0}; - std::vector items; + std::span items; }; -std::vector g_dataset; +static std::vector g_dataset; +inline thread_local std::array tls_processed_items; + +static void load_dataset() { + std::vector paths = { + "/data/dataset.json", + "data/dataset.json", + "../data/dataset.json" + }; + + std::string content; + for (const auto& p : paths) { + std::ifstream f(p); + if (f.is_open()) { + std::ostringstream ss; + ss << f.rdbuf(); + content = ss.str(); + break; + } + } -void load_dataset() { - const char* env = std::getenv("DATASET_PATH"); - std::string path = env ? env : "/data/dataset.json"; - std::ifstream file(path); - if (!file) { - std::cerr << "Warning: Could not open dataset at " << path << "\n"; + if (content.empty()) { + std::cerr << "Warning: Could not open dataset.json" << std::endl; return; } - std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - auto err = glz::read(g_dataset, content); - if (err) { - std::cerr << "Warning: Failed to parse dataset: " << glz::format_error(err, content) << "\n"; - } else { - std::cout << "Loaded dataset with " << g_dataset.size() << " items\n"; + + auto ec = glz::read_json(g_dataset, content); + if (ec) { + std::cerr << "Failed to parse dataset.json: " << glz::format_error(ec, content) << std::endl; } } -long long parse_long(std::string_view sv) noexcept { - long long val = 0; - if (sv.empty()) return 0; - std::from_chars(sv.data(), sv.data() + sv.size(), val); - return val; +void handle_baseline_get(Context& ctx) { + int64_t sum = 0; + std::string_view q = ctx.req().query(); + while (!q.empty()) { + size_t amp = q.find('&'); + std::string_view pair = (amp != std::string_view::npos) ? q.substr(0, amp) : q; + size_t eq = pair.find('='); + if (eq != std::string_view::npos) { + int64_t val = 0; + std::from_chars(pair.data() + eq + 1, pair.data() + pair.size(), val); + sum += val; + } + if (amp == std::string_view::npos) break; + q.remove_prefix(amp + 1); + } + char buf[32]; + auto [p, _] = std::to_chars(buf, buf + sizeof(buf), sum); + ctx.res().text(std::string_view(buf, p - buf)); } -long long compute_baseline_sum(const Request& req) { - long long sum = 0; - std::string_view q = req.query(); +void handle_baseline_post(Context& ctx) { + int64_t sum = 0; + std::string_view q = ctx.req().query(); while (!q.empty()) { size_t amp = q.find('&'); std::string_view pair = (amp != std::string_view::npos) ? q.substr(0, amp) : q; size_t eq = pair.find('='); if (eq != std::string_view::npos) { - std::string_view v = pair.substr(eq + 1); - sum += parse_long(v); + int64_t val = 0; + std::from_chars(pair.data() + eq + 1, pair.data() + pair.size(), val); + sum += val; } if (amp == std::string_view::npos) break; q.remove_prefix(amp + 1); } - if (req.method() == Method::POST && !req.body().empty()) { - sum += parse_long(req.body()); + std::string_view body = ctx.req().body(); + while (!body.empty() && std::isspace(static_cast(body.front()))) body.remove_prefix(1); + while (!body.empty() && std::isspace(static_cast(body.back()))) body.remove_suffix(1); + if (!body.empty()) { + int64_t body_val = 0; + auto [ptr, ec] = std::from_chars(body.data(), body.data() + body.size(), body_val); + if (ec == std::errc()) { + sum += body_val; + } + } + char buf[32]; + auto [p, _] = std::to_chars(buf, buf + sizeof(buf), sum); + ctx.res().text(std::string_view(buf, p - buf)); +} + +aegon::core::Task handle_delay(Context& ctx) { + uint64_t ms = 0; + if (auto ms_str = ctx.req().param("ms")) { + std::from_chars(ms_str->data(), ms_str->data() + ms_str->size(), ms); + } + if (ms > 0) { + co_await aegon::core::EventLoop::current()->ring().timeout(ms * 1'000'000ULL); } - return sum; + char buf[32]; + auto [p, _] = std::to_chars(buf, buf + sizeof(buf), ms); + ctx.res().text(std::string_view(buf, p - buf)); } void register_routes(Router& router) { @@ -93,55 +160,52 @@ void register_routes(Router& router) { }); // 2. Baseline endpoints (HTTP/1.1) - router.get("/baseline11", [](Context& ctx) { - ctx.res().text(std::to_string(compute_baseline_sum(ctx.req()))); - }); - router.post("/baseline11", [](Context& ctx) { - ctx.res().text(std::to_string(compute_baseline_sum(ctx.req()))); - }); + router.get("/baseline11", handle_baseline_get); + router.post("/baseline11", handle_baseline_post); // 3. Baseline endpoints (HTTP/2) - router.get("/baseline2", [](Context& ctx) { - ctx.res().text(std::to_string(compute_baseline_sum(ctx.req()))); - }); - router.post("/baseline2", [](Context& ctx) { - ctx.res().text(std::to_string(compute_baseline_sum(ctx.req()))); - }); - - // 4. Delay endpoint (async wait) - router.get("/delay/:ms", [](Context& ctx) { - auto ms_param = ctx.req().param("ms").value_or("0"); - long long ms = parse_long(ms_param); - if (ms <= 0) { - ctx.res().text("0"); - return; - } - std::this_thread::sleep_for(std::chrono::milliseconds(ms)); - ctx.res().text(std::to_string(ms)); - }); + router.get("/baseline2", handle_baseline_get); + router.post("/baseline2", handle_baseline_post); - // 5. JSON serialization & compression endpoint - router.get("/json/:count", [](Context& ctx) { - auto count_str = ctx.req().param("count").value_or("0"); - int count = static_cast(parse_long(count_str)); - if (count < 0) count = 0; - if (count > static_cast(g_dataset.size())) count = static_cast(g_dataset.size()); + // 4. Async delay endpoint (non-blocking io_uring timeout coroutine) + router.get("/delay/:ms", handle_delay); - long long m = 1; + // 5. JSON serialization & compression endpoint (zero-copy view) + router.get("/json/:count", {aegon::http::middleware::Compress({ + .min_size = 64, + .gzip = true, + .deflate = true, + .prefer_deflate = false + })}, [](Context& ctx) { + size_t count = 0; + if (auto count_str = ctx.req().param("count")) { + std::from_chars(count_str->data(), count_str->data() + count_str->size(), count); + } + int64_t m = 1; if (auto m_str = ctx.req().query_param("m")) { - m = parse_long(*m_str); + std::from_chars(m_str->data(), m_str->data() + m_str->size(), m); } - JsonPayload payload; - payload.count = count; - payload.items.reserve(static_cast(count)); - - for (int i = 0; i < count; ++i) { - DatasetItem item = g_dataset[static_cast(i)]; - item.total = item.price * item.quantity * m; - payload.items.push_back(std::move(item)); + size_t n = std::min(count, std::min(g_dataset.size(), tls_processed_items.size())); + for (size_t i = 0; i < n; ++i) { + const auto& d = g_dataset[i]; + tls_processed_items[i] = ProcessedItem{ + .id = d.id, + .name = d.name, + .category = d.category, + .price = d.price, + .quantity = d.quantity, + .total = d.price * d.quantity * m, + .active = d.active, + .tags = std::span(d.tags.data(), d.tags.size()), + .rating = d.rating + }; } + JsonPayload payload{ + .count = static_cast(n), + .items = std::span(tls_processed_items.data(), n) + }; ctx.res().json(payload); }); @@ -152,7 +216,6 @@ void register_routes(Router& router) { }); } - unsigned int cgroup_cpus() { unsigned int quota_limit = 0; @@ -227,6 +290,8 @@ int main() { if (has_certs) { // Port 8081: TLS HTTP/1.1 (for json-tls, 8gbit) server8081 = std::make_unique(); + server8081->ring_entries(8192); + server8081->buffer_pool_entries(16384); register_routes(server8081->router()); server8081->enable_tls(certFile, keyFile); server8081->listen(8081); @@ -236,6 +301,8 @@ int main() { // Port 8443: TLS HTTP/2 (for baseline-h2) server8443 = std::make_unique(); + server8443->ring_entries(8192); + server8443->buffer_pool_entries(16384); register_routes(server8443->router()); server8443->enable_tls(certFile, keyFile); server8443->listen(8443); @@ -246,12 +313,8 @@ int main() { // Port 8080: HTTP/1.1 (main server) Server server8080; - server8080.use(middleware::Compress(middleware::CompressOptions{ - .min_size = 64, - .gzip = true, - .deflate = true, - .prefer_deflate = false - })); + server8080.ring_entries(8192); + server8080.buffer_pool_entries(16384); register_routes(server8080.router()); server8080.listen(8080); server8080.run(threads); From c5e8b642d01378b93c6975e9e92965079f574ebc Mon Sep 17 00:00:00 2001 From: Uday Khare Date: Tue, 22 Sep 2026 12:14:40 +0530 Subject: [PATCH 04/14] docs: clarify zero-copy and non-blocking timeout endpoints --- frameworks/aegon/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frameworks/aegon/README.md b/frameworks/aegon/README.md index b5c0fdca3..8663fb916 100644 --- a/frameworks/aegon/README.md +++ b/frameworks/aegon/README.md @@ -7,8 +7,8 @@ - `GET /pipeline`: Plaintext response ("ok") - `GET /baseline11` & `POST /baseline11`: Sum of query parameters + POST body - `GET /baseline2` & `POST /baseline2`: HTTP/2 baseline endpoints -- `GET /delay/:ms`: Asynchronous non-blocking delayed response -- `GET /json/:count`: Glaze JSON serialization with libdeflate gzip compression +- `GET /delay/:ms`: Non-blocking asynchronous timeout via io_uring timer coroutines +- `GET /json/:count`: Zero-copy Glaze JSON serialization with libdeflate gzip compression - `POST /echo`: 8Gbit verbatim binary echo over TLS ## Concurrency & CPU Sizing From bac186db97a5491f71fdf7af40007f62116cfe29 Mon Sep 17 00:00:00 2001 From: Uday Khare Date: Wed, 23 Sep 2026 13:41:25 +0530 Subject: [PATCH 05/14] feat: add support for HTTP/2, HTTP/3, and static file serving --- frameworks/aegon/Dockerfile | 2 +- frameworks/aegon/main.cpp | 54 +++++++++++++------------------------ frameworks/aegon/meta.json | 8 +++++- 3 files changed, 27 insertions(+), 37 deletions(-) diff --git a/frameworks/aegon/Dockerfile b/frameworks/aegon/Dockerfile index 011009681..26d65c67f 100644 --- a/frameworks/aegon/Dockerfile +++ b/frameworks/aegon/Dockerfile @@ -48,6 +48,6 @@ ENV LD_LIBRARY_PATH=/usr/local/lib COPY --from=build /usr/local/lib/ /usr/local/lib/ COPY --from=build /app/build/aegon-arena /usr/local/bin/aegon-arena -EXPOSE 8080 8081 8443 +EXPOSE 8080 8081 8082 8443 8443/udp CMD ["/usr/local/bin/aegon-arena"] diff --git a/frameworks/aegon/main.cpp b/frameworks/aegon/main.cpp index 98c8ff3f2..cd1651dfd 100644 --- a/frameworks/aegon/main.cpp +++ b/frameworks/aegon/main.cpp @@ -214,6 +214,10 @@ void register_routes(Router& router) { ctx.res().header("Content-Type", "application/octet-stream"); ctx.res().body(std::string(ctx.req().body())); }); + + // 7. Static file serving (static-h2, static-h3) - Aegon core static_files API + const char* static_dir = std::filesystem::exists("/data/static") ? "/data/static" : "data/static"; + router.static_files("/static", static_dir); } unsigned int cgroup_cpus() { @@ -283,45 +287,25 @@ int main() { const std::string keyFile = "/certs/server.key"; bool has_certs = std::filesystem::exists(certFile) && std::filesystem::exists(keyFile); - std::vector server_threads; - std::unique_ptr server8081; - std::unique_ptr server8443; + Server server; + server.ring_entries(8192); + server.buffer_pool_entries(16384); + register_routes(server.router()); + + // Port 8080: Plaintext HTTP/1.1 (main benchmarks) + server.listen(8080); + // Port 8082: Plaintext HTTP/2 prior-knowledge (baseline-h2c, json-h2c) + server.listen(8082); if (has_certs) { - // Port 8081: TLS HTTP/1.1 (for json-tls, 8gbit) - server8081 = std::make_unique(); - server8081->ring_entries(8192); - server8081->buffer_pool_entries(16384); - register_routes(server8081->router()); - server8081->enable_tls(certFile, keyFile); - server8081->listen(8081); - server_threads.emplace_back([&]() { - server8081->run(threads); - }); - - // Port 8443: TLS HTTP/2 (for baseline-h2) - server8443 = std::make_unique(); - server8443->ring_entries(8192); - server8443->buffer_pool_entries(16384); - register_routes(server8443->router()); - server8443->enable_tls(certFile, keyFile); - server8443->listen(8443); - server_threads.emplace_back([&]() { - server8443->run(threads); - }); + server.enable_tls(certFile, keyFile); + // Port 8081: TLS HTTP/1.1 (json-tls, 8gbit) + server.listen_tls(8081); + // Port 8443: TLS HTTP/2 (baseline-h2) + server.listen_tls(8443); } - // Port 8080: HTTP/1.1 (main server) - Server server8080; - server8080.ring_entries(8192); - server8080.buffer_pool_entries(16384); - register_routes(server8080.router()); - server8080.listen(8080); - server8080.run(threads); - - for (auto& t : server_threads) { - if (t.joinable()) t.join(); - } + server.run(threads); return 0; } diff --git a/frameworks/aegon/meta.json b/frameworks/aegon/meta.json index 4c85ad4fe..5ced241bc 100644 --- a/frameworks/aegon/meta.json +++ b/frameworks/aegon/meta.json @@ -24,7 +24,13 @@ "json-tls", "json-comp", "8gbit", - "baseline-h2" + "static-tls", + "baseline-h2", + "baseline-h2c", + "json-h2c", + "static-h2", + "baseline-h3", + "static-h3" ], "maintainers": [ "UdayKhare09" From 7b2e9ea7ee013b3300e16637e157bad0ed7f11fa Mon Sep 17 00:00:00 2001 From: Uday Khare Date: Wed, 23 Sep 2026 19:48:28 +0530 Subject: [PATCH 06/14] docs: update aegon README and pin commit hash in Dockerfile --- frameworks/aegon/Dockerfile | 4 ++- frameworks/aegon/README.md | 49 ++++++++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/frameworks/aegon/Dockerfile b/frameworks/aegon/Dockerfile index 26d65c67f..813b83efe 100644 --- a/frameworks/aegon/Dockerfile +++ b/frameworks/aegon/Dockerfile @@ -14,9 +14,11 @@ RUN pacman -Syu --noconfirm --needed \ ARG AEGON_REPO=https://github.com/UdayKhare09/Aegon.git ARG AEGON_REF=main +ARG AEGON_COMMIT=449d73d WORKDIR /src -RUN git clone --depth 1 --branch "${AEGON_REF}" "${AEGON_REPO}" aegon-src +RUN echo "Building Aegon commit: ${AEGON_COMMIT}" && \ + git clone --depth 1 --branch "${AEGON_REF}" "${AEGON_REPO}" aegon-src WORKDIR /src/aegon-src RUN cmake -B build -G Ninja \ diff --git a/frameworks/aegon/README.md b/frameworks/aegon/README.md index 8663fb916..eedcd542f 100644 --- a/frameworks/aegon/README.md +++ b/frameworks/aegon/README.md @@ -1,19 +1,50 @@ -# Aegon HttpArena Entry +# aegon [Aegon](https://github.com/UdayKhare09/Aegon) is a Linux-native C++26 asynchronous web framework powered by `io_uring` multishot primitives, coroutines, stepped SIMD vectorization, and compile-time data engines. +## Stack + +- **Language:** C++26 (GCC 14) +- **Engine:** Linux `io_uring` multishot accept/recv, provided buffer rings +- **Serialization:** Glaze (compile-time reflection, zero-copy JSON) +- **Compression:** `libdeflate` gzip/deflate streaming middleware +- **Crypto & TLS:** OpenSSL with ALPN (`h2`, `http/1.1`) +- **Build:** CMake with Ninja on Arch Linux + ## Endpoints -- `GET /pipeline`: Plaintext response ("ok") -- `GET /baseline11` & `POST /baseline11`: Sum of query parameters + POST body -- `GET /baseline2` & `POST /baseline2`: HTTP/2 baseline endpoints -- `GET /delay/:ms`: Non-blocking asynchronous timeout via io_uring timer coroutines -- `GET /json/:count`: Zero-copy Glaze JSON serialization with libdeflate gzip compression -- `POST /echo`: 8Gbit verbatim binary echo over TLS +| Endpoint | Method | Protocol | Description | +|---|---|---|---| +| `/pipeline` | GET | HTTP/1.1 | Pipelined plaintext response (`ok`) | +| `/baseline11` | GET | HTTP/1.1 | Fast query string parameter summation | +| `/baseline11` | POST | HTTP/1.1 | Sums query parameters and request body | +| `/baseline2` | GET | HTTP/2 | Baseline query summation over HTTP/2 | +| `/baseline2` | POST | HTTP/2 | Baseline query + body summation over HTTP/2 | +| `/delay/:ms` | GET | HTTP/1.1 | Non-blocking asynchronous delay via `io_uring` timer coroutine | +| `/json/:count?m=N` | GET | HTTP/1.1 & HTTP/2 | Zero-copy Glaze JSON serialization with `libdeflate` compression | +| `/echo` | POST | TLS | 8Gbit verbatim binary stream echo | +| `/static/*` | GET | TLS & HTTP/2 | High-throughput static file delivery via `router.static_files` | + +## Ports & Protocols + +Aegon runs concurrent multi-port listeners with protocol multiplexing: + +- **Port 8080 (HTTP/1.1 Plaintext):** Primary plaintext benchmark port (`baseline`, `async`, `latency-*`, `pipelined`, `limited-conn`). +- **Port 8082 (HTTP/2 Cleartext / Prior Knowledge):** `h2c` benchmarking (`baseline-h2c`, `json-h2c`). +- **Port 8081 (HTTP/1.1 TLS):** Secure HTTP/1.1 workloads (`json-tls`, `8gbit`). +- **Port 8443 (HTTP/2 TLS):** Secure HTTP/2 workloads (`baseline-h2`, `static-h2`). + +## Completeness & Features + +Aegon qualifies for 4/4 Completeness (100%, multiplier ×1.00): +- **Routing:** Parameterized path matching (`:ms`, `:count`), static prefix tree matching (`/static/*`). +- **Middleware:** Composable request/response middleware chain with streaming compression (`Compress`). +- **Request:** Zero-copy URI decoding, query parsing, header lookup, route params, body handling. +- **Response:** Fluent response builder, custom status codes, headers, streaming, and direct Glaze JSON serialization. ## Concurrency & CPU Sizing -Worker thread allocation respects container CPU constraints: +Worker thread allocation dynamically inspects container resource constraints: - Evaluates cgroup v2 (`/sys/fs/cgroup/cpu.max`) and cgroup v1 CFS bandwidth quotas. - Evaluates CPU affinity masks (`sched_getaffinity`). -- Falls back to hardware concurrency, guaranteeing at least one worker and avoiding thread over-subscription under restricted CPU quotas (e.g. `latency-500k-8cpu`). +- Falls back to hardware concurrency, guaranteeing at least one worker and avoiding thread over-subscription under restricted CPU quotas (e.g., `latency-500k-8cpu`). From 832c17ccf1d5b36345f0f37a097ffcb57ca84d00 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 23 Sep 2026 16:57:12 +0000 Subject: [PATCH 07/14] Benchmark results: aegon [skip ci] --- site/data/frameworks.json | 14 + site/data/results/aegon.json | 468 ++++++++++++++++++ site/static/logs/8gbit/512/aegon.log | 0 site/static/logs/async/32000/aegon.log | 0 site/static/logs/baseline-h2/1024/aegon.log | 0 site/static/logs/baseline-h2/256/aegon.log | 0 site/static/logs/baseline-h2c/1024/aegon.log | 0 site/static/logs/baseline-h2c/256/aegon.log | 0 site/static/logs/baseline-h2c/4096/aegon.log | 0 site/static/logs/baseline-h3/64/aegon.log | 0 site/static/logs/baseline/4096/aegon.log | 0 site/static/logs/json-comp/16384/aegon.log | 0 site/static/logs/json-comp/4096/aegon.log | 0 site/static/logs/json-h2c/1024/aegon.log | 0 site/static/logs/json-h2c/4096/aegon.log | 0 site/static/logs/json-tls/4096/aegon.log | 0 site/static/logs/latency-10k/1024/aegon.log | 0 site/static/logs/latency-1m/1024/aegon.log | 0 .../logs/latency-500k-8cpu/1024/aegon.log | 0 site/static/logs/limited-conn/4096/aegon.log | 0 site/static/logs/pipelined/4096/aegon.log | 0 site/static/logs/static-h2/1024/aegon.log | 0 site/static/logs/static-h2/256/aegon.log | 0 site/static/logs/static-h3/64/aegon.log | 0 site/static/logs/static-tls/1024/aegon.log | 0 25 files changed, 482 insertions(+) create mode 100644 site/data/results/aegon.json create mode 100644 site/static/logs/8gbit/512/aegon.log create mode 100644 site/static/logs/async/32000/aegon.log create mode 100644 site/static/logs/baseline-h2/1024/aegon.log create mode 100644 site/static/logs/baseline-h2/256/aegon.log create mode 100644 site/static/logs/baseline-h2c/1024/aegon.log create mode 100644 site/static/logs/baseline-h2c/256/aegon.log create mode 100644 site/static/logs/baseline-h2c/4096/aegon.log create mode 100644 site/static/logs/baseline-h3/64/aegon.log create mode 100644 site/static/logs/baseline/4096/aegon.log create mode 100644 site/static/logs/json-comp/16384/aegon.log create mode 100644 site/static/logs/json-comp/4096/aegon.log create mode 100644 site/static/logs/json-h2c/1024/aegon.log create mode 100644 site/static/logs/json-h2c/4096/aegon.log create mode 100644 site/static/logs/json-tls/4096/aegon.log create mode 100644 site/static/logs/latency-10k/1024/aegon.log create mode 100644 site/static/logs/latency-1m/1024/aegon.log create mode 100644 site/static/logs/latency-500k-8cpu/1024/aegon.log create mode 100644 site/static/logs/limited-conn/4096/aegon.log create mode 100644 site/static/logs/pipelined/4096/aegon.log create mode 100644 site/static/logs/static-h2/1024/aegon.log create mode 100644 site/static/logs/static-h2/256/aegon.log create mode 100644 site/static/logs/static-h3/64/aegon.log create mode 100644 site/static/logs/static-tls/1024/aegon.log diff --git a/site/data/frameworks.json b/site/data/frameworks.json index ac6f14311..5bd111ed8 100644 --- a/site/data/frameworks.json +++ b/site/data/frameworks.json @@ -37,6 +37,20 @@ } ] }, + "aegon": { + "dir": "aegon", + "description": "Linux-native C++26 asynchronous web framework powered by io_uring multishot primitives, coroutines, stepped SIMD vectorization, and Glaze JSON serialization.", + "repo": "https://github.com/UdayKhare09/Aegon", + "type": "experimental", + "engine": "io_uring", + "mode": "standard", + "completeness": { + "routing": true, + "middleware": true, + "request": true, + "response": true + } + }, "aiohttp": { "dir": "aiohttp", "description": "aiohttp 3.14 web server on uvloop, one forked worker per core sharing the port with SO_REUSEPORT. Routing through the aiohttp router, JSON through web.json_response, gzip through the built-in response compression.", diff --git a/site/data/results/aegon.json b/site/data/results/aegon.json new file mode 100644 index 000000000..65a7f0fdf --- /dev/null +++ b/site/data/results/aegon.json @@ -0,0 +1,468 @@ +{ + "framework": "aegon", + "results": { + "8gbit-512": { + "framework": "aegon", + "language": "C++", + "rps": 49364, + "avg_latency": "114.7us", + "p99_latency": "168.0us", + "cpu": "306.2%", + "memory": "4.3GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "512.15MB/s", + "input_bw": "482.07MB/s", + "reconnects": 0, + "status_2xx": 246888, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0, + "cpu_usec": 16845081, + "cpu_per_req_us": 68.2296, + "target_rate": 50000, + "rate_ratio": 0.9873, + "p99_9_latency": "2695.0us" + }, + "async-32000": { + "framework": "aegon", + "language": "C++", + "rps": 1816143, + "avg_latency": "17.50ms", + "p99_latency": "19.90ms", + "cpu": "3468.5%", + "memory": "4.6GiB", + "connections": 32000, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "114.29MB/s", + "input_bw": "83.14MB/s", + "reconnects": 0, + "status_2xx": 18161433, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "baseline-4096": { + "framework": "aegon", + "language": "C++", + "rps": 4277881, + "avg_latency": "957us", + "p99_latency": "1.32ms", + "cpu": "6445.5%", + "memory": "4.2GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "269.13MB/s", + "input_bw": "330.46MB/s", + "reconnects": 0, + "status_2xx": 21389407, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "baseline-h2-1024": { + "framework": "aegon", + "language": "C++", + "rps": 14797722, + "avg_latency": "3.62ms", + "p99_latency": "93.48ms", + "cpu": "4706.9%", + "memory": "4.3GiB", + "connections": 1024, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "370.60MB/s", + "reconnects": 0, + "status_2xx": 74728500, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "baseline-h2-256": { + "framework": "aegon", + "language": "C++", + "rps": 14486023, + "avg_latency": "1.17ms", + "p99_latency": "14.68ms", + "cpu": "4371.7%", + "memory": "4.2GiB", + "connections": 256, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "361.35MB/s", + "reconnects": 0, + "status_2xx": 72864700, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "baseline-h2c-1024": { + "framework": "aegon", + "language": "C++", + "rps": 15788772, + "avg_latency": "3.34ms", + "p99_latency": "11.46ms", + "cpu": "4264.9%", + "memory": "4.2GiB", + "connections": 1024, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "380.21MB/s", + "reconnects": 0, + "status_2xx": 79733300, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "baseline-h2c-256": { + "framework": "aegon", + "language": "C++", + "rps": 14893439, + "avg_latency": "1.03ms", + "p99_latency": "7.14ms", + "cpu": "3824.6%", + "memory": "4.2GiB", + "connections": 256, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "357.22MB/s", + "reconnects": 0, + "status_2xx": 74914000, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "baseline-h2c-4096": { + "framework": "aegon", + "language": "C++", + "rps": 14888196, + "avg_latency": "14.07ms", + "p99_latency": "46.51ms", + "cpu": "4045.5%", + "memory": "4.3GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "362.09MB/s", + "reconnects": 0, + "status_2xx": 75929800, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "baseline-h3-64": { + "framework": "aegon", + "language": "C++", + "rps": 3344869, + "avg_latency": "1.43ms", + "p99_latency": "3.06ms", + "cpu": "3729.3%", + "memory": "4.2GiB", + "connections": 64, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "51.09MB/s", + "reconnects": 0, + "status_2xx": 16757797, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "json-comp-16384": { + "framework": "aegon", + "language": "C++", + "rps": 956083, + "avg_latency": "17.01ms", + "p99_latency": "23.60ms", + "cpu": "6442.4%", + "memory": "4.5GiB", + "connections": 16384, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "1.34GB/s", + "input_bw": "71.12MB/s", + "reconnects": 183334, + "status_2xx": 4780418, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "json-comp-4096": { + "framework": "aegon", + "language": "C++", + "rps": 981679, + "avg_latency": "4.13ms", + "p99_latency": "8.86ms", + "cpu": "6717.7%", + "memory": "4.3GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "1.37GB/s", + "input_bw": "73.02MB/s", + "reconnects": 195842, + "status_2xx": 4908395, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "json-h2c-1024": { + "framework": "aegon", + "language": "C++", + "rps": 3675222, + "avg_latency": "8.43ms", + "p99_latency": "23.15ms", + "cpu": "6591.2%", + "memory": "4.5GiB", + "connections": 1024, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "12.30GB/s", + "reconnects": 0, + "status_2xx": 18633380, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "json-h2c-4096": { + "framework": "aegon", + "language": "C++", + "rps": 3094589, + "avg_latency": "40.94ms", + "p99_latency": "96.85ms", + "cpu": "6523.6%", + "memory": "5.7GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "10.41GB/s", + "reconnects": 0, + "status_2xx": 15782406, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "json-tls-4096": { + "framework": "aegon", + "language": "C++", + "rps": 1342139, + "avg_latency": "2.99ms", + "p99_latency": "62.00ms", + "cpu": "6570.8%", + "memory": "4.8GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "4.56GB", + "reconnects": 0, + "status_2xx": 6845772, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "latency-10k-1024": { + "framework": "aegon", + "language": "C++", + "rps": 9982, + "avg_latency": "69.4us", + "p99_latency": "97.0us", + "cpu": "28.6%", + "memory": "4.1GiB", + "connections": 1024, + "threads": 64, + "duration": "20s", + "pipeline": 1, + "bandwidth": "0.65MB/s", + "reconnects": 0, + "status_2xx": 199667, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0, + "cpu_usec": 5994365, + "cpu_per_req_us": 30.0218, + "target_rate": 10000, + "rate_ratio": 0.9982, + "p99_9_latency": "508.0us" + }, + "latency-1m-1024": { + "framework": "aegon", + "language": "C++", + "rps": 997968, + "avg_latency": "92.7us", + "p99_latency": "159.0us", + "cpu": "2309.7%", + "memory": "4.1GiB", + "connections": 1024, + "threads": 64, + "duration": "20s", + "pipeline": 1, + "bandwidth": "64.87MB/s", + "reconnects": 0, + "status_2xx": 19962735, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0, + "cpu_usec": 421151167, + "cpu_per_req_us": 21.0969, + "target_rate": 1000000, + "rate_ratio": 0.998, + "p99_9_latency": "4986.0us" + }, + "latency-500k-8cpu-1024": { + "framework": "aegon", + "language": "C++", + "rps": 496457, + "avg_latency": "47922.9us", + "p99_latency": "636672.0us", + "cpu": "839.1%", + "memory": "555MiB", + "connections": 1024, + "threads": 64, + "duration": "20s", + "pipeline": 1, + "bandwidth": "32.27MB/s", + "reconnects": 0, + "status_2xx": 9931077, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0, + "cpu_usec": 158832936, + "cpu_per_req_us": 15.9935, + "target_rate": 500000, + "rate_ratio": 0.9929, + "p99_9_latency": "685824.0us" + }, + "limited-conn-4096": { + "framework": "aegon", + "language": "C++", + "rps": 2647150, + "avg_latency": "1.41ms", + "p99_latency": "1.92ms", + "cpu": "6044.0%", + "memory": "4.2GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "166.55MB/s", + "input_bw": "204.49MB/s", + "reconnects": 1324519, + "status_2xx": 13235752, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "pipelined-4096": { + "framework": "aegon", + "language": "C++", + "rps": 43600880, + "avg_latency": "1.50ms", + "p99_latency": "2.06ms", + "cpu": "6629.1%", + "memory": "4.2GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 16, + "bandwidth": "2.68GB/s", + "reconnects": 0, + "status_2xx": 218004401, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "static-h2-1024": { + "framework": "aegon", + "language": "C++", + "rps": 562094, + "avg_latency": "33.18ms", + "p99_latency": "98.75ms", + "cpu": "5965.9%", + "memory": "4.6GiB", + "connections": 1024, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "8.62GB/s", + "reconnects": 0, + "status_2xx": 2849819, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "static-h2-256": { + "framework": "aegon", + "language": "C++", + "rps": 525553, + "avg_latency": "13.34ms", + "p99_latency": "38.02ms", + "cpu": "5979.7%", + "memory": "4.3GiB", + "connections": 256, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "8.02GB/s", + "reconnects": 0, + "status_2xx": 2643534, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "static-h3-64": { + "framework": "aegon", + "language": "C++", + "rps": 351724, + "avg_latency": "13.76ms", + "p99_latency": "37.79ms", + "cpu": "4888.4%", + "memory": "4.3GiB", + "connections": 64, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "5.35GB/s", + "reconnects": 0, + "status_2xx": 1762139, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "static-tls-1024": { + "framework": "aegon", + "language": "C++", + "rps": 536131, + "avg_latency": "2.14ms", + "p99_latency": "29.28ms", + "cpu": "6785.7%", + "memory": "4.6GiB", + "connections": 1024, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "8.20GB", + "reconnects": 0, + "status_2xx": 2734466, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + } + } +} diff --git a/site/static/logs/8gbit/512/aegon.log b/site/static/logs/8gbit/512/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/async/32000/aegon.log b/site/static/logs/async/32000/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/baseline-h2/1024/aegon.log b/site/static/logs/baseline-h2/1024/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/baseline-h2/256/aegon.log b/site/static/logs/baseline-h2/256/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/baseline-h2c/1024/aegon.log b/site/static/logs/baseline-h2c/1024/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/baseline-h2c/256/aegon.log b/site/static/logs/baseline-h2c/256/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/baseline-h2c/4096/aegon.log b/site/static/logs/baseline-h2c/4096/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/baseline-h3/64/aegon.log b/site/static/logs/baseline-h3/64/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/baseline/4096/aegon.log b/site/static/logs/baseline/4096/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/json-comp/16384/aegon.log b/site/static/logs/json-comp/16384/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/json-comp/4096/aegon.log b/site/static/logs/json-comp/4096/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/json-h2c/1024/aegon.log b/site/static/logs/json-h2c/1024/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/json-h2c/4096/aegon.log b/site/static/logs/json-h2c/4096/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/json-tls/4096/aegon.log b/site/static/logs/json-tls/4096/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/latency-10k/1024/aegon.log b/site/static/logs/latency-10k/1024/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/latency-1m/1024/aegon.log b/site/static/logs/latency-1m/1024/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/latency-500k-8cpu/1024/aegon.log b/site/static/logs/latency-500k-8cpu/1024/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/limited-conn/4096/aegon.log b/site/static/logs/limited-conn/4096/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/pipelined/4096/aegon.log b/site/static/logs/pipelined/4096/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/static-h2/1024/aegon.log b/site/static/logs/static-h2/1024/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/static-h2/256/aegon.log b/site/static/logs/static-h2/256/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/static-h3/64/aegon.log b/site/static/logs/static-h3/64/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/static-tls/1024/aegon.log b/site/static/logs/static-tls/1024/aegon.log new file mode 100644 index 000000000..e69de29bb From 4b34315905e95150015518ec1393def004c26695 Mon Sep 17 00:00:00 2001 From: Uday Khare Date: Wed, 23 Sep 2026 22:58:24 +0530 Subject: [PATCH 08/14] feat: integrate WebSocket support, update Aegon framework commit, and add echo-ws benchmarks --- frameworks/aegon/Dockerfile | 2 +- frameworks/aegon/README.md | 10 ++++++---- frameworks/aegon/main.cpp | 19 +++++++++++++++++-- frameworks/aegon/meta.json | 7 +++++-- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/frameworks/aegon/Dockerfile b/frameworks/aegon/Dockerfile index 813b83efe..92f749057 100644 --- a/frameworks/aegon/Dockerfile +++ b/frameworks/aegon/Dockerfile @@ -14,7 +14,7 @@ RUN pacman -Syu --noconfirm --needed \ ARG AEGON_REPO=https://github.com/UdayKhare09/Aegon.git ARG AEGON_REF=main -ARG AEGON_COMMIT=449d73d +ARG AEGON_COMMIT=790c8b5 WORKDIR /src RUN echo "Building Aegon commit: ${AEGON_COMMIT}" && \ diff --git a/frameworks/aegon/README.md b/frameworks/aegon/README.md index eedcd542f..5c01ee2f3 100644 --- a/frameworks/aegon/README.md +++ b/frameworks/aegon/README.md @@ -9,6 +9,7 @@ - **Serialization:** Glaze (compile-time reflection, zero-copy JSON) - **Compression:** `libdeflate` gzip/deflate streaming middleware - **Crypto & TLS:** OpenSSL with ALPN (`h2`, `http/1.1`) +- **WebSocket:** RFC 6455 frame parser with AVX2 SIMD payload unmasking and fast-path batched echo engine - **Build:** CMake with Ninja on Arch Linux ## Endpoints @@ -23,21 +24,22 @@ | `/delay/:ms` | GET | HTTP/1.1 | Non-blocking asynchronous delay via `io_uring` timer coroutine | | `/json/:count?m=N` | GET | HTTP/1.1 & HTTP/2 | Zero-copy Glaze JSON serialization with `libdeflate` compression | | `/echo` | POST | TLS | 8Gbit verbatim binary stream echo | -| `/static/*` | GET | TLS & HTTP/2 | High-throughput static file delivery via `router.static_files` | +| `/static/*` | GET | TLS, HTTP/2 & HTTP/3 | High-throughput static file delivery via `router.static_files` | +| `/ws` | Upgrade | HTTP/1.1 (RFC 6455) | Full-duplex WebSocket echo with SIMD unmasking and `io_uring` batching | ## Ports & Protocols Aegon runs concurrent multi-port listeners with protocol multiplexing: -- **Port 8080 (HTTP/1.1 Plaintext):** Primary plaintext benchmark port (`baseline`, `async`, `latency-*`, `pipelined`, `limited-conn`). +- **Port 8080 (HTTP/1.1 Plaintext & WebSocket):** Primary plaintext and WebSocket benchmark port (`baseline`, `async`, `latency-*`, `pipelined`, `limited-conn`, `echo-ws`, `echo-ws-pipeline`, `echo-ws-limited`). - **Port 8082 (HTTP/2 Cleartext / Prior Knowledge):** `h2c` benchmarking (`baseline-h2c`, `json-h2c`). - **Port 8081 (HTTP/1.1 TLS):** Secure HTTP/1.1 workloads (`json-tls`, `8gbit`). -- **Port 8443 (HTTP/2 TLS):** Secure HTTP/2 workloads (`baseline-h2`, `static-h2`). +- **Port 8443 (HTTP/2 TLS & HTTP/3 QUIC / UDP):** Secure HTTP/2 and HTTP/3 workloads (`baseline-h2`, `static-h2`, `baseline-h3`, `static-h3`). ## Completeness & Features Aegon qualifies for 4/4 Completeness (100%, multiplier ×1.00): -- **Routing:** Parameterized path matching (`:ms`, `:count`), static prefix tree matching (`/static/*`). +- **Routing:** Parameterized path matching (`:ms`, `:count`), static prefix tree matching (`/static/*`), RFC 6455 WebSocket routes (`/ws`) with automatic `426 Upgrade Required` fallback. - **Middleware:** Composable request/response middleware chain with streaming compression (`Compress`). - **Request:** Zero-copy URI decoding, query parsing, header lookup, route params, body handling. - **Response:** Fluent response builder, custom status codes, headers, streaming, and direct Glaze JSON serialization. diff --git a/frameworks/aegon/main.cpp b/frameworks/aegon/main.cpp index cd1651dfd..f91b1adf7 100644 --- a/frameworks/aegon/main.cpp +++ b/frameworks/aegon/main.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -218,6 +219,9 @@ void register_routes(Router& router) { // 7. Static file serving (static-h2, static-h3) - Aegon core static_files API const char* static_dir = std::filesystem::exists("/data/static") ? "/data/static" : "data/static"; router.static_files("/static", static_dir); + + // 8. WebSocket Echo endpoint + router.ws("/ws"); } unsigned int cgroup_cpus() { @@ -287,9 +291,20 @@ int main() { const std::string keyFile = "/certs/server.key"; bool has_certs = std::filesystem::exists(certFile) && std::filesystem::exists(keyFile); + struct rlimit rl{}; + bool low_memlock = false; + if (getrlimit(RLIMIT_MEMLOCK, &rl) == 0 && rl.rlim_cur != RLIM_INFINITY && rl.rlim_cur < 64 * 1024 * 1024) { + low_memlock = true; + } + Server server; - server.ring_entries(8192); - server.buffer_pool_entries(16384); + if (low_memlock) { + server.ring_entries(512); + server.buffer_pool_entries(256); + } else { + server.ring_entries(8192); + server.buffer_pool_entries(16384); + } register_routes(server.router()); // Port 8080: Plaintext HTTP/1.1 (main benchmarks) diff --git a/frameworks/aegon/meta.json b/frameworks/aegon/meta.json index 5ced241bc..dc6ab96ad 100644 --- a/frameworks/aegon/meta.json +++ b/frameworks/aegon/meta.json @@ -30,9 +30,12 @@ "json-h2c", "static-h2", "baseline-h3", - "static-h3" + "static-h3", + "echo-ws", + "echo-ws-pipeline", + "echo-ws-limited" ], "maintainers": [ "UdayKhare09" ] -} +} \ No newline at end of file From a8d75e94b34f3b37c3bb5b888f1974f0f68d9643 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 23 Sep 2026 19:29:11 +0000 Subject: [PATCH 09/14] Benchmark results: aegon [skip ci] --- site/data/frameworks.json | 2 +- site/data/results/aegon.json | 488 ++++++++++++------ .../logs/echo-ws-limited/4096/aegon.log | 0 .../static/logs/echo-ws-limited/512/aegon.log | 0 .../logs/echo-ws-pipeline/16384/aegon.log | 0 .../logs/echo-ws-pipeline/4096/aegon.log | 0 .../logs/echo-ws-pipeline/512/aegon.log | 0 site/static/logs/echo-ws/16384/aegon.log | 0 site/static/logs/echo-ws/4096/aegon.log | 0 site/static/logs/echo-ws/512/aegon.log | 0 10 files changed, 321 insertions(+), 169 deletions(-) create mode 100644 site/static/logs/echo-ws-limited/4096/aegon.log create mode 100644 site/static/logs/echo-ws-limited/512/aegon.log create mode 100644 site/static/logs/echo-ws-pipeline/16384/aegon.log create mode 100644 site/static/logs/echo-ws-pipeline/4096/aegon.log create mode 100644 site/static/logs/echo-ws-pipeline/512/aegon.log create mode 100644 site/static/logs/echo-ws/16384/aegon.log create mode 100644 site/static/logs/echo-ws/4096/aegon.log create mode 100644 site/static/logs/echo-ws/512/aegon.log diff --git a/site/data/frameworks.json b/site/data/frameworks.json index 5bd111ed8..775fb724e 100644 --- a/site/data/frameworks.json +++ b/site/data/frameworks.json @@ -1264,7 +1264,7 @@ "dir": "nilo", "description": "A toolkit for Zig 0.16 whose largest module is an HTTP/1.1 server on zio fibers (io_uring, epoll, kqueue). A plain function is a route: its argument list is the routing, the typed input, the 400 for anything that does not fit, and the OpenAPI document. One allocation per request, 4,669 bytes per idle connection, and a wait parks the fiber rather than the thread. Serves cleartext on 8080 and TLS 1.3 on 8081 from one process. Refuses HTTP/2, HTTP/3, gRPC and templates on the record, which is why it sits out those profiles.", "repo": "https://github.com/nevindra/nilo", - "type": "emerging", + "type": "experimental", "engine": "nilo_http on zio", "mode": "standard", "completeness": { diff --git a/site/data/results/aegon.json b/site/data/results/aegon.json index 65a7f0fdf..40e96bd80 100644 --- a/site/data/results/aegon.json +++ b/site/data/results/aegon.json @@ -4,44 +4,44 @@ "8gbit-512": { "framework": "aegon", "language": "C++", - "rps": 49364, - "avg_latency": "114.7us", - "p99_latency": "168.0us", - "cpu": "306.2%", - "memory": "4.3GiB", + "rps": 49360, + "avg_latency": "119.6us", + "p99_latency": "170.0us", + "cpu": "315.1%", + "memory": "4.2GiB", "connections": 512, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "512.15MB/s", - "input_bw": "482.07MB/s", + "bandwidth": "512.11MB/s", + "input_bw": "482.03MB/s", "reconnects": 0, - "status_2xx": 246888, + "status_2xx": 246870, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0, - "cpu_usec": 16845081, - "cpu_per_req_us": 68.2296, + "cpu_usec": 17256110, + "cpu_per_req_us": 69.8996, "target_rate": 50000, - "rate_ratio": 0.9873, - "p99_9_latency": "2695.0us" + "rate_ratio": 0.9872, + "p99_9_latency": "3921.0us" }, "async-32000": { "framework": "aegon", "language": "C++", - "rps": 1816143, + "rps": 1816298, "avg_latency": "17.50ms", - "p99_latency": "19.90ms", - "cpu": "3468.5%", + "p99_latency": "19.80ms", + "cpu": "3430.1%", "memory": "4.6GiB", "connections": 32000, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "114.29MB/s", + "bandwidth": "114.30MB/s", "input_bw": "83.14MB/s", "reconnects": 0, - "status_2xx": 18161433, + "status_2xx": 18162984, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -49,19 +49,19 @@ "baseline-4096": { "framework": "aegon", "language": "C++", - "rps": 4277881, - "avg_latency": "957us", - "p99_latency": "1.32ms", - "cpu": "6445.5%", + "rps": 4231339, + "avg_latency": "973us", + "p99_latency": "1.46ms", + "cpu": "6184.5%", "memory": "4.2GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "269.13MB/s", - "input_bw": "330.46MB/s", + "bandwidth": "266.26MB/s", + "input_bw": "326.86MB/s", "reconnects": 0, - "status_2xx": 21389407, + "status_2xx": 21156695, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -69,18 +69,18 @@ "baseline-h2-1024": { "framework": "aegon", "language": "C++", - "rps": 14797722, - "avg_latency": "3.62ms", - "p99_latency": "93.48ms", - "cpu": "4706.9%", + "rps": 14496356, + "avg_latency": "3.63ms", + "p99_latency": "96.67ms", + "cpu": "4690.4%", "memory": "4.3GiB", "connections": 1024, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "370.60MB/s", + "bandwidth": "363.05MB/s", "reconnects": 0, - "status_2xx": 74728500, + "status_2xx": 73206600, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -88,18 +88,18 @@ "baseline-h2-256": { "framework": "aegon", "language": "C++", - "rps": 14486023, - "avg_latency": "1.17ms", - "p99_latency": "14.68ms", - "cpu": "4371.7%", + "rps": 14543836, + "avg_latency": "1.13ms", + "p99_latency": "7.29ms", + "cpu": "4512.5%", "memory": "4.2GiB", "connections": 256, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "361.35MB/s", + "bandwidth": "362.79MB/s", "reconnects": 0, - "status_2xx": 72864700, + "status_2xx": 73155500, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -107,18 +107,18 @@ "baseline-h2c-1024": { "framework": "aegon", "language": "C++", - "rps": 15788772, - "avg_latency": "3.34ms", - "p99_latency": "11.46ms", - "cpu": "4264.9%", + "rps": 15706739, + "avg_latency": "3.37ms", + "p99_latency": "15.29ms", + "cpu": "4308.3%", "memory": "4.2GiB", "connections": 1024, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "380.21MB/s", + "bandwidth": "378.98MB/s", "reconnects": 0, - "status_2xx": 79733300, + "status_2xx": 79476100, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -126,18 +126,18 @@ "baseline-h2c-256": { "framework": "aegon", "language": "C++", - "rps": 14893439, - "avg_latency": "1.03ms", - "p99_latency": "7.14ms", - "cpu": "3824.6%", + "rps": 14653976, + "avg_latency": "1.04ms", + "p99_latency": "6.88ms", + "cpu": "3988.5%", "memory": "4.2GiB", "connections": 256, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "357.22MB/s", + "bandwidth": "351.48MB/s", "reconnects": 0, - "status_2xx": 74914000, + "status_2xx": 73709500, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -145,18 +145,18 @@ "baseline-h2c-4096": { "framework": "aegon", "language": "C++", - "rps": 14888196, - "avg_latency": "14.07ms", - "p99_latency": "46.51ms", - "cpu": "4045.5%", - "memory": "4.3GiB", + "rps": 14766424, + "avg_latency": "14.34ms", + "p99_latency": "45.60ms", + "cpu": "4250.3%", + "memory": "4.4GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "362.09MB/s", + "bandwidth": "358.43MB/s", "reconnects": 0, - "status_2xx": 75929800, + "status_2xx": 75161100, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -164,18 +164,170 @@ "baseline-h3-64": { "framework": "aegon", "language": "C++", - "rps": 3344869, - "avg_latency": "1.43ms", - "p99_latency": "3.06ms", - "cpu": "3729.3%", + "rps": 3342752, + "avg_latency": "1.46ms", + "p99_latency": "3.24ms", + "cpu": "3763.2%", "memory": "4.2GiB", "connections": 64, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "51.09MB/s", + "bandwidth": "51.06MB/s", + "reconnects": 0, + "status_2xx": 16747192, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "echo-ws-16384": { + "framework": "aegon", + "language": "C++", + "rps": 4039162, + "avg_latency": "4.04ms", + "p99_latency": "5.33ms", + "cpu": "6134.6%", + "memory": "4.6GiB", + "connections": 16384, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "27.36MB/s", + "reconnects": 0, + "status_2xx": 20195810, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "echo-ws-4096": { + "framework": "aegon", + "language": "C++", + "rps": 4371217, + "avg_latency": "936us", + "p99_latency": "1.25ms", + "cpu": "6191.1%", + "memory": "4.2GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "29.18MB/s", + "reconnects": 0, + "status_2xx": 21856089, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "echo-ws-512": { + "framework": "aegon", + "language": "C++", + "rps": 4102815, + "avg_latency": "124us", + "p99_latency": "214us", + "cpu": "6428.3%", + "memory": "4.1GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "27.39MB/s", + "reconnects": 0, + "status_2xx": 20514079, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "echo-ws-limited-4096": { + "framework": "aegon", + "language": "C++", + "rps": 2529153, + "avg_latency": "1.06ms", + "p99_latency": "1.78ms", + "cpu": "6098.3%", + "memory": "4.3GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "48.00MB/s", + "reconnects": 1264505, + "status_2xx": 12645769, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "echo-ws-limited-512": { + "framework": "aegon", + "language": "C++", + "rps": 2171092, + "avg_latency": "126us", + "p99_latency": "374us", + "cpu": "5526.2%", + "memory": "4.2GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "41.19MB/s", + "reconnects": 1085597, + "status_2xx": 10855461, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "echo-ws-pipeline-16384": { + "framework": "aegon", + "language": "C++", + "rps": 61827241, + "avg_latency": "4.22ms", + "p99_latency": "5.19ms", + "cpu": "6421.7%", + "memory": "4.6GiB", + "connections": 16384, + "threads": 64, + "duration": "5s", + "pipeline": 16, + "bandwidth": "412.97MB/s", + "reconnects": 0, + "status_2xx": 309136208, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "echo-ws-pipeline-4096": { + "framework": "aegon", + "language": "C++", + "rps": 67059395, + "avg_latency": "977us", + "p99_latency": "1.30ms", + "cpu": "6441.9%", + "memory": "4.2GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 16, + "bandwidth": "447.49MB/s", + "reconnects": 0, + "status_2xx": 335296976, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "echo-ws-pipeline-512": { + "framework": "aegon", + "language": "C++", + "rps": 62172707, + "avg_latency": "131us", + "p99_latency": "261us", + "cpu": "6280.6%", + "memory": "4.1GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 16, + "bandwidth": "414.83MB/s", "reconnects": 0, - "status_2xx": 16757797, + "status_2xx": 310863535, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -183,19 +335,19 @@ "json-comp-16384": { "framework": "aegon", "language": "C++", - "rps": 956083, - "avg_latency": "17.01ms", - "p99_latency": "23.60ms", - "cpu": "6442.4%", + "rps": 954659, + "avg_latency": "17.05ms", + "p99_latency": "24.20ms", + "cpu": "6777.0%", "memory": "4.5GiB", "connections": 16384, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "1.34GB/s", - "input_bw": "71.12MB/s", - "reconnects": 183334, - "status_2xx": 4780418, + "bandwidth": "1.33GB/s", + "input_bw": "71.01MB/s", + "reconnects": 183039, + "status_2xx": 4773296, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -203,19 +355,19 @@ "json-comp-4096": { "framework": "aegon", "language": "C++", - "rps": 981679, - "avg_latency": "4.13ms", - "p99_latency": "8.86ms", - "cpu": "6717.7%", - "memory": "4.3GiB", + "rps": 985154, + "avg_latency": "4.11ms", + "p99_latency": "8.81ms", + "cpu": "6787.7%", + "memory": "4.2GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "1.37GB/s", - "input_bw": "73.02MB/s", - "reconnects": 195842, - "status_2xx": 4908395, + "bandwidth": "1.38GB/s", + "input_bw": "73.28MB/s", + "reconnects": 195503, + "status_2xx": 4925773, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -223,18 +375,18 @@ "json-h2c-1024": { "framework": "aegon", "language": "C++", - "rps": 3675222, - "avg_latency": "8.43ms", - "p99_latency": "23.15ms", - "cpu": "6591.2%", - "memory": "4.5GiB", + "rps": 3680638, + "avg_latency": "8.56ms", + "p99_latency": "22.21ms", + "cpu": "6492.8%", + "memory": "4.4GiB", "connections": 1024, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "12.30GB/s", + "bandwidth": "12.32GB/s", "reconnects": 0, - "status_2xx": 18633380, + "status_2xx": 18660838, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -242,18 +394,18 @@ "json-h2c-4096": { "framework": "aegon", "language": "C++", - "rps": 3094589, - "avg_latency": "40.94ms", - "p99_latency": "96.85ms", - "cpu": "6523.6%", - "memory": "5.7GiB", + "rps": 3109662, + "avg_latency": "40.78ms", + "p99_latency": "87.74ms", + "cpu": "6335.4%", + "memory": "5.3GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "10.41GB/s", + "bandwidth": "10.42GB/s", "reconnects": 0, - "status_2xx": 15782406, + "status_2xx": 15797088, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -261,18 +413,18 @@ "json-tls-4096": { "framework": "aegon", "language": "C++", - "rps": 1342139, - "avg_latency": "2.99ms", - "p99_latency": "62.00ms", - "cpu": "6570.8%", + "rps": 1334245, + "avg_latency": "3.02ms", + "p99_latency": "67.12ms", + "cpu": "6589.2%", "memory": "4.8GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "4.56GB", + "bandwidth": "4.53GB", "reconnects": 0, - "status_2xx": 6845772, + "status_2xx": 6805719, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -280,10 +432,10 @@ "latency-10k-1024": { "framework": "aegon", "language": "C++", - "rps": 9982, - "avg_latency": "69.4us", - "p99_latency": "97.0us", - "cpu": "28.6%", + "rps": 9983, + "avg_latency": "68.1us", + "p99_latency": "98.0us", + "cpu": "28.7%", "memory": "4.1GiB", "connections": 1024, "threads": 64, @@ -291,80 +443,80 @@ "pipeline": 1, "bandwidth": "0.65MB/s", "reconnects": 0, - "status_2xx": 199667, + "status_2xx": 199674, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0, - "cpu_usec": 5994365, - "cpu_per_req_us": 30.0218, + "cpu_usec": 6011326, + "cpu_per_req_us": 30.1057, "target_rate": 10000, - "rate_ratio": 0.9982, - "p99_9_latency": "508.0us" + "rate_ratio": 0.9983, + "p99_9_latency": "252.0us" }, "latency-1m-1024": { "framework": "aegon", "language": "C++", - "rps": 997968, - "avg_latency": "92.7us", - "p99_latency": "159.0us", - "cpu": "2309.7%", + "rps": 997803, + "avg_latency": "89.8us", + "p99_latency": "163.0us", + "cpu": "2350.1%", "memory": "4.1GiB", "connections": 1024, "threads": 64, "duration": "20s", "pipeline": 1, - "bandwidth": "64.87MB/s", + "bandwidth": "64.86MB/s", "reconnects": 0, - "status_2xx": 19962735, + "status_2xx": 19959195, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0, - "cpu_usec": 421151167, - "cpu_per_req_us": 21.0969, + "cpu_usec": 426630871, + "cpu_per_req_us": 21.3752, "target_rate": 1000000, - "rate_ratio": 0.998, - "p99_9_latency": "4986.0us" + "rate_ratio": 0.9978, + "p99_9_latency": "1132.0us" }, "latency-500k-8cpu-1024": { "framework": "aegon", "language": "C++", - "rps": 496457, - "avg_latency": "47922.9us", - "p99_latency": "636672.0us", - "cpu": "839.1%", + "rps": 495918, + "avg_latency": "58087.6us", + "p99_latency": "780032.0us", + "cpu": "833.7%", "memory": "555MiB", "connections": 1024, "threads": 64, "duration": "20s", "pipeline": 1, - "bandwidth": "32.27MB/s", + "bandwidth": "32.23MB/s", "reconnects": 0, - "status_2xx": 9931077, + "status_2xx": 9920240, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0, - "cpu_usec": 158832936, - "cpu_per_req_us": 15.9935, + "cpu_usec": 158461452, + "cpu_per_req_us": 15.9736, "target_rate": 500000, - "rate_ratio": 0.9929, - "p99_9_latency": "685824.0us" + "rate_ratio": 0.9918, + "p99_9_latency": "837376.0us" }, "limited-conn-4096": { "framework": "aegon", "language": "C++", - "rps": 2647150, - "avg_latency": "1.41ms", - "p99_latency": "1.92ms", - "cpu": "6044.0%", + "rps": 2661047, + "avg_latency": "1.40ms", + "p99_latency": "1.93ms", + "cpu": "6078.0%", "memory": "4.2GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "166.55MB/s", - "input_bw": "204.49MB/s", - "reconnects": 1324519, - "status_2xx": 13235752, + "bandwidth": "167.43MB/s", + "input_bw": "205.56MB/s", + "reconnects": 1330051, + "status_2xx": 13305239, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -372,18 +524,18 @@ "pipelined-4096": { "framework": "aegon", "language": "C++", - "rps": 43600880, - "avg_latency": "1.50ms", - "p99_latency": "2.06ms", - "cpu": "6629.1%", + "rps": 43291308, + "avg_latency": "1.51ms", + "p99_latency": "1.99ms", + "cpu": "6640.6%", "memory": "4.2GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 16, - "bandwidth": "2.68GB/s", + "bandwidth": "2.66GB/s", "reconnects": 0, - "status_2xx": 218004401, + "status_2xx": 216456544, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -391,18 +543,18 @@ "static-h2-1024": { "framework": "aegon", "language": "C++", - "rps": 562094, - "avg_latency": "33.18ms", - "p99_latency": "98.75ms", - "cpu": "5965.9%", - "memory": "4.6GiB", + "rps": 487518, + "avg_latency": "64.09ms", + "p99_latency": "158.49ms", + "cpu": "6502.3%", + "memory": "5.0GiB", "connections": 1024, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "8.62GB/s", + "bandwidth": "7.51GB/s", "reconnects": 0, - "status_2xx": 2849819, + "status_2xx": 2471720, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -410,18 +562,18 @@ "static-h2-256": { "framework": "aegon", "language": "C++", - "rps": 525553, - "avg_latency": "13.34ms", - "p99_latency": "38.02ms", - "cpu": "5979.7%", - "memory": "4.3GiB", + "rps": 555333, + "avg_latency": "15.76ms", + "p99_latency": "43.37ms", + "cpu": "6699.8%", + "memory": "4.4GiB", "connections": 256, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "8.02GB/s", + "bandwidth": "8.48GB/s", "reconnects": 0, - "status_2xx": 2643534, + "status_2xx": 2793327, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -429,18 +581,18 @@ "static-h3-64": { "framework": "aegon", "language": "C++", - "rps": 351724, - "avg_latency": "13.76ms", - "p99_latency": "37.79ms", - "cpu": "4888.4%", + "rps": 304544, + "avg_latency": "15.70ms", + "p99_latency": "33.63ms", + "cpu": "4315.8%", "memory": "4.3GiB", "connections": 64, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "5.35GB/s", + "bandwidth": "4.63GB/s", "reconnects": 0, - "status_2xx": 1762139, + "status_2xx": 1525769, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -448,18 +600,18 @@ "static-tls-1024": { "framework": "aegon", "language": "C++", - "rps": 536131, - "avg_latency": "2.14ms", - "p99_latency": "29.28ms", - "cpu": "6785.7%", - "memory": "4.6GiB", + "rps": 529259, + "avg_latency": "2.17ms", + "p99_latency": "36.06ms", + "cpu": "6713.5%", + "memory": "4.5GiB", "connections": 1024, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "8.20GB", + "bandwidth": "8.09GB", "reconnects": 0, - "status_2xx": 2734466, + "status_2xx": 2699242, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 diff --git a/site/static/logs/echo-ws-limited/4096/aegon.log b/site/static/logs/echo-ws-limited/4096/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/echo-ws-limited/512/aegon.log b/site/static/logs/echo-ws-limited/512/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/echo-ws-pipeline/16384/aegon.log b/site/static/logs/echo-ws-pipeline/16384/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/echo-ws-pipeline/4096/aegon.log b/site/static/logs/echo-ws-pipeline/4096/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/echo-ws-pipeline/512/aegon.log b/site/static/logs/echo-ws-pipeline/512/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/echo-ws/16384/aegon.log b/site/static/logs/echo-ws/16384/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/echo-ws/4096/aegon.log b/site/static/logs/echo-ws/4096/aegon.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/echo-ws/512/aegon.log b/site/static/logs/echo-ws/512/aegon.log new file mode 100644 index 000000000..e69de29bb From 693ff75eefa876d676e42e6dc978a0df40aa9b7b Mon Sep 17 00:00:00 2001 From: Uday Khare Date: Sat, 26 Sep 2026 00:27:15 +0530 Subject: [PATCH 10/14] update Aegon commit --- frameworks/aegon/Dockerfile | 2 +- frameworks/aegon/main.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/frameworks/aegon/Dockerfile b/frameworks/aegon/Dockerfile index 92f749057..d0b1cd5b8 100644 --- a/frameworks/aegon/Dockerfile +++ b/frameworks/aegon/Dockerfile @@ -14,7 +14,7 @@ RUN pacman -Syu --noconfirm --needed \ ARG AEGON_REPO=https://github.com/UdayKhare09/Aegon.git ARG AEGON_REF=main -ARG AEGON_COMMIT=790c8b5 +ARG AEGON_COMMIT=f39a7b9 WORKDIR /src RUN echo "Building Aegon commit: ${AEGON_COMMIT}" && \ diff --git a/frameworks/aegon/main.cpp b/frameworks/aegon/main.cpp index f91b1adf7..d0db7f93e 100644 --- a/frameworks/aegon/main.cpp +++ b/frameworks/aegon/main.cpp @@ -314,9 +314,10 @@ int main() { if (has_certs) { server.enable_tls(certFile, keyFile); + server.enable_http3(true); // Port 8081: TLS HTTP/1.1 (json-tls, 8gbit) server.listen_tls(8081); - // Port 8443: TLS HTTP/2 (baseline-h2) + // Port 8443: TLS HTTP/2 & HTTP/3 (baseline-h2, static-h2, baseline-h3, static-h3) server.listen_tls(8443); } From bdf655cee8e25a6b7662e3e971e8040a824535d6 Mon Sep 17 00:00:00 2001 From: Uday Khare Date: Sat, 26 Sep 2026 18:58:49 +0530 Subject: [PATCH 11/14] perf(aegon): bump Aegon to b1abba1 to fix WS handoff race and optimize send hot paths - Fix multishot stream handoff race during WebSocket upgrade, preventing dropped pipelined frames in echo-ws-limited - Ensure reliable terminal EOF/disconnect delivery in MultishotRecvStream - Fast-path single-SQE ring.send() in HTTP/1.1 and HTTP/2 cleartext flushes to eliminate coroutine allocation overhead - Remove by-value string copies in send_all helper --- frameworks/aegon/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/aegon/Dockerfile b/frameworks/aegon/Dockerfile index d0b1cd5b8..215c163a1 100644 --- a/frameworks/aegon/Dockerfile +++ b/frameworks/aegon/Dockerfile @@ -14,7 +14,7 @@ RUN pacman -Syu --noconfirm --needed \ ARG AEGON_REPO=https://github.com/UdayKhare09/Aegon.git ARG AEGON_REF=main -ARG AEGON_COMMIT=f39a7b9 +ARG AEGON_COMMIT=b1abba1 WORKDIR /src RUN echo "Building Aegon commit: ${AEGON_COMMIT}" && \ From 9f65893d265958f3c232c923b6a5aec4f3f1b32f Mon Sep 17 00:00:00 2001 From: Uday Khare Date: Sun, 27 Sep 2026 21:44:51 +0530 Subject: [PATCH 12/14] aegon: bump commit to 9368fa2 --- frameworks/aegon/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/aegon/Dockerfile b/frameworks/aegon/Dockerfile index 215c163a1..14ae93685 100644 --- a/frameworks/aegon/Dockerfile +++ b/frameworks/aegon/Dockerfile @@ -14,7 +14,7 @@ RUN pacman -Syu --noconfirm --needed \ ARG AEGON_REPO=https://github.com/UdayKhare09/Aegon.git ARG AEGON_REF=main -ARG AEGON_COMMIT=b1abba1 +ARG AEGON_COMMIT=9368fa2 WORKDIR /src RUN echo "Building Aegon commit: ${AEGON_COMMIT}" && \ From 003b5bb345119a43a7508eaaf9d63c0b481431aa Mon Sep 17 00:00:00 2001 From: Uday Khare Date: Wed, 30 Sep 2026 00:51:08 +0530 Subject: [PATCH 13/14] update AEGON_COMMIT to 8ad36fe in aegon Dockerfile --- frameworks/aegon/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/aegon/Dockerfile b/frameworks/aegon/Dockerfile index 14ae93685..d3352e888 100644 --- a/frameworks/aegon/Dockerfile +++ b/frameworks/aegon/Dockerfile @@ -14,7 +14,7 @@ RUN pacman -Syu --noconfirm --needed \ ARG AEGON_REPO=https://github.com/UdayKhare09/Aegon.git ARG AEGON_REF=main -ARG AEGON_COMMIT=9368fa2 +ARG AEGON_COMMIT=8ad36fe WORKDIR /src RUN echo "Building Aegon commit: ${AEGON_COMMIT}" && \ From 8e2cd52f1fd9b5c00b92b47b8ffabf07cfa8dacf Mon Sep 17 00:00:00 2001 From: Uday Khare Date: Wed, 30 Sep 2026 16:48:44 +0530 Subject: [PATCH 14/14] fix(aegon): include aegon_orm in build targets and update commit to f9edfc3 --- frameworks/aegon/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frameworks/aegon/Dockerfile b/frameworks/aegon/Dockerfile index d3352e888..3b2e4ad11 100644 --- a/frameworks/aegon/Dockerfile +++ b/frameworks/aegon/Dockerfile @@ -14,7 +14,7 @@ RUN pacman -Syu --noconfirm --needed \ ARG AEGON_REPO=https://github.com/UdayKhare09/Aegon.git ARG AEGON_REF=main -ARG AEGON_COMMIT=8ad36fe +ARG AEGON_COMMIT=f9edfc3 WORKDIR /src RUN echo "Building Aegon commit: ${AEGON_COMMIT}" && \ @@ -24,7 +24,7 @@ WORKDIR /src/aegon-src RUN cmake -B build -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr/local && \ - cmake --build build --target aegon_core aegon_config aegon_redis aegon_memory aegon_http aegon_gateway aegon_cli -j$(nproc) && \ + cmake --build build --target aegon_core aegon_config aegon_redis aegon_memory aegon_orm aegon_http aegon_gateway aegon_cli -j$(nproc) && \ cmake --install build WORKDIR /app