Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions frameworks/libioma/Dockerfile
Original file line number Diff line number Diff line change
@@ -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

Expand Down
2 changes: 1 addition & 1 deletion frameworks/libioma/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
68 changes: 17 additions & 51 deletions frameworks/libioma/main.c
Original file line number Diff line number Diff line change
@@ -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 <ioma.h>

#include <stdlib.h>

/* 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);
Expand All @@ -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)
Expand Down
Loading