From 8ec9f8ee59ec927f23fc6fd0dec52145c6e2e220 Mon Sep 17 00:00:00 2001 From: Nigro Simone Date: Fri, 14 Aug 2026 07:20:40 +0200 Subject: [PATCH 1/2] Add django framework --- frameworks/django/Dockerfile | 7 +++ frameworks/django/README.md | 26 ++++++++++ frameworks/django/app.py | 79 ++++++++++++++++++++++++++++++ frameworks/django/meta.json | 19 +++++++ frameworks/django/requirements.txt | 2 + 5 files changed, 133 insertions(+) create mode 100644 frameworks/django/Dockerfile create mode 100644 frameworks/django/README.md create mode 100644 frameworks/django/app.py create mode 100644 frameworks/django/meta.json create mode 100644 frameworks/django/requirements.txt diff --git a/frameworks/django/Dockerfile b/frameworks/django/Dockerfile new file mode 100644 index 000000000..7e01c937e --- /dev/null +++ b/frameworks/django/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.13-slim +WORKDIR /app +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY . . +EXPOSE 8080 +CMD uvicorn app:application --host 0.0.0.0 --port 8080 --workers $(nproc) --log-level critical diff --git a/frameworks/django/README.md b/frameworks/django/README.md new file mode 100644 index 000000000..eaa26253a --- /dev/null +++ b/frameworks/django/README.md @@ -0,0 +1,26 @@ +# django + +Django 6.1 as an ASGI application on Uvicorn. + +## Stack + +- **Language:** Python 3.13 +- **Framework:** Django 6.1 +- **Server:** Uvicorn, one worker per core +- **Build:** `python:3.13-slim` + +## Endpoints + +| Endpoint | Method | Description | +|----------|--------|-------------| +| `/pipeline` | GET | Returns `ok` (plain text) | +| `/baseline11` | GET | Sums query parameter values | +| `/baseline11` | POST | Sums query parameters + request body | +| `/json/{count}?m=N` | GET | First `count` dataset items with `total = price * quantity * m` | +| `/upload` | POST | Reads the body and returns the byte count | + +## Notes + +- URLconf routing with the `int` path converter, async views returning `HttpResponse` / `JsonResponse` +- Compression through `django.middleware.gzip.GZipMiddleware` +- ASGI and not WSGI because the WSGI request drops `Transfer-Encoding: chunked` bodies, which the baseline profile sends diff --git a/frameworks/django/app.py b/frameworks/django/app.py new file mode 100644 index 000000000..2a0092e04 --- /dev/null +++ b/frameworks/django/app.py @@ -0,0 +1,79 @@ +import json +import os + +import django +from django.conf import settings + +settings.configure( + DEBUG=False, + ALLOWED_HOSTS=["*"], + SECRET_KEY="httparena", + ROOT_URLCONF=__name__, + MIDDLEWARE=["django.middleware.gzip.GZipMiddleware"], + LOGGING_CONFIG=None, +) +django.setup() + +from django.core.asgi import get_asgi_application # noqa: E402 +from django.http import HttpResponse, JsonResponse # noqa: E402 +from django.urls import path # noqa: E402 + +DATASET_PATH = os.environ.get("DATASET_PATH", "/data/dataset.json") +DATASET = [] +try: + with open(DATASET_PATH) as dataset_file: + DATASET = json.load(dataset_file) +except OSError: + pass + + +async def pipeline(request): + return HttpResponse("ok", content_type="text/plain") + + +async def baseline11(request): + total = 0 + for value in request.GET.values(): + try: + total += int(value) + except ValueError: + pass + if request.method == "POST": + try: + total += int(request.body.strip()) + except ValueError: + pass + return HttpResponse(str(total), content_type="text/plain") + + +async def json_items(request, count): + try: + m = int(request.GET.get("m", 1)) + except ValueError: + m = 1 + items = [] + for item in DATASET[:count]: + processed = dict(item) + processed["total"] = item["price"] * item["quantity"] * m + items.append(processed) + return JsonResponse({"items": items, "count": len(items)}) + + +async def upload(request): + size = 0 + while True: + chunk = request.read(262144) + if not chunk: + break + size += len(chunk) + return HttpResponse(str(size), content_type="text/plain") + + +urlpatterns = [ + path("pipeline", pipeline), + path("baseline11", baseline11), + path("json/", json_items), + path("upload", upload), +] + +application = get_asgi_application() diff --git a/frameworks/django/meta.json b/frameworks/django/meta.json new file mode 100644 index 000000000..8805dfa02 --- /dev/null +++ b/frameworks/django/meta.json @@ -0,0 +1,19 @@ +{ + "display_name": "django", + "language": "Python", + "type": "flagship", + "mode": "standard", + "engine": "uvicorn", + "description": "Django 6.1 as an ASGI application on Uvicorn. URLconf routing and path converters through the Django API, JsonResponse for the JSON payload, GZipMiddleware for compression.", + "repo": "https://github.com/django/django", + "enabled": true, + "tests": [ + "baseline", + "pipelined", + "limited-conn", + "json", + "json-comp", + "upload" + ], + "maintainers": [] +} diff --git a/frameworks/django/requirements.txt b/frameworks/django/requirements.txt new file mode 100644 index 000000000..971ba23e0 --- /dev/null +++ b/frameworks/django/requirements.txt @@ -0,0 +1,2 @@ +Django==6.1 +uvicorn[standard]==0.52.3 From e4a73ce27b74acef772c40787f696d9ce39816df Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 14 Aug 2026 06:24:22 +0000 Subject: [PATCH 2/2] Benchmark results: django [skip ci] --- site/data/frameworks.json | 8 + site/data/results/django.json | 243 ++++++++++++++++++ site/static/logs/baseline/4096/django.log | 0 site/static/logs/baseline/512/django.log | 0 site/static/logs/json-comp/16384/django.log | 0 site/static/logs/json-comp/4096/django.log | 0 site/static/logs/json-comp/512/django.log | 0 site/static/logs/json/4096/django.log | 0 site/static/logs/limited-conn/4096/django.log | 0 site/static/logs/limited-conn/512/django.log | 0 site/static/logs/pipelined/4096/django.log | 0 site/static/logs/pipelined/512/django.log | 0 site/static/logs/upload/256/django.log | 0 site/static/logs/upload/32/django.log | 0 14 files changed, 251 insertions(+) create mode 100644 site/data/results/django.json create mode 100644 site/static/logs/baseline/4096/django.log create mode 100644 site/static/logs/baseline/512/django.log create mode 100644 site/static/logs/json-comp/16384/django.log create mode 100644 site/static/logs/json-comp/4096/django.log create mode 100644 site/static/logs/json-comp/512/django.log create mode 100644 site/static/logs/json/4096/django.log create mode 100644 site/static/logs/limited-conn/4096/django.log create mode 100644 site/static/logs/limited-conn/512/django.log create mode 100644 site/static/logs/pipelined/4096/django.log create mode 100644 site/static/logs/pipelined/512/django.log create mode 100644 site/static/logs/upload/256/django.log create mode 100644 site/static/logs/upload/32/django.log diff --git a/site/data/frameworks.json b/site/data/frameworks.json index 7f879a980..f7a7b8f41 100644 --- a/site/data/frameworks.json +++ b/site/data/frameworks.json @@ -236,6 +236,14 @@ "engine": "deno", "mode": "tuned" }, + "django": { + "dir": "django", + "description": "Django 6.1 as an ASGI application on Uvicorn. URLconf routing and path converters through the Django API, JsonResponse for the JSON payload, GZipMiddleware for compression.", + "repo": "https://github.com/django/django", + "type": "flagship", + "engine": "uvicorn", + "mode": "standard" + }, "dogrider": { "dir": "dogrider", "description": "GenHTTP websockets with zerg backend", diff --git a/site/data/results/django.json b/site/data/results/django.json new file mode 100644 index 000000000..beb0ddfa4 --- /dev/null +++ b/site/data/results/django.json @@ -0,0 +1,243 @@ +{ + "framework": "django", + "results": { + "baseline-4096": { + "framework": "django", + "language": "Python", + "rps": 29568, + "avg_latency": "136.21ms", + "p99_latency": "245.70ms", + "cpu": "5881.2%", + "memory": "3.1GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "3.92MB/s", + "input_bw": "2.28MB/s", + "reconnects": 0, + "status_2xx": 147844, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "baseline-512": { + "framework": "django", + "language": "Python", + "rps": 30555, + "avg_latency": "16.78ms", + "p99_latency": "25.20ms", + "cpu": "5873.5%", + "memory": "2.4GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "4.05MB/s", + "input_bw": "2.36MB/s", + "reconnects": 0, + "status_2xx": 152779, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "json-4096": { + "framework": "django", + "language": "Python", + "rps": 27191, + "avg_latency": "146.76ms", + "p99_latency": "382.10ms", + "cpu": "5833.8%", + "memory": "3.1GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "107.57MB/s", + "input_bw": "1.30MB/s", + "reconnects": 4149, + "status_2xx": 135955, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "json-comp-16384": { + "framework": "django", + "language": "Python", + "rps": 22094, + "avg_latency": "544.27ms", + "p99_latency": "2.54s", + "cpu": "5707.4%", + "memory": "9.4GiB", + "connections": 16384, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "31.68MB/s", + "input_bw": "1.64MB/s", + "reconnects": 12, + "status_2xx": 110471, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "json-comp-4096": { + "framework": "django", + "language": "Python", + "rps": 24540, + "avg_latency": "162.31ms", + "p99_latency": "435.90ms", + "cpu": "5953.6%", + "memory": "4.7GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "35.17MB/s", + "input_bw": "1.83MB/s", + "reconnects": 2692, + "status_2xx": 122703, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "json-comp-512": { + "framework": "django", + "language": "Python", + "rps": 25069, + "avg_latency": "20.43ms", + "p99_latency": "39.30ms", + "cpu": "6031.4%", + "memory": "2.7GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "35.94MB/s", + "input_bw": "1.86MB/s", + "reconnects": 4840, + "status_2xx": 125345, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "limited-conn-4096": { + "framework": "django", + "language": "Python", + "rps": 29657, + "avg_latency": "133.56ms", + "p99_latency": "547.70ms", + "cpu": "5900.5%", + "memory": "3.1GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "3.93MB/s", + "input_bw": "2.29MB/s", + "reconnects": 13780, + "status_2xx": 148286, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "limited-conn-512": { + "framework": "django", + "language": "Python", + "rps": 29850, + "avg_latency": "17.16ms", + "p99_latency": "33.10ms", + "cpu": "5942.6%", + "memory": "2.5GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "3.95MB/s", + "input_bw": "2.31MB/s", + "reconnects": 14836, + "status_2xx": 149250, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "pipelined-4096": { + "framework": "django", + "language": "Python", + "rps": 57033, + "avg_latency": "1.01s", + "p99_latency": "1.39s", + "cpu": "5980.0%", + "memory": "3.1GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 16, + "bandwidth": "7.56MB/s", + "reconnects": 0, + "status_2xx": 285167, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "pipelined-512": { + "framework": "django", + "language": "Python", + "rps": 70655, + "avg_latency": "115.46ms", + "p99_latency": "172.20ms", + "cpu": "6351.2%", + "memory": "2.4GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 16, + "bandwidth": "9.36MB/s", + "reconnects": 0, + "status_2xx": 353276, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "upload-256": { + "framework": "django", + "language": "Python", + "rps": 656, + "avg_latency": "361.91ms", + "p99_latency": "1.35s", + "cpu": "6230.4%", + "memory": "2.9GiB", + "connections": 256, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "92.52KB/s", + "input_bw": "5.20GB/s", + "reconnects": 571, + "status_2xx": 3282, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + }, + "upload-32": { + "framework": "django", + "language": "Python", + "rps": 656, + "avg_latency": "48.59ms", + "p99_latency": "215.50ms", + "cpu": "2050.0%", + "memory": "2.4GiB", + "connections": 32, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "92.39KB/s", + "input_bw": "5.20GB/s", + "reconnects": 650, + "status_2xx": 3280, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 + } + } +} diff --git a/site/static/logs/baseline/4096/django.log b/site/static/logs/baseline/4096/django.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/baseline/512/django.log b/site/static/logs/baseline/512/django.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/json-comp/16384/django.log b/site/static/logs/json-comp/16384/django.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/json-comp/4096/django.log b/site/static/logs/json-comp/4096/django.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/json-comp/512/django.log b/site/static/logs/json-comp/512/django.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/json/4096/django.log b/site/static/logs/json/4096/django.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/limited-conn/4096/django.log b/site/static/logs/limited-conn/4096/django.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/limited-conn/512/django.log b/site/static/logs/limited-conn/512/django.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/pipelined/4096/django.log b/site/static/logs/pipelined/4096/django.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/pipelined/512/django.log b/site/static/logs/pipelined/512/django.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/upload/256/django.log b/site/static/logs/upload/256/django.log new file mode 100644 index 000000000..e69de29bb diff --git a/site/static/logs/upload/32/django.log b/site/static/logs/upload/32/django.log new file mode 100644 index 000000000..e69de29bb