Configurable decode retraction order (#30573)

Co-authored-by: tanujtiwari1998 <168470992+tanujtiwari1998@users.noreply.github.com>
This commit is contained in:
Lianmin Zheng
2026-07-09 17:55:26 -07:00
committed by GitHub
co-authored by tanujtiwari1998
parent 5be9c9f7c6
commit 32c8973ce8
2 changed files with 72 additions and 15 deletions
+54 -15
View File
@@ -40,6 +40,7 @@ import copy
import dataclasses
import logging
import re
import sys
from array import array
from concurrent.futures import Future
from enum import Enum, auto
@@ -2552,21 +2553,13 @@ class ScheduleBatch(ScheduleBatchDisaggregationDecodeMixin):
self, server_args: ServerArgs
) -> Tuple[List[Req], float, List[Req]]:
"""Retract the decoding requests when there is not enough memory."""
sorted_indices = list(range(len(self.reqs)))
# TODO(lsyin): improve retraction policy for radix cache
# For spec decoding, filter_batch API can only filter
# requests from the back, so we can only retract from the back.
# TODO(sang): Clean up finish path and support better retract
# policy.
if not server_args.speculative_algorithm:
sorted_indices.sort(
key=lambda i: (
len(self.reqs[i].output_ids),
-len(self.reqs[i].origin_input_ids),
),
reverse=True,
)
sorted_indices = self._get_decode_retraction_order(
self.reqs,
server_args,
allow_policy_sort=(
self.spec_algorithm is None or self.spec_algorithm.is_none()
),
)
retracted_reqs = []
first_iter = True
@@ -2612,6 +2605,52 @@ class ScheduleBatch(ScheduleBatchDisaggregationDecodeMixin):
return retracted_reqs, new_estimate_ratio, reqs_to_abort
@staticmethod
def _get_decode_retraction_order(
reqs: List[Req], server_args: ServerArgs, *, allow_policy_sort: bool
) -> List[int]:
"""Return indices ordered from most-preferred to least-preferred to keep.
The retraction loop pops from the end of this list, so the least-preferred
request is retracted first.
"""
sorted_indices = list(range(len(reqs)))
# TODO(lsyin): improve retraction policy for radix cache
# For spec decoding, filter_batch API can only filter requests from the
# back, so we can only retract from the back.
# TODO(sang): Clean up finish path and support better retract policy.
if not allow_policy_sort:
return sorted_indices
def length_key(req: Req) -> Tuple[int, int]:
return (len(req.output_ids), -len(req.origin_input_ids))
if server_args.retraction_policy == "priority":
priority_sign = 1 if server_args.schedule_low_priority_values_first else -1
def retraction_key(req: Req) -> Tuple[int, int, int]:
priority = req.priority
if priority is None:
priority = (
sys.maxsize
if server_args.schedule_low_priority_values_first
else -sys.maxsize - 1
)
return (priority * (-priority_sign), *length_key(req))
sorted_indices.sort(
key=lambda i: retraction_key(reqs[i]),
reverse=True,
)
return sorted_indices
sorted_indices.sort(
key=lambda i: length_key(reqs[i]),
reverse=True,
)
return sorted_indices
def release_req(self, idx: int, remaing_req_count: int, server_args: ServerArgs):
release_req(
req=self.reqs[idx],
+18
View File
@@ -292,6 +292,7 @@ FP4_GEMM_RUNNER_BACKEND_CHOICES = [
BF16_GEMM_BACKEND_CHOICES = ["auto", "cutedsl"]
RADIX_EVICTION_POLICY_CHOICES = ["lru", "lfu", "slru", "priority"]
RETRACTION_POLICY_CHOICES = ["length", "priority"]
RL_ON_POLICY_TARGET_CHOICES = ["fsdp"]
@@ -736,6 +737,19 @@ class ServerArgs:
int,
"Minimum difference in priorities for an incoming request to have to preempt running request(s).",
] = 10
retraction_policy: A[
str,
Arg(
help=(
"The decode retraction policy to use when the KV cache is full. "
"'length' preserves the existing behavior and retracts short-output, "
"long-input requests first. 'priority' retracts lower-priority "
"requests first, using the same priority direction as priority "
"scheduling."
),
choices=RETRACTION_POLICY_CHOICES,
),
] = "length"
schedule_conservativeness: A[
float,
"How conservative the schedule policy is. A larger value means more conservative scheduling. Use a larger value if you see requests being retracted frequently.",
@@ -7004,6 +7018,10 @@ class ServerArgs:
logger.warning(
"--default-priority-value has no effect without --enable-priority-scheduling"
)
if self.retraction_policy == "priority" and not self.enable_priority_scheduling:
raise ValueError(
"--retraction-policy priority requires --enable-priority-scheduling"
)
# Check hisparse
# Moved to the resolution pipeline (arg_groups/overrides.py: