Last updated: 2026-09-07
Scheduler
Scheduler
Continuous-batching scheduler groundwork for concurrent inference requests.
Today this module owns request slot accounting and state collection only. The HTTP serving hot path still serializes generation behind ServerState.generation_mutex; the batched prefill/decode dispatch loop is not wired yet.
1 exports shown
struct
Scheduler
pub const Scheduler = struct Fixed-capacity pool of request slots used to track concurrent inference requests.
Each slot holds at most one active `Request`; slots are reused once released.
Methods
14method
Scheduler.init
pub fn init(allocator: std.mem.Allocator, max_parallel: u32) !Scheduler Initialize the scheduler with a fixed number of concurrent request slots.
method
Scheduler.enqueue
pub fn enqueue(self: *Scheduler, prompt_tokens: []const u32, params: GenerationParams) !u64 Enqueue a new request without assigning a slot (continuous-batching path).
The request sits in `pending` (state `.pending`) until `admitNext` moves it into a free slot. Unlike `submit`, this never fails on a full slot array — arrivals queue and are admitted as slots free, which is what lets a running batch admit/evict sequences between decode steps.
method
Scheduler.admitNext
pub fn admitNext(self: *Scheduler) !?u32 Admit the oldest pending request into the first free slot, if any.
Moves it out of the `pending` queue, assigns `slot_id`, and transitions it to `.prefilling`. The caller then runs prefill for every slot reported by `pendingPrefill` and transitions those to `.decoding`.
method
Scheduler.hasFreeSlot
pub fn hasFreeSlot(self: *const Scheduler) bool True if at least one slot is free.
method
Scheduler.isIdle
pub fn isIdle(self: *const Scheduler) bool True if there is no outstanding work: every slot empty and no waiters.
method
Scheduler.submit
pub fn submit(self: *Scheduler, prompt_tokens: []const u32, params: GenerationParams) !u32 Submit a new request and assign it to the first free slot.
method
Scheduler.isFull
pub fn isFull(self: *const Scheduler) bool Check if all slots are occupied.
method
Scheduler.activeCount
pub fn activeCount(self: *const Scheduler) u32 Get the number of active (non-null) requests.
method
Scheduler.transition
pub fn transition(self: *Scheduler, slot_id: u32, new_state: RequestState) !void Transition a live slot through the request state machine.
method
Scheduler.collectByState
pub fn collectByState(self: *const Scheduler, state: RequestState, out: []u32) []u32 Collect slot IDs whose request currently has `state`.
method
Scheduler.pendingPrefill
pub fn pendingPrefill(self: *Scheduler) []u32 Slot IDs of requests in the `.prefilling` state (admitted, prompt not yet processed).
The driver runs prefill for each, then transitions it to `.decoding`. activeDecoding call.
method
Scheduler.activeDecoding
pub fn activeDecoding(self: *Scheduler) []u32 Slot IDs of requests in the `.decoding` state (the running decode batch).
The driver gathers (token, position, slot) per id and issues ONE batched decode step over them. activeDecoding call.
method
Scheduler.release
pub fn release(self: *Scheduler, slot_id: u32) void Release a completed or cancelled request's slot, freeing its resources.
method
Scheduler.deinit
pub fn deinit(self: *Scheduler) void Tear down all active and pending requests and free owned buffers.