AI engineering and inferenceLoading progress…

Service objectives

Trace static and iteration-level schedules and explain chunked prefill, preemption and latency tradeoffs.

Judging a schedule by service objectives

A schedule is good or bad relative to a goal. State the goal as an objective such as "95% of requests finish within 0.5 s" and measure it with percentiles and attainment under a stated arrival process (how requests really arrive, in bursts or evenly). A mean can look fine while the tail is bad, and a fixed batch that happens to suit your test says little about real traffic.

latency objective (s)0.5
0.3
0.33
0.35
0.38
0.4
0.42
0.45
0.5
0.9
1.2
attainment (≤ 0.5 s): 8 of 10 = 0.8 mean 0.523 s median 0.41 s p90 0.93 s p99 1.173 s

A schedule can keep the hardware 100% busy and still miss an interactive target, and a good average can hide a slow tail. Judge a policy with tail latency and completion rates under a stated arrival process, not on one favourable fixed batch.

Ten request latencies. Move the objective and read attainment, mean and tail.

Predict first. Can a schedule with higher utilisation still miss an interactive latency target?

Chapter context

Requests arrive at different times and finish after different output lengths. Scheduling decides which work enters each iteration and how waiting prompts compete with ongoing generation.

Chapter reference: math, worked example & code

This section belongs to the whole chapter, so it is the same on every lesson in it and may cover a different lesson's topic. The code for the experiment you just ran is inside the experiment itself.

Math and notation

In a simplified equal-cost decode schedule, utilization = active sequence-iterations / available sequence-iterations. This omits prefill costs and assumes uniform iteration time. A real scheduler needs measured compute, memory and latency constraints.

Worked example

Two slots serve requests A,B,C with output lengths 2,1,2. Static groups run A+B for two iterations, then C alone for two: 5 active slots out of 8 available. Continuous admission runs A+B, then A+C, then C: 5 active slots out of 6. Utilization rises from 62.5% to about 83.33% in this toy schedule; real token costs are not equal.

Reference code

The following example uses the Python standard library and does not call a remote service.

from math import isclose
static=[['A','B'],['A',None],['C',None],['C',None]]
continuous=[['A','B'],['A','C'],['C',None]]
util=lambda rows: sum(x is not None for row in rows for x in row)/(2*len(rows))
assert util(static) == .625
assert isclose(util(continuous),5/6)

Python examples are provided for study and local execution; this page does not execute Python.

Common mistakes

Continuous batching does not guarantee a fixed improvement. Chunked prefill changes scheduling granularity, not the model's context dependencies. Include cache movement or recomputation costs when comparing preemption policies.