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
7 changes: 7 additions & 0 deletions frameworks/django/Dockerfile
Original file line number Diff line number Diff line change
@@ -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
26 changes: 26 additions & 0 deletions frameworks/django/README.md
Original file line number Diff line number Diff line change
@@ -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
79 changes: 79 additions & 0 deletions frameworks/django/app.py
Original file line number Diff line number Diff line change
@@ -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/<int:count>", json_items),
path("upload", upload),
]

application = get_asgi_application()
19 changes: 19 additions & 0 deletions frameworks/django/meta.json
Original file line number Diff line number Diff line change
@@ -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": []
}
2 changes: 2 additions & 0 deletions frameworks/django/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Django==6.1
uvicorn[standard]==0.52.3
8 changes: 8 additions & 0 deletions site/data/frameworks.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
243 changes: 243 additions & 0 deletions site/data/results/django.json
Original file line number Diff line number Diff line change
@@ -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
}
}
}
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.