vllm-project/vllm
Scheduler
Active contributors: Cyrus Leung, Cody Yu, Andreas Karatzas, Nick Hill.
Purpose
The scheduler decides, every engine step, which requests advance, how many tokens each request runs (prefill or decode), and which KV cache blocks back them. It implements continuous batching, chunked prefill, prefix-cache reuse, structured-output budget enforcement, KV-connector handoff, and (when enabled) async scheduling.
Directory layout
vllm/v1/core/sched/
├── __init__.py
├── interface.py # SchedulerInterface (abstract) + PauseState
├── scheduler.py # The Scheduler implementation (2,308 lines)
├── async_scheduler.py # AsyncScheduler subclass (overlaps schedule with execute)
├── output.py # SchedulerOutput, NewRequestData, CachedRequestData, GrammarOutput
├── request_queue.py # FIFO / priority request queues
└── utils.py # check_stop, remove_all helpersKey abstractions
| Abstraction | File | Role |
|---|---|---|
SchedulerInterface |
vllm/v1/core/sched/interface.py |
Abstract base |
Scheduler |
vllm/v1/core/sched/scheduler.py |
The concrete scheduler |
AsyncScheduler |
vllm/v1/core/sched/async_scheduler.py |
Variant that schedules step N+1 while step N executes |
SchedulerOutput |
vllm/v1/core/sched/output.py |
What the scheduler emits each step (running set, blocks, MM hashes, grammar) |
RequestQueue |
vllm/v1/core/sched/request_queue.py |
FIFO and priority queues for waiting requests |
Request |
vllm/v1/request.py |
The scheduler's view of a request |
RequestStatus |
vllm/v1/request.py |
Enum: WAITING, RUNNING, PREEMPTED, FINISHED, etc. |
How a step is scheduled
graph TD
Wait[Waiting queue<br/>FIFO or priority]
Run[Running list]
Sched[Scheduler.schedule]
Budget[Budget:<br/>max_num_running_reqs<br/>max_num_scheduled_tokens<br/>token_budget]
KV[KVCacheManager.allocate]
PC[Prefix cache lookup<br/>BlockHash chain]
GR[StructuredOutputManager.grammar_step]
Pre[Preempt running if needed]
Out[SchedulerOutput<br/>NewRequestData / CachedRequestData / FinishedRequest]
Wait -->|admit if budget allows| Sched
Run --> Sched
Sched --> Budget
Sched --> KV --> PC
Sched --> GR
Sched --> Pre
Sched --> OutEach call to Scheduler.schedule():
- Walks the running list in priority order. For each request, it computes how many additional tokens to compute this step (decoding step = 1 + draft tokens; prefill chunk size for prefill stage), respecting the global token budget.
- Tries to admit waiting requests while there's slack: it consults the KV cache manager to allocate blocks (with prefix-cache reuse) and grammar manager to make sure structured-output state is ready.
- Preempts running requests whose KV blocks must be evicted to admit higher-priority work — preempted requests go back to the head of the waiting queue.
- Builds a
SchedulerOutput: lists ofNewRequestData(just-admitted),CachedRequestData(continuing), andfinished_req_ids(terminal in this step), plus the per-request token budgets and KV block layouts. - Records
EngineCoreEvents (QUEUED,SCHEDULED,PREEMPTED) used by stats loggers.
After the executor returns a ModelRunnerOutput, Scheduler.update_from_output:
- Applies the new tokens to each running
Request. - Detects stop strings, max-tokens, repetition, and other terminal conditions via
check_stop. - Releases KV blocks for finished requests (
KVCacheManager.free). - Returns
EngineCoreOutputsto the EngineCore loop.
Scheduling policies
SchedulerConfig.policy chooses the request queue:
fcfs— first-come-first-serve.priority— priority queue keyed onRequest.priority(set per-request).
SchedulerConfig.scheduling_policy (FCFS, etc.) lives in vllm/v1/core/sched/request_queue.py::SchedulingPolicy.
Chunked prefill
Long prompts are broken into chunks so that decode requests in the same batch are not starved. The chunk size is dynamic: the scheduler computes tokens_remaining = token_budget - decode_tokens and assigns it to the next prefill request. Chunked prefill is the default; it can be disabled via config but only at significant throughput cost.
Prefix caching
When a request is admitted, the scheduler asks the KV cache manager for its prefix-cached blocks: any leading hash-matched block sequence is reused, and only the tail is computed. Implementation:
- Hashing in
vllm/v1/core/kv_cache_utils.py(BlockHash,get_request_block_hasher). - Reuse in
KVCacheManager.allocateviaKVCacheCoordinator. - Per-step prefix-cache stats on
SchedulerStats.prefix_cache_stats.
See KV cache and prefix caching.
KV connectors
Disaggregated prefill/decode is integrated at the scheduler level. The scheduler:
- Asks the KV connector (e.g., NIXL, Redis, Mooncake) whether KV for a request is already on a remote prefill instance.
- If so, schedules a "load" step that pulls the KV blocks before the first decode forward pass.
- If outbound (we are the prefill side), schedules a "save" step that pushes KV after each layer.
KVConnectorBase_V1 lives in vllm/distributed/kv_transfer/kv_connector/v1/base.py; the scheduler's hooks are in Scheduler.schedule and update_from_output. Per-step connector metadata is KVConnectorMetadata.
Async scheduling
SchedulerConfig.async_scheduling = True swaps in AsyncScheduler (vllm/v1/core/sched/async_scheduler.py), which calls executor.execute_model(..., non_block=True) and immediately starts scheduling the next step. The previous step's Future[ModelRunnerOutput] is awaited at the start of update_from_output. This roughly doubles scheduler concurrency on ≥H100-class GPUs.
Encoder cache
For multimodal models the scheduler cooperates with EncoderCacheManager / EncoderDecoderCacheManager (vllm/v1/core/encoder_cache_manager.py) to reserve encoder cache slots before scheduling cross-attention work.
Key source files
| File | Purpose |
|---|---|
vllm/v1/core/sched/scheduler.py |
The main scheduler logic |
vllm/v1/core/sched/output.py |
SchedulerOutput dataclass family |
vllm/v1/core/sched/request_queue.py |
FIFO / priority queues |
vllm/v1/core/sched/async_scheduler.py |
Async scheduling subclass |
vllm/v1/core/sched/utils.py |
check_stop, remove_all |
vllm/v1/core/sched/interface.py |
Abstract base (used by tests and alt schedulers) |
vllm/v1/request.py |
Request, RequestStatus, StreamingUpdate |
vllm/v1/metrics/perf.py |
PerfStats, ModelMetrics consumed by the scheduler |
Entry points for modification
- New scheduling policy: extend
SchedulingPolicyinrequest_queue.pyand add a queue. - New stop condition: implement
check_stopsemantics invllm/v1/core/sched/utils.py. Add a correspondingFinishReason. - New per-step state for the model: extend
SchedulerOutput/CachedRequestDataand consume it invllm/v1/worker/gpu_model_runner.py. - New connector hook: implement
KVConnectorBase_V1; the scheduler will call yourstart_load_kv/wait_for_saveautomatically.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.