diff --git a/frameworks/libioma/Dockerfile b/frameworks/libioma/Dockerfile index c5d767872..2c97ca9bb 100644 --- a/frameworks/libioma/Dockerfile +++ b/frameworks/libioma/Dockerfile @@ -1,20 +1,21 @@ FROM ubuntu:24.04 AS build RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc make curl ca-certificates libc6-dev \ + gcc-14 make curl ca-certificates libc6-dev \ && rm -rf /var/lib/apt/lists/* WORKDIR /app -# Build libioma from its own repo, pinned to a commit for reproducibility (the h2o pattern: fetch -# upstream at a fixed SHA and build it here, tuned for this CPU). No liburing — libioma issues the -# io_uring syscalls directly. Only the baseline handler lives in this entry. -ARG LIBIOMA_VERSION=263905f98b3c6f9200ed11ddbfaf0f5cddcecc9d +# Build libioma from its own repo, pinned to a commit (the h2o pattern: fetch upstream at a fixed +# SHA and build it here, tuned for this CPU). No liburing: libioma issues the io_uring syscalls +# directly. Only the baseline handler lives in this entry. Fat LTO objects for the library and +# -flto on the handler link, so the handler inlines into the engine. +ARG LIBIOMA_VERSION=b027f05360b8ae5192bd73133437663cd645bac1 RUN mkdir -p /tmp/libioma && \ curl -LSs "https://github.com/MDA2AV/libioma/archive/${LIBIOMA_VERSION}.tar.gz" \ | tar --strip-components=1 -xz -C /tmp/libioma && \ - make -C /tmp/libioma libioma.a CFLAGS="-O3 -march=native" + make -C /tmp/libioma libioma.a CC=gcc-14 CFLAGS="-O3 -march=native -flto -ffat-lto-objects" COPY main.c . -RUN gcc -O3 -march=native -Wall -std=gnu11 -pthread \ +RUN gcc-14 -O3 -march=native -flto -Wall -std=gnu11 -pthread \ -I/tmp/libioma/include \ main.c /tmp/libioma/libioma.a -o server -pthread diff --git a/frameworks/libioma/README.md b/frameworks/libioma/README.md index 31bfcbd8c..9b97d6e2b 100644 --- a/frameworks/libioma/README.md +++ b/frameworks/libioma/README.md @@ -7,7 +7,7 @@ state machine. ## Stack -- **Language:** C (GCC, `-O2 -march=native`) +- **Language:** C23 (gcc 14, `-O3 -march=native -flto`) - **Engine:** raw `io_uring` syscalls — no liburing. Multishot accept and multishot recv over per-worker provided buffer rings; `SINGLE_ISSUER | DEFER_TASKRUN | NO_SQARRAY`. - **Architecture:** thread-per-core, shared-nothing. One ring, one `SO_REUSEPORT` listener and one diff --git a/frameworks/libioma/main.c b/frameworks/libioma/main.c index e6456f134..47c77905b 100644 --- a/frameworks/libioma/main.c +++ b/frameworks/libioma/main.c @@ -1,59 +1,26 @@ /* - * HttpArena baseline handler for ioma. + * HttpArena baseline handler for libioma. * - * baseline profile: GET/POST /baseline11?a=..&b=.. — sum the query parameter values, and on POST - * add the request body value too. The body arrives as Content-Length or Transfer-Encoding: chunked; - * ioma decodes both, so the same handler serves all three request shapes the profile rotates. + * baseline profile: GET/POST /baseline11?a=..&b=.. - sum the query parameter values, and on POST + * add the request body value too. libioma hands the query already split into key/value slices; + * the body is read on demand (Content-Length or chunked, decoded). The digits are written straight + * into the reply slab. */ #include #include -/* Sum the integer values of the query parameters, e.g. "a=13&b=42" -> 55. */ -static long sum_query(const char *q, size_t n) +static void baseline11(ioma_ctx *c) { - long sum = 0; - size_t i = 0; - while (i < n) { - while (i < n && q[i] != '=') i++; /* to this parameter's '=' */ - if (i >= n) break; - i++; /* past '=' */ - - long v = 0; - int any = 0; - while (i < n && q[i] != '&') { - if (q[i] >= '0' && q[i] <= '9') { - v = v * 10 + (q[i] - '0'); - any = 1; - } - i++; - } - if (any) sum += v; - if (i < n && q[i] == '&') i++; - } - return sum; -} - -/* Leading integer of a body like "20". */ -static long body_int(const char *b, size_t n) -{ - long v = 0; - for (size_t i = 0; i < n; i++) { - if (b[i] < '0' || b[i] > '9') break; - v = v * 10 + (b[i] - '0'); - } - return v; -} - -/* GET / POST /baseline11 - the summed response, formatted straight into the request scratch. */ -static ioma_response baseline11(ioma_request *req) -{ - long sum = 0; - if (req->query_len) sum += sum_query(req->query, req->query_len); - if (req->body_len) sum += body_int(req->body, req->body_len); - - /* itoa into scratch (alive until the reply is sent) - no snprintf on the hot path */ - char *p = req->scratch; + int64_t sum = 0, v; + for (size_t i = 0; i < c->req.n_params; i++) + if (ioma_to_i64(c->req.params[i].value, &v)) + sum += v; + if ((c->req.content_length || c->req.chunked) && ioma_to_i64(ioma_slice_trim(ioma_body(c)), &v)) + sum += v; + + /* itoa straight into the reply slab - no snprintf, no copy */ + char *out = c->res.buf + c->res.len; char tmp[24]; int t = 0; unsigned long u = (unsigned long)(sum < 0 ? 0 : sum); @@ -62,9 +29,8 @@ static ioma_response baseline11(ioma_request *req) u /= 10; } while (u); for (int i = 0; i < t; i++) - p[i] = tmp[t - 1 - i]; - - return ioma_bytes(200, "text/plain", req->scratch, (size_t)t); + out[i] = tmp[t - 1 - i]; + c->res.len += (size_t)t; } int main(int argc, char **argv)