main
py 167 lines 5.55 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 from collections.abc import Iterable, Iterator
4 from itertools import chain
5 from typing import TYPE_CHECKING
6
7 from vllm.v1.sample.logits_processor.interface import (
8 AddedRequest,
9 BatchUpdate,
10 MovedRequest,
11 RemovedRequest,
12 )
13
14 if TYPE_CHECKING:
15 from vllm.v1.sample.logits_processor.interface import LogitsProcessor
16
17
18 class BatchUpdateBuilder:
19 """Helps track persistent batch state changes and build
20 a batch update data structure for logitsprocs
21 Assumptions:
22 * All information about requests removed from persistent batch
23 during a step is aggregated in self._removed through calls to
24 self.removed_append() at the beginning of a step. This must happen
25 before the first time that self.removed, self.pop_removed()
26 or self.peek_removed() are invoked in a given step
27 * After the first time that self.removed, self.pop_removed()
28 or self.peek_removed() are read in a step, no new removals
29 are registered using self.removed_append()
30 * Elements of self._removed are never directly modified, added or
31 removed (i.e. modification is only via self.removed_append() and
32 self.pop_removed())
33 Guarantees under above assumptions:
34 * self.removed is always sorted in descending order
35 * self.pop_removed() and self.peek_removed() both return
36 the lowest removed request index in the current step
37 """
38
39 _removed: list[RemovedRequest]
40 _is_removed_sorted: bool
41 added: list[AddedRequest]
42 moved: list[MovedRequest]
43
44 def __init__(
45 self,
46 removed: list[RemovedRequest] | None = None,
47 added: list[AddedRequest] | None = None,
48 moved: list[MovedRequest] | None = None,
49 ) -> None:
50 self._removed = removed or []
51 self.added = added or []
52 self.moved = moved or []
53 self._is_removed_sorted = False
54
55 # Used to track changes in the pooling case
56 # where we don't populate the added list.
57 self.batch_changed = False
58
59 def _ensure_removed_sorted(self) -> None:
60 """Sort removed request indices in
61 descending order.
62 Idempotent after first call in a
63 given step, until reset.
64 """
65 if not self._is_removed_sorted:
66 self._removed.sort(reverse=True)
67 self._is_removed_sorted = True
68
69 @property
70 def removed(self) -> list[RemovedRequest]:
71 """Removed request indices sorted in
72 descending order"""
73 self._ensure_removed_sorted()
74 return self._removed
75
76 def removed_append(self, index: int) -> None:
77 """Register the removal of a request from the persistent batch.
78
79 Must not be called after the first time self.removed,
80 self.pop_removed() or self.peek_removed() are invoked.
81
82 Args:
83 index: request index
84
85 """
86 if self._is_removed_sorted:
87 raise RuntimeError(
88 "Cannot register new removed request after self.removed has been read."
89 )
90 self._removed.append(index)
91 self.batch_changed = True
92
93 def has_removed(self) -> bool:
94 return bool(self._removed)
95
96 def peek_removed(self) -> int | None:
97 """Return lowest removed request index."""
98 if self.has_removed():
99 self._ensure_removed_sorted()
100 return self._removed[-1]
101 return None
102
103 def pop_removed(self) -> int | None:
104 """Pop lowest removed request index."""
105 if self.has_removed():
106 self._ensure_removed_sorted()
107 return self._removed.pop()
108 return None
109
110 def reset(self) -> bool:
111 """Returns True if there were any changes to the batch."""
112 self._is_removed_sorted = False
113 self._removed.clear()
114 self.added.clear()
115 self.moved.clear()
116 batch_changed = self.batch_changed
117 self.batch_changed = False
118 return batch_changed
119
120 def get_and_reset(self, batch_size: int) -> BatchUpdate | None:
121 """Generate a logitsprocs batch update data structure and reset
122 internal batch update builder state.
123
124 Args:
125 batch_size: current persistent batch size
126
127 Returns:
128 Frozen logitsprocs batch update instance; `None` if no updates
129
130 """
131 # Reset removal-sorting logic
132 self._is_removed_sorted = False
133 self.batch_changed = False
134 if not any((self._removed, self.moved, self.added)):
135 # No update; short-circuit
136 return None
137 # Build batch state update
138 batch_update = BatchUpdate(
139 batch_size=batch_size,
140 removed=self._removed,
141 moved=self.moved,
142 added=self.added,
143 )
144 self._removed = []
145 self.moved = []
146 self.added = []
147 return batch_update
148
149
150 class LogitsProcessors:
151 """Encapsulates initialized logitsproc objects."""
152
153 def __init__(self, logitsprocs: Iterable["LogitsProcessor"] | None = None) -> None:
154 self.argmax_invariant: list[LogitsProcessor] = []
155 self.non_argmax_invariant: list[LogitsProcessor] = []
156 if logitsprocs:
157 for logitproc in logitsprocs:
158 (
159 self.argmax_invariant
160 if logitproc.is_argmax_invariant()
161 else self.non_argmax_invariant
162 ).append(logitproc)
163
164 @property
165 def all(self) -> Iterator["LogitsProcessor"]:
166 """Iterator over all logits processors."""
167 return chain(self.argmax_invariant, self.non_argmax_invariant)