Skip to main content
Scheduler decides which sequences to run on each forward pass and manages the allocation of KV cache blocks through BlockManager. It maintains two queues — waiting and running — and alternates between prefill batches (promoting sequences from waiting) and decode batches (stepping running sequences by one token).

Constructor

int
required
Maximum number of sequences that can be scheduled in a single batch, whether during prefill or decode.
int
required
Maximum total tokens across all sequences in one batch. Prefill counts the full prompt length; decode counts one token per sequence.
int
required
Total number of KV cache blocks available in the pool. Passed directly to BlockManager. At runtime this is overridden by ModelRunner.allocate_kv_cache() to the actual GPU-measured value.
int
required
Number of tokens per KV cache block. Must match the value used by ModelRunner.
int
required
EOS token ID used to detect end-of-sequence during postprocessing.

Queue model

The scheduler maintains two deque objects:
  • waiting — sequences that have been added but not yet allocated KV cache blocks.
  • running — sequences that own KV cache blocks and are actively being decoded.
On each call to schedule(), the scheduler first tries to promote sequences from waiting to running (prefill). Only if no waiting sequence can be admitted does it then schedule a decode step over the sequences in running.

Methods

add_sequence

Appends a Sequence object to the end of the waiting queue. Called by LLMEngine.add_prompt() after tokenization.
Sequence
required
A fully constructed Sequence object. The sequence must already have its token IDs and SamplingParams fields set.

schedule

Selects sequences for the next batch and returns them together with a flag indicating whether the batch is a prefill or a decode. Prefill path — iterates the waiting queue front-to-back:
  • Checks BlockManager.can_allocate(seq) and the max_num_batched_tokens / max_num_sequences limits.
  • Allocates KV blocks, sets seq.status = RUNNING, and moves the sequence to running.
  • Stops as soon as any limit is hit or the queue is empty.
  • Returns (scheduled_sequences, True) if any sequences were admitted.
Decode path — only reached when no sequence was admitted from waiting:
  • Iterates the running queue and checks BlockManager.can_append(seq).
  • If a running sequence cannot be appended (no free block for the next token), it is preempted: the least-recently-scheduled running sequence is moved back to waiting.
  • Stops when max_num_batched_tokens or max_num_sequences is reached.
  • Returns (scheduled_sequences, False).

Return value

list[Sequence]
Sequences selected for this forward pass. Empty when both queues are empty.
bool
True when the batch is a prefill pass; False for a decode pass.

postprocess

Called after ModelRunner.run() returns sampled token IDs. For each (seq, token_id) pair:
  1. Appends token_id to the sequence’s token list.
  2. Evaluates the three stopping conditions below.
  3. If any condition is met, sets seq.status = FINISHED, deallocates its KV blocks, and removes it from the running queue.

Stopping conditions

list[Sequence]
required
The same list returned by the preceding schedule() call.
list[int]
required
One sampled token ID per sequence, in the same order as seqs.

preempt

Moves a running sequence back to the front of the waiting queue. Its KV cache blocks are deallocated so they can be used by other sequences. When the sequence is rescheduled later it will go through prefill again.
Sequence
required
A sequence currently in the running queue.

is_finished

Returns True when both the waiting and running queues are empty, indicating that all submitted sequences have completed generation.

Example