mirror of
https://git.datalinker.icu/vllm-project/vllm.git
synced 2026-07-12 18:57:23 +08:00
Fix removal from heap
Signed-off-by: Harry Mellor <19981378+hmellor@users.noreply.github.com> Signed-off-by: weichen <calvin_zhu0210@outlook.com>
This commit is contained in:
parent
4fe722fae5
commit
601387735c
@ -6,6 +6,7 @@ from abc import ABC, abstractmethod
|
|||||||
from collections import deque
|
from collections import deque
|
||||||
from collections.abc import Iterable, Iterator
|
from collections.abc import Iterable, Iterator
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from vllm.v1.core.sched.policy.weighted_score_sorter import WeightedScoreSorter
|
from vllm.v1.core.sched.policy.weighted_score_sorter import WeightedScoreSorter
|
||||||
from vllm.v1.request import Request
|
from vllm.v1.request import Request
|
||||||
@ -135,73 +136,57 @@ class FCFSRequestQueue(deque[Request], RequestQueue):
|
|||||||
return super().__reversed__()
|
return super().__reversed__()
|
||||||
|
|
||||||
|
|
||||||
class HeapBasedRequestQueue(RequestQueue, ABC):
|
class RequestHeap(RequestQueue):
|
||||||
"""Base class for heap-based request queues (priority and SJF)."""
|
"""A queue that supports heap operations."""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self._heap: list = []
|
self._heap: list = []
|
||||||
|
|
||||||
@abstractmethod
|
def _request_to_heap(self, request: Request) -> Any:
|
||||||
def _to_heap_element(self, request: Request) -> object:
|
|
||||||
"""Convert a request to the appropriate heap element."""
|
"""Convert a request to the appropriate heap element."""
|
||||||
pass
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
def _heap_to_request(self, element: Any) -> Request:
|
||||||
def _from_heap_element(self, heap_element: object) -> Request:
|
|
||||||
"""Extract the request from a heap element."""
|
"""Extract the request from a heap element."""
|
||||||
pass
|
raise NotImplementedError
|
||||||
|
|
||||||
def add_request(self, request: Request) -> None:
|
def add_request(self, request: Request) -> None:
|
||||||
"""Add a request to the heap queue."""
|
"""Add a request to the queue according to heap priority."""
|
||||||
heap_element = self._to_heap_element(request)
|
heapq.heappush(self._heap, self._request_to_heap(request))
|
||||||
heapq.heappush(self._heap, heap_element)
|
|
||||||
|
|
||||||
def pop_request(self) -> Request:
|
def pop_request(self) -> Request:
|
||||||
"""Pop the highest priority request from the heap."""
|
"""Pop the highest priority request from the heap."""
|
||||||
if not self._heap:
|
if not self._heap:
|
||||||
raise IndexError("pop from empty heap")
|
raise IndexError("pop from empty heap")
|
||||||
heap_element = heapq.heappop(self._heap)
|
return self._heap_to_request(heapq.heappop(self._heap))
|
||||||
return self._from_heap_element(heap_element)
|
|
||||||
|
|
||||||
def peek_request(self) -> Request:
|
def peek_request(self) -> Request:
|
||||||
"""Peek at the highest priority request without removing it."""
|
"""Peek at the highest priority request in the heap without removing it."""
|
||||||
if not self._heap:
|
if not self._heap:
|
||||||
raise IndexError("peek from empty heap")
|
raise IndexError("peek from empty heap")
|
||||||
return self._from_heap_element(self._heap[0])
|
return self._heap_to_request(self._heap[0])
|
||||||
|
|
||||||
def prepend_request(self, request: Request) -> None:
|
def prepend_request(self, request: Request) -> None:
|
||||||
"""
|
"""Add a request to the heap. In heap-based queues there is no beginning as
|
||||||
Add request to the queue. In heap-based queues, "prepend" has no
|
elements are ordered by priority/score. This behaves like add_request."""
|
||||||
special meaning as elements are ordered by priority/score. This
|
|
||||||
behaves like add_request.
|
|
||||||
"""
|
|
||||||
self.add_request(request)
|
self.add_request(request)
|
||||||
|
|
||||||
def prepend_requests(self, requests: RequestQueue) -> None:
|
def prepend_requests(self, requests: RequestQueue) -> None:
|
||||||
"""
|
"""Add all requests from another queue to the heap. In heap-based queues there
|
||||||
Add all requests from another queue. In heap-based queues,
|
is no beginning as elements are ordered by priority/score. This behaves like
|
||||||
"prepend" has no special meaning as elements are ordered by
|
add_request."""
|
||||||
priority/score. This behaves like adding all requests.
|
|
||||||
"""
|
|
||||||
for request in requests:
|
for request in requests:
|
||||||
self.add_request(request)
|
self.add_request(request)
|
||||||
|
|
||||||
def remove_request(self, request: Request) -> None:
|
def remove_request(self, request: Request) -> None:
|
||||||
"""Remove a specific request from the heap."""
|
"""Remove a specific request from the heap."""
|
||||||
try:
|
self._heap.remove(self._request_to_heap(request))
|
||||||
self._heap.remove(request)
|
heapq.heapify(self._heap)
|
||||||
heapq.heapify(self._heap)
|
|
||||||
except ValueError as err:
|
|
||||||
raise ValueError(
|
|
||||||
f"Request {request.request_id} not found in queue"
|
|
||||||
) from err
|
|
||||||
|
|
||||||
def remove_requests(self, requests: Iterable[Request]) -> None:
|
def remove_requests(self, requests: Iterable[Request]) -> None:
|
||||||
"""Remove multiple specific requests from the heap."""
|
"""Remove multiple specific requests from the heap."""
|
||||||
requests_to_remove = (
|
remove = requests if isinstance(requests, set) else set(requests)
|
||||||
set(requests) if not isinstance(requests, set) else requests
|
self._heap = [h for h in self._heap if self._heap_to_request(h) not in remove]
|
||||||
)
|
|
||||||
self._heap = [r for r in self._heap if r not in requests_to_remove]
|
|
||||||
heapq.heapify(self._heap)
|
heapq.heapify(self._heap)
|
||||||
|
|
||||||
def __bool__(self) -> bool:
|
def __bool__(self) -> bool:
|
||||||
@ -213,40 +198,37 @@ class HeapBasedRequestQueue(RequestQueue, ABC):
|
|||||||
return len(self._heap)
|
return len(self._heap)
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[Request]:
|
def __iter__(self) -> Iterator[Request]:
|
||||||
"""Iterate over requests in priority/score order."""
|
"""Iterate over the queue to heap order."""
|
||||||
heap_copy = self._heap.copy()
|
heap_copy = self._heap[:]
|
||||||
while heap_copy:
|
while heap_copy:
|
||||||
heap_element = heapq.heappop(heap_copy)
|
yield self._heap_to_request(heapq.heappop(heap_copy))
|
||||||
yield self._from_heap_element(heap_element)
|
|
||||||
|
|
||||||
def __reversed__(self) -> Iterator[Request]:
|
def __reversed__(self) -> Iterator[Request]:
|
||||||
"""Iterate over requests in reverse priority/score order."""
|
"""Iterate over the queue in reverse heap order."""
|
||||||
return reversed(list(self))
|
return reversed(list(self))
|
||||||
|
|
||||||
|
|
||||||
class PriorityRequestQueue(HeapBasedRequestQueue):
|
class PriorityRequestQueue(RequestHeap):
|
||||||
"""
|
"""A priority queue that supports heap operations.
|
||||||
A priority queue where requests are ordered by (priority, arrival_time).
|
|
||||||
Lower priority values and earlier arrival times are processed first.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def _to_heap_element(self, request: Request) -> Request:
|
Respects the ordering defined in the Request class, where requests with a smaller
|
||||||
|
value of `priority` are processed first. If multiple requests have the same
|
||||||
|
priority, the one with the earlier `arrival_time` is processed first."""
|
||||||
|
|
||||||
|
def _request_to_heap(self, request: Request) -> Request:
|
||||||
"""For priority queue, the heap element is the request itself."""
|
"""For priority queue, the heap element is the request itself."""
|
||||||
return request
|
return request
|
||||||
|
|
||||||
def _from_heap_element(self, heap_element: object) -> Request:
|
def _heap_to_request(self, element: Request) -> Request:
|
||||||
"""Extract request from heap element with type checking."""
|
"""Extract request from heap element with type checking."""
|
||||||
assert isinstance(heap_element, Request)
|
return element
|
||||||
return heap_element
|
|
||||||
|
|
||||||
|
|
||||||
class SJFRequestQueue(HeapBasedRequestQueue):
|
class SJFRequestQueue(RequestHeap):
|
||||||
"""
|
"""A Shortest Job First (SJF) queue where requests are ordered by weighted score.
|
||||||
A Shortest Job First (SJF) queue where requests are ordered by weighted score.
|
Requests with higher weighted scores (shorter jobs) are processed first."""
|
||||||
Requests with higher weighted scores (shorter jobs) are processed first.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def _to_heap_element(self, request: Request) -> tuple[WeightedScoreSorter, Request]:
|
def _request_to_heap(self, request: Request) -> tuple[WeightedScoreSorter, Request]:
|
||||||
"""Convert request to (weighted_score, request) tuple for heap."""
|
"""Convert request to (weighted_score, request) tuple for heap."""
|
||||||
assert request.prompt_token_ids is not None
|
assert request.prompt_token_ids is not None
|
||||||
return (
|
return (
|
||||||
@ -254,26 +236,11 @@ class SJFRequestQueue(HeapBasedRequestQueue):
|
|||||||
request,
|
request,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _from_heap_element(self, heap_element: object) -> Request:
|
def _heap_to_request(self, element: tuple[WeightedScoreSorter, Request]) -> Request:
|
||||||
"""Extract request from the (score, request) tuple with type checking."""
|
"""Extract request from the (score, request) tuple with type checking."""
|
||||||
assert isinstance(heap_element, tuple) and len(heap_element) == 2
|
_, request = element
|
||||||
_, request = heap_element
|
|
||||||
return request
|
return request
|
||||||
|
|
||||||
def remove_request(self, request: Request) -> None:
|
|
||||||
"""Remove a specific request from the SJF heap."""
|
|
||||||
original_length = len(self._heap)
|
|
||||||
self._heap = [(ws, r) for (ws, r) in self._heap if r != request]
|
|
||||||
if len(self._heap) == original_length:
|
|
||||||
raise ValueError(f"Request {request.request_id} not found in SJF queue")
|
|
||||||
heapq.heapify(self._heap)
|
|
||||||
|
|
||||||
def remove_requests(self, requests: Iterable[Request]) -> None:
|
|
||||||
"""Remove multiple specific requests from the SJF heap."""
|
|
||||||
requests_to_remove = set(requests)
|
|
||||||
self._heap = [(ws, r) for (ws, r) in self._heap if r not in requests_to_remove]
|
|
||||||
heapq.heapify(self._heap)
|
|
||||||
|
|
||||||
|
|
||||||
def create_request_queue(policy: SchedulingPolicy) -> RequestQueue:
|
def create_request_queue(policy: SchedulingPolicy) -> RequestQueue:
|
||||||
"""Create request queue based on scheduling policy."""
|
"""Create request queue based on scheduling policy."""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user