Read an SGLang sweep on an L4

LabMedium30 min16 checks

inferenceservinggoodputbenchmarking

Problem

A serving benchmark gives a table of numbers for each setting. You must read the table and decide. In this lab you read real SGLang 0.5.22 runs of Qwen3-8B on one NVIDIA L4. You find where throughput stops rising, where the latency SLO breaks, what FP8 gives, and whether a smaller prefill chunk helps.

The data comes from manuals/sglang-101/capture/gpu/summary/l4.json in this repository. support.py has a copy of the rows that the lab needs. Each value is the median of three seeds. The MIXED rows also keep the min and max of the three seeds.

Task

Write five helper functions and answers().

  1. gains(ys) returns a float array of length n - 1. Entry i is y_{i+1} / y_i - 1.
  2. saturation_point(xs, ys, min_gain=0.05) finds the first step i with gain strictly below min_gain. It returns xs[i], the last level before that step. If no step has a gain below min_gain, it returns xs[-1].
  3. largest_within(xs, ys, limit) returns the largest x whose y is less than or equal to limit. If no y meets the limit, it returns None.
  4. pct_change(new, old) returns 100 \cdot (new - old) / old.
  5. ranges_overlap(a, b) takes two dicts with the keys "min" and "max". It returns True when a_{min} \le b_{max} and b_{min} \le a_{max}.

Then do the experiment in answers(). Use the helpers.

  1. Change the concurrency from 1 to 64 in LOAD["default"]. Measure output_throughput. Report the saturation point with min_gain = 0.05 as saturation_default.
  2. Do step 1 again for LOAD["fp8"]. Report saturation_fp8.
  3. In LOAD["default"], measure p99_ttft_ms at each concurrency. Report the largest concurrency with p99_ttft_ms within SLO["ttft_ms"] as slo_concurrency_default.
  4. In LOAD["default"], measure goodput_rps. Report the concurrency with the highest goodput as best_goodput_concurrency_default. If two levels have the same goodput, use the lower concurrency.
  5. At concurrency 32, divide the FP8 output_throughput by the default output_throughput. Report the ratio as fp8_speedup_c32.
  6. Change the prefill chunk from the default (4096 tokens) to 1024 tokens. Compare MIXED["chunk-1024"] with MIXED["default"] at the same rate. Use the "median" field. Report the mean over the three rates of pct_change in median_ttft_ms as chunk_ttft_change_pct. Report the same mean for output_throughput as chunk_throughput_change_pct. The new value is the chunk 1024 value. The old value is the default value.
  7. For each rate, test if the seed ranges of median_ttft_ms for the two settings overlap. Report the number of rates with an overlap as chunk_overlap_rates.

Input and output

NameTypeShapeMeaning
xslist of numbers(n,)the levels of the variable that you change, in increasing order
yslist of floats(n,)the measured value at each level, all above 0 for gains
min_gainfloatscalarthe smallest relative gain that counts as a rise
limitfloatscalarthe SLO bound, in the unit of ys
new, oldfloatscalarthe changed value and the base value, old is not 0
a, bdictkeys min, maxone seed range each
  • gains returns a float array of shape (n - 1,).
  • saturation_point and largest_within return one element of xs. largest_within can return None.
  • pct_change returns a float. ranges_overlap returns a bool.
  • answers() returns a dict with the eight keys above. Each value is a Python float.

Constraints

  • 2 <= n <= 20 for gains and saturation_point.
  • Do not change the input lists.
  • Do not round the answers. The checks accept a relative difference of 1e-6 from the reference run.
  • Use the data in support.py only. Use numpy and the standard library only.

Examples

pythongains([13.42, 31.2, 61.54])
text[1.32488823 0.9724359 ]
pythonsaturation_point([1, 2, 4, 8], [10.0, 20.0, 20.5, 30.0])
text2

The gain from 2 to 4 is 0.025, which is below 0.05. The series rises again at 8, but the rule stops at the first low gain.

pythonlargest_within([1, 2, 4, 8], [100.0, 900.0, 1000.0, 1200.0], 1000.0)
text4
pythonpct_change(37411.99, 35999.18)
text3.9245616150145577

answers()["saturation_default"] is 32.0.

Provided code: support.py

Your code and the checks import this module with from support import .... You do not change it.

SOURCE = "manuals/sglang-101/capture/gpu/summary/l4.json"

GPU = "NVIDIA L4"
MODELS = {"default": "Qwen/Qwen3-8B", "fp8": "Qwen/Qwen3-8B-FP8 with --kv-cache-dtype fp8_e4m3"}

SLO = {"ttft_ms": 1000.0, "tpot_ms": 100.0}

KV_POOL_TOKENS = {"default": 24094, "fp8": 142369}

LOAD = {
    "default": [
        {"concurrency": 1, "output_throughput": 13.42, "median_ttft_ms": 189.16, "p99_ttft_ms": 696.1, "median_tpot_ms": 60.16, "goodput_rps": 0.09},
        {"concurrency": 2, "output_throughput": 31.2, "median_ttft_ms": 115.43, "p99_ttft_ms": 133.75, "median_tpot_ms": 63.66, "goodput_rps": 0.24},
        {"concurrency": 4, "output_throughput": 61.54, "median_ttft_ms": 137.53, "p99_ttft_ms": 139.33, "median_tpot_ms": 64.36, "goodput_rps": 0.48},
        {"concurrency": 8, "output_throughput": 112.62, "median_ttft_ms": 170.43, "p99_ttft_ms": 1275.48, "median_tpot_ms": 66.01, "goodput_rps": 0.63},
        {"concurrency": 16, "output_throughput": 201.09, "median_ttft_ms": 211.78, "p99_ttft_ms": 2461.58, "median_tpot_ms": 70.11, "goodput_rps": 0.98},
        {"concurrency": 32, "output_throughput": 270.11, "median_ttft_ms": 2969.61, "p99_ttft_ms": 4901.04, "median_tpot_ms": 96.18, "goodput_rps": 0.0},
        {"concurrency": 64, "output_throughput": 250.85, "median_ttft_ms": 18348.57, "p99_ttft_ms": 33395.92, "median_tpot_ms": 107.42, "goodput_rps": 0.0},
    ],
    "fp8": [
        {"concurrency": 1, "output_throughput": 24.53, "median_ttft_ms": 140.72, "p99_ttft_ms": 255.79, "median_tpot_ms": 39.66, "goodput_rps": 0.19},
        {"concurrency": 2, "output_throughput": 49.96, "median_ttft_ms": 107.51, "p99_ttft_ms": 110.09, "median_tpot_ms": 39.48, "goodput_rps": 0.39},
        {"concurrency": 4, "output_throughput": 98.8, "median_ttft_ms": 101.18, "p99_ttft_ms": 102.56, "median_tpot_ms": 39.96, "goodput_rps": 0.77},
        {"concurrency": 8, "output_throughput": 177.43, "median_ttft_ms": 128.01, "p99_ttft_ms": 1055.25, "median_tpot_ms": 40.93, "goodput_rps": 1.17},
        {"concurrency": 16, "output_throughput": 313.92, "median_ttft_ms": 147.52, "p99_ttft_ms": 2019.22, "median_tpot_ms": 43.11, "goodput_rps": 1.49},
        {"concurrency": 32, "output_throughput": 507.2, "median_ttft_ms": 199.09, "p99_ttft_ms": 3946.51, "median_tpot_ms": 47.73, "goodput_rps": 2.23},
        {"concurrency": 64, "output_throughput": 735.91, "median_ttft_ms": 296.42, "p99_ttft_ms": 7903.44, "median_tpot_ms": 56.31, "goodput_rps": 2.87},
    ],
}

MIXED = {
    "default": [
        {"rate": 0.5, "output_throughput": {"median": 44.09, "min": 44.06, "max": 44.88}, "median_ttft_ms": {"median": 35999.18, "min": 9752.1, "max": 39340.7}, "p99_itl_ms": {"median": 2578.99, "min": 2480.05, "max": 2863.96}},
        {"rate": 1.0, "output_throughput": {"median": 45.44, "min": 45.01, "max": 46.71}, "median_ttft_ms": {"median": 52367.56, "min": 29402.36, "max": 56992.61}, "p99_itl_ms": {"median": 2751.61, "min": 2409.74, "max": 2985.09}},
        {"rate": 2.0, "output_throughput": {"median": 46.16, "min": 44.5, "max": 47.54}, "median_ttft_ms": {"median": 59833.66, "min": 39476.3, "max": 67280.64}, "p99_itl_ms": {"median": 2512.47, "min": 2332.1, "max": 3007.5}},
    ],
    "chunk-1024": [
        {"rate": 0.5, "output_throughput": {"median": 43.26, "min": 43.11, "max": 43.32}, "median_ttft_ms": {"median": 37411.99, "min": 11475.16, "max": 41100.82}, "p99_itl_ms": {"median": 2922.44, "min": 2766.91, "max": 3066.65}},
        {"rate": 1.0, "output_throughput": {"median": 44.78, "min": 43.92, "max": 45.46}, "median_ttft_ms": {"median": 52859.49, "min": 29777.7, "max": 59333.3}, "p99_itl_ms": {"median": 2843.09, "min": 2592.19, "max": 3096.66}},
        {"rate": 2.0, "output_throughput": {"median": 43.97, "min": 43.72, "max": 45.72}, "median_ttft_ms": {"median": 62469.02, "min": 41871.45, "max": 69443.92}, "p99_itl_ms": {"median": 2929.75, "min": 2454.91, "max": 3183.3}},
    ],
}


def column(rows, key):
    return [row[key] for row in rows]

Hints

4 hints

    Solution and notes

    Locked

    Pass every check with Submit to open the reference solution and the notes.

    Run it on your computer

    Clone the repository, install numpy and run the same checks in a terminal:

    python3 scripts/practice/run.py lab-sglang-l4-serving my_answer.py
    python3 scripts/practice/run.py lab-sglang-l4-serving my_answer.py --examples

    Start my_answer.py from starter.py.

    Your code

    Python loads on the first run

    Your code is saved in this browser as you type. On a phone you can read and edit the code, but the checks are easier to use on a desktop.

    Keyboard shortcuts
    Ctrl Enter
    Run the examples
    Ctrl Shift Enter
    Submit
    Tab / Shift Tab
    Indent or outdent the lines
    Esc then Tab
    Move the focus out of the editor
    Alt H
    Show the next hint

    On a Mac, use Cmd in place of Ctrl.

    Select Run to check the examples, or Submit to run every check.