# Prefill Throughput Bias from Cold-Start Requests ## Problem AIPerf's per-run `profile_export_aiperf.json` aggregates ALL requests, including the very first one which has to establish a fresh HTTP connection. This biases the `prefill_throughput_per_user` metric significantly: | Request | Input Tokens | Prefill tok/s | TTFT | Connection | |---------|-------------|---------------|------|------------| | 0 | 7 | **4 tok/s** | 1699 ms | DNS (1002ms) + TCP (1144ms) | | 1 | 371 | 2003 tok/s | 185 ms | Reused ✓ | | 2 | 676 | 3596 tok/s | 188 ms | Reused ✓ | | 5 | 1488 | 7571 tok/s | 197 ms | Reused ✓ | The first request's DNS lookup + TCP handshake (2+ seconds) is counted toward "prefill time", deflating the metric. The **true** prefill throughput (requests 1+) is ~2K–7.5K tok/s, not the ~4K aggregate. ## Impact - **Prefill metrics**: Inflated by ~1.5–2× for short runs (<20 requests). Improves as sample size grows. - **TTFT p99**: May be driven by the warm-up request's elevated TTFT. - **Low-concurrency runs** (conc=1, single session) are most affected because only ONE session exists and its first request is always cold. ## Mitigation ### Option A: Discard First Request (Recommended for Prescriptive Benchmarks) Parse `profile_export.jsonl` (line-delimited JSON, one request per line) and exclude `session_num=0` / `turn_index=0`: ```python import json metrics = [] with open("profile_export.jsonl") as f: for line in f: req = json.loads(line) # Skip first turn of first session (cold-start) if req["metadata"]["turn_index"] == 0 and req["metadata"]["session_num"] == 0: continue m = req["metrics"] metrics.append({ "ttft": m["time_to_first_token"]["value"], "prefill": m["prefill_throughput_per_user"]["value"], }) # Now metrics[] excludes the warm-up request ``` ### Option B: Use Connection Warm-Up Before Benchmarking Send 1–2 throwaway requests to establish the TCP + TLS + HTTP/2 connection pool before the measured phase. AIPerf does not have a built-in warm-up phase, so this must be done externally: ```bash # Pre-warm the connection venv/bin/aiperf profile --config warmup.yaml \ --concurrency 1 --request-count 1 \ --artifact-dir /tmp/warmup # Now run the real benchmark — connections are hot venv/bin/aiperf profile --config benchmark.yaml \ --concurrency 1 --request-count 50 \ --artifact-dir results/benchmark ``` The warmup run should use the **same endpoint, model, and streaming=true** as the benchmark to ensure the connection pool is pre-established. ### Option C: Accept Bias for Comparative Benchmarks If comparing **N models on the same infra with the same settings**, the cold-start bias applies equally to all. The absolute numbers are slightly off, but **rankings and relative ratios remain valid**. Use this only when: - Absolute SLA numbers are not the goal - All runs use identical connection topology (same client → same endpoint) - Sample size is large enough that one cold request is <5% of total ## When It Matters Most | Scenario | Severity | Why | |----------|----------|-----| | conc=1, sessions=1 | 🔴 High | First request is 100% of traffic | | conc=5, sessions=5 | 🟡 Medium | 1 of 5 sessions starts cold | | conc=50, sessions=50 | 🟢 Low | Many sessions, cold-start amortized | | Capacity (10→100+) | 🟢 Low | Many sessions, cold-start amortized | | Steady-state (10min) | 🟢 Low | Thousands of requests, negligible | ## Per-Request Data Location Raw per-request data is in `profile_export.jsonl` (NOT `profile_export_aiperf.json` which is aggregated). Each line is a JSON object with: ```json { "metadata": { "session_num": 0, "turn_index": 0, "worker_id": "worker_766ae0c2", "conversation_id": "...", "was_cancelled": false }, "metrics": { "time_to_first_token": {"value": 1699.2, "unit": "ms"}, "prefill_throughput_per_user": {"value": 4.1, "unit": "tokens/sec/user"}, "request_latency": {"value": 26372.4, "unit": "ms"}, "http_req_connection_reused": {"value": 0, "unit": "ratio"} } } ``` Key indicators of a cold request: - `"http_req_connection_reused": {"value": 0}` — fresh connection - `"http_req_dns_lookup"` > 500ms — DNS resolution happened - `"http_req_connecting"` > 500ms — TCP/TLS handshake happened A reused connection has `"http_req_connection_reused": {"value": 1}` and near-zero DNS/connect times.