lmcache-cli 0.5.6rc4.dev27__py3-none-any.whl → 0.5.7.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lmcache/_version.py +3 -3
- lmcache/cli/commands/bench/l2_adapter_bench/data.py +1 -1
- lmcache/cli/commands/query/_request.py +22 -6
- lmcache/integration/sglang/multi_process_adapter.py +1 -1
- lmcache/integration/sglang/unified_lmcache_mp_connector.py +28 -31
- lmcache/integration/vllm/lmcache_mp_connector.py +49 -36
- lmcache/integration/vllm/vllm_multi_process_adapter.py +233 -23
- lmcache/utils.py +11 -0
- lmcache/v1/distributed/l1_manager.py +2 -1
- lmcache/v1/internal_api_server/vllm/cache_api.py +1 -1
- lmcache/v1/memory_management.py +1 -1
- lmcache/v1/mp_observability/event.py +4 -1
- lmcache/v1/mp_observability/event_bus.py +28 -0
- lmcache/v1/multiprocess/config.py +11 -0
- lmcache/v1/multiprocess/custom_types.py +33 -0
- lmcache/v1/multiprocess/futures.py +63 -0
- lmcache/v1/multiprocess/modules/kv_events.py +302 -0
- lmcache/v1/multiprocess/modules/lmcache_driven_transfer.py +17 -2
- lmcache/v1/multiprocess/modules/management.py +3 -9
- lmcache/v1/multiprocess/request_handler.py +6 -3
- lmcache/v1/multiprocess/rpc.py +16 -4
- lmcache/v1/multiprocess/server.py +10 -3
- lmcache/v1/multiprocess/transfer_context/async_engine_driven.py +3 -2
- lmcache/v1/multiprocess/transfer_context/base.py +9 -3
- lmcache/v1/multiprocess/transfer_context/worker_transfer.py +53 -50
- lmcache/v1/multiprocess/transfer_mode.py +30 -0
- lmcache/v1/multiprocess/transport/base.py +7 -1
- lmcache/v1/multiprocess/transport/grpc_impl/client.py +26 -6
- lmcache/v1/multiprocess/transport/grpc_impl/descriptors.py +1 -1
- lmcache/v1/multiprocess/transport/grpc_impl/method_registry.py +6 -0
- lmcache/v1/multiprocess/transport/grpc_impl/protos/observability_service.proto +26 -0
- lmcache/v1/multiprocess/transport/grpc_impl/server.py +42 -1
- lmcache/v1/multiprocess/transport/zmq_impl/client.py +4 -4
- lmcache/v1/multiprocess/transport/zmq_impl/mq.py +163 -10
- lmcache/v1/platform/base/device_spec.py +33 -4
- lmcache/v1/platform/base/ipc_wire.py +195 -0
- lmcache/v1/platform/base/ipc_wrapper.py +71 -23
- lmcache/v1/platform/devices/cpu/__init__.py +15 -0
- lmcache/v1/platform/devices/cpu/shm.py +23 -1
- lmcache/v1/platform/devices/cuda/__init__.py +4 -0
- lmcache/v1/platform/devices/cuda/ipc_wrapper.py +82 -7
- lmcache/v1/platform/devices/musa/__init__.py +6 -1
- lmcache/v1/platform/devices/musa/ipc_wrapper.py +16 -0
- lmcache/v1/platform/devices/neuron/__init__.py +1 -1
- lmcache/v1/platform/devices/npu/__init__.py +4 -0
- lmcache/v1/platform/devices/npu/ipc_wrapper.py +47 -0
- lmcache/v1/platform/devices/rbln/__init__.py +3 -4
- lmcache/v1/platform/torch_ops/_kv_format.py +1 -49
- lmcache/v1/platform/torch_ops/mem_kernels.py +4 -3
- lmcache/v1/platform/torch_ops/mp_mem_kernels.py +48 -61
- {lmcache_cli-0.5.6rc4.dev27.dist-info → lmcache_cli-0.5.7.dev0.dist-info}/METADATA +1 -1
- {lmcache_cli-0.5.6rc4.dev27.dist-info → lmcache_cli-0.5.7.dev0.dist-info}/RECORD +56 -53
- {lmcache_cli-0.5.6rc4.dev27.dist-info → lmcache_cli-0.5.7.dev0.dist-info}/WHEEL +0 -0
- {lmcache_cli-0.5.6rc4.dev27.dist-info → lmcache_cli-0.5.7.dev0.dist-info}/entry_points.txt +0 -0
- {lmcache_cli-0.5.6rc4.dev27.dist-info → lmcache_cli-0.5.7.dev0.dist-info}/licenses/LICENSE +0 -0
- {lmcache_cli-0.5.6rc4.dev27.dist-info → lmcache_cli-0.5.7.dev0.dist-info}/top_level.txt +0 -0
lmcache/_version.py
CHANGED
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.5.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 5,
|
|
21
|
+
__version__ = version = '0.5.7.dev0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 5, 7, 'dev0')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g3e11e1081'
|
|
@@ -140,7 +140,7 @@ def make_memory_objects(
|
|
|
140
140
|
metadata = MemoryObjMetadata(
|
|
141
141
|
shape=torch.Size([data_size]),
|
|
142
142
|
dtype=torch.uint8,
|
|
143
|
-
address=
|
|
143
|
+
address=start,
|
|
144
144
|
phy_size=data_size * raw_tensor.element_size(),
|
|
145
145
|
fmt=MemoryFormat.KV_2LTD,
|
|
146
146
|
ref_count=1,
|
|
@@ -130,8 +130,23 @@ def _stream(
|
|
|
130
130
|
chat: bool,
|
|
131
131
|
max_tokens: int,
|
|
132
132
|
) -> dict[str, Any]:
|
|
133
|
-
"""POST with ``stream: true
|
|
134
|
-
|
|
133
|
+
"""POST with ``stream: true`` and collect text and token/latency metrics.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
url: Endpoint URL for the streaming request.
|
|
137
|
+
body: OpenAI-compatible request payload.
|
|
138
|
+
timeout: HTTP request timeout in seconds.
|
|
139
|
+
chat: Whether the endpoint uses chat completion chunks.
|
|
140
|
+
max_tokens: Output-token estimate when the server omits its count.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Completion text, server token counts, and measured latency metrics.
|
|
144
|
+
A reported completion count of zero is preserved.
|
|
145
|
+
|
|
146
|
+
Raises:
|
|
147
|
+
RuntimeError: If the HTTP request fails, the server reports an error,
|
|
148
|
+
or the stream contains neither text nor usage.
|
|
149
|
+
"""
|
|
135
150
|
payload = {
|
|
136
151
|
**body,
|
|
137
152
|
"stream": True,
|
|
@@ -199,9 +214,8 @@ def _stream(
|
|
|
199
214
|
|
|
200
215
|
u = usage or {}
|
|
201
216
|
prompt_tokens = int(u.get("prompt_tokens") or 0)
|
|
202
|
-
num_completion =
|
|
203
|
-
|
|
204
|
-
num_generated = num_completion if num_completion > 0 else max_tokens
|
|
217
|
+
num_completion = u.get("completion_tokens")
|
|
218
|
+
num_generated = int(num_completion) if num_completion is not None else max_tokens
|
|
205
219
|
if first_token_t is None:
|
|
206
220
|
# Use total round-trip as a conservative TTFT approximation.
|
|
207
221
|
ttft_s = t1 - t0
|
|
@@ -294,7 +308,9 @@ class Request:
|
|
|
294
308
|
Returns:
|
|
295
309
|
A ``(answer, metrics)`` tuple where ``answer`` is the model's
|
|
296
310
|
completion text and ``metrics`` is a :data:`MetricMap` of token
|
|
297
|
-
and latency stats keyed by metric id.
|
|
311
|
+
and latency stats keyed by metric id. Output tokens use the
|
|
312
|
+
server's completion count, including zero, or ``max_tokens``
|
|
313
|
+
when the count is absent.
|
|
298
314
|
"""
|
|
299
315
|
request_data = self.build_request(prompt)
|
|
300
316
|
result = self._query_with_fallback(request_data)
|
|
@@ -101,7 +101,7 @@ def _wrap_sglang_kv_caches(
|
|
|
101
101
|
device = _validate_sglang_kv_pools(k_pool, v_pool)
|
|
102
102
|
tensors = [*k_pool, *v_pool]
|
|
103
103
|
device_spec = get_device_spec(device.type)
|
|
104
|
-
if device_spec is None or not device_spec.
|
|
104
|
+
if device_spec is None or not device_spec.is_lmcache_driven_available():
|
|
105
105
|
raise ValueError(
|
|
106
106
|
"SGLang MP handle transfer is unavailable for device type "
|
|
107
107
|
f"{device.type!r}: required memory IPC, event IPC, cache context, "
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
This module deliberately talks to LMCache's engine-neutral MP protocol. It
|
|
5
5
|
does not use LMCache's legacy SGLang integration and it never constructs an
|
|
6
6
|
in-process LMCache engine. The registered SGLang GPU KV tensors remain owned
|
|
7
|
-
by SGLang;
|
|
7
|
+
by SGLang; the selected transfer context moves their KV data.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Future
|
|
@@ -62,7 +62,7 @@ class _ImmediateFuture:
|
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
class UnifiedLMCacheMPConnector:
|
|
65
|
-
"""Asynchronous
|
|
65
|
+
"""Asynchronous device-IPC connector to a standalone LMCache server."""
|
|
66
66
|
|
|
67
67
|
def __init__(
|
|
68
68
|
self,
|
|
@@ -113,8 +113,6 @@ class UnifiedLMCacheMPConnector:
|
|
|
113
113
|
if not kv_groups or any(not group.kv_tensors for group in kv_groups):
|
|
114
114
|
raise ValueError("LMCache KV group registration cannot be empty")
|
|
115
115
|
kv_tensors = [tensor for group in kv_groups for tensor in group.kv_tensors]
|
|
116
|
-
if any(t.device.type != "cuda" for t in kv_tensors):
|
|
117
|
-
raise NotImplementedError("LMCache MP currently requires CUDA KV tensors")
|
|
118
116
|
if any(t.device != kv_tensors[0].device for t in kv_tensors):
|
|
119
117
|
raise ValueError("All LMCache-registered KV tensors must share one device")
|
|
120
118
|
if any(t.dim() < 2 for t in kv_tensors):
|
|
@@ -240,6 +238,9 @@ class UnifiedLMCacheMPConnector:
|
|
|
240
238
|
_DEFAULT_HEARTBEAT_INTERVAL_SECONDS,
|
|
241
239
|
)
|
|
242
240
|
)
|
|
241
|
+
self._mp_transfer_mode = config.get_extra_config_value( # type: ignore[attr-defined]
|
|
242
|
+
"lmcache.mp.mp_transfer_mode", None
|
|
243
|
+
)
|
|
243
244
|
if any(
|
|
244
245
|
group.recurrent_state or group.sliding_window_size >= 0
|
|
245
246
|
for group in wire_groups
|
|
@@ -302,7 +303,6 @@ class UnifiedLMCacheMPConnector:
|
|
|
302
303
|
) = self._build_engine_group_info_specs()
|
|
303
304
|
self._req_client = RequestClientFactory.create(self.server_url)
|
|
304
305
|
self._transfer_ctx: Optional["TransferContext"] = None
|
|
305
|
-
self._event_backend: Any = None
|
|
306
306
|
self._registered = False
|
|
307
307
|
self._closed = False
|
|
308
308
|
self._lookups: dict[str, LMCacheLookupOperation] = {}
|
|
@@ -321,9 +321,10 @@ class UnifiedLMCacheMPConnector:
|
|
|
321
321
|
f"LMCache chunk size {self.chunk_size} must be a positive "
|
|
322
322
|
"multiple of every SGLang group tokens_per_block"
|
|
323
323
|
)
|
|
324
|
-
#
|
|
325
|
-
# block
|
|
326
|
-
|
|
324
|
+
# Engine-driven currently accepts one transfer group and needs its
|
|
325
|
+
# physical block count. LMCache-driven derives per-group counts from
|
|
326
|
+
# EngineGroupInfo and ignores this compatibility argument.
|
|
327
|
+
self.blocks_in_chunk = self.chunk_size // self._kv_groups[0].tokens_per_block
|
|
327
328
|
self.register_kv_cache()
|
|
328
329
|
logger.info("UnifiedLMCacheMPConnector initialized succeed.")
|
|
329
330
|
|
|
@@ -525,22 +526,19 @@ class UnifiedLMCacheMPConnector:
|
|
|
525
526
|
dist.all_reduce(tensor, op=op, group=self.pp_group)
|
|
526
527
|
|
|
527
528
|
def register_kv_cache(self) -> None:
|
|
528
|
-
"""
|
|
529
|
+
"""Register SGLang KV tensors with the selected transfer context."""
|
|
529
530
|
# First Party
|
|
530
531
|
from lmcache.utils import EngineType
|
|
531
532
|
from lmcache.v1.multiprocess.group_view import EngineGroupInfo
|
|
532
533
|
from lmcache.v1.multiprocess.transfer_context import create_transfer_context
|
|
533
|
-
from lmcache.v1.platform.base.event_ipc import get_event_ipc_backend
|
|
534
534
|
|
|
535
535
|
if self._registered:
|
|
536
536
|
raise RuntimeError("LMCache KV tensors are already registered")
|
|
537
|
-
self._event_backend = get_event_ipc_backend(self.device)
|
|
538
|
-
self._event_backend.check_event_support(self.device)
|
|
539
537
|
transfer_ctx = create_transfer_context(
|
|
540
538
|
self._kv_caches,
|
|
541
539
|
instance_id=self.instance_id,
|
|
542
540
|
req_client=self._req_client,
|
|
543
|
-
mode=
|
|
541
|
+
mode=self._mp_transfer_mode,
|
|
544
542
|
)
|
|
545
543
|
self._transfer_ctx = transfer_ctx
|
|
546
544
|
engine_group_infos = [
|
|
@@ -599,13 +597,6 @@ class UnifiedLMCacheMPConnector:
|
|
|
599
597
|
self._heartbeat_thread = heartbeat_thread
|
|
600
598
|
logger.info("LMCache MP heartbeat thread started")
|
|
601
599
|
|
|
602
|
-
def _new_event(self, stream: Any = None) -> Any:
|
|
603
|
-
event = self._event_backend.create_event(self.device)
|
|
604
|
-
if stream is None:
|
|
605
|
-
stream = torch.get_device_module(self.device).current_stream()
|
|
606
|
-
self._event_backend.record_event(event, stream)
|
|
607
|
-
return event
|
|
608
|
-
|
|
609
600
|
def _create_key(
|
|
610
601
|
self,
|
|
611
602
|
operation: LMCacheLookupOperation,
|
|
@@ -886,11 +877,7 @@ class UnifiedLMCacheMPConnector:
|
|
|
886
877
|
transfer_ctx = self._transfer_ctx
|
|
887
878
|
if transfer_ctx is None:
|
|
888
879
|
raise RuntimeError("LMCache KV tensors are not registered")
|
|
889
|
-
event = (
|
|
890
|
-
self._new_event()
|
|
891
|
-
if producer_stream is None
|
|
892
|
-
else self._new_event(producer_stream)
|
|
893
|
-
)
|
|
880
|
+
event = self._create_recorded_event(transfer_ctx, producer_stream)
|
|
894
881
|
future = transfer_ctx.submit_retrieve(
|
|
895
882
|
operation.request_id,
|
|
896
883
|
key,
|
|
@@ -941,11 +928,11 @@ class UnifiedLMCacheMPConnector:
|
|
|
941
928
|
otherwise ``False``.
|
|
942
929
|
|
|
943
930
|
Notes:
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
931
|
+
LMCache-driven retrieval imports the server's completion event and
|
|
932
|
+
orders it on ``stream`` without a CPU device synchronization.
|
|
933
|
+
Engine-driven retrieval completes its worker-side scatter before
|
|
934
|
+
returning its plain future. On a cross-rank failure, successful
|
|
935
|
+
ranks synchronize local work before destination slots are released.
|
|
949
936
|
"""
|
|
950
937
|
local_success = False
|
|
951
938
|
try:
|
|
@@ -1121,7 +1108,7 @@ class UnifiedLMCacheMPConnector:
|
|
|
1121
1108
|
key = self._create_key(
|
|
1122
1109
|
lookup, start=start, end=aligned_end, worker_id=self.kv_worker_id
|
|
1123
1110
|
)
|
|
1124
|
-
event =
|
|
1111
|
+
event = transfer_ctx.create_recorded_event()
|
|
1125
1112
|
future = transfer_ctx.submit_store(
|
|
1126
1113
|
request_id,
|
|
1127
1114
|
key,
|
|
@@ -1260,3 +1247,13 @@ class UnifiedLMCacheMPConnector:
|
|
|
1260
1247
|
transfer_ctx.close()
|
|
1261
1248
|
self._transfer_ctx = None
|
|
1262
1249
|
self._req_client.close()
|
|
1250
|
+
|
|
1251
|
+
def _create_recorded_event(
|
|
1252
|
+
self, transfer_ctx: "TransferContext", stream: Any = None
|
|
1253
|
+
) -> Any:
|
|
1254
|
+
"""Create a context-owned event on an optional SGLang producer stream."""
|
|
1255
|
+
if stream is None:
|
|
1256
|
+
return transfer_ctx.create_recorded_event()
|
|
1257
|
+
device_module = torch.get_device_module(self.device)
|
|
1258
|
+
with device_module.stream(stream):
|
|
1259
|
+
return transfer_ctx.create_recorded_event()
|
|
@@ -10,6 +10,7 @@ import time
|
|
|
10
10
|
# Third Party
|
|
11
11
|
from vllm.config import VllmConfig
|
|
12
12
|
from vllm.distributed.kv_events import (
|
|
13
|
+
BlockRemoved,
|
|
13
14
|
BlockStored,
|
|
14
15
|
KVCacheEvent,
|
|
15
16
|
KVConnectorKVEvents,
|
|
@@ -81,6 +82,7 @@ from lmcache.integration.vllm.utils import (
|
|
|
81
82
|
mla_only,
|
|
82
83
|
vllm_layout_hints,
|
|
83
84
|
)
|
|
85
|
+
from lmcache.utils import CacheRemoveEvent
|
|
84
86
|
from lmcache.utils import init_logger as lmcache_init_logger
|
|
85
87
|
|
|
86
88
|
try:
|
|
@@ -146,16 +148,23 @@ class LMCacheMPKVEvents(KVConnectorKVEvents):
|
|
|
146
148
|
|
|
147
149
|
def __init__(self, num_workers: int) -> None:
|
|
148
150
|
self._aggregator = KVEventAggregator(num_workers)
|
|
151
|
+
self._batches: list[list[KVCacheEvent]] = []
|
|
149
152
|
|
|
150
153
|
def add_events(self, events: list[KVCacheEvent]) -> None:
|
|
151
154
|
"""Add events from one worker."""
|
|
152
155
|
self._aggregator.add_events(events)
|
|
156
|
+
self._batches.append(list(events))
|
|
153
157
|
|
|
154
158
|
def aggregate(self) -> "LMCacheMPKVEvents":
|
|
155
|
-
"""
|
|
156
|
-
|
|
159
|
+
"""Keep all pollers' events, preserving transitions within each batch."""
|
|
160
|
+
remaining = set(self._aggregator.get_all_events())
|
|
161
|
+
merged: list[KVCacheEvent] = []
|
|
162
|
+
for events in self._batches:
|
|
163
|
+
merged.extend(event for event in events if event in remaining)
|
|
164
|
+
remaining.difference_update(events)
|
|
165
|
+
self._batches = [merged] if merged else []
|
|
157
166
|
self._aggregator.clear_events()
|
|
158
|
-
self._aggregator.add_events(
|
|
167
|
+
self._aggregator.add_events(merged)
|
|
159
168
|
self._aggregator.reset_workers()
|
|
160
169
|
return self
|
|
161
170
|
|
|
@@ -164,8 +173,8 @@ class LMCacheMPKVEvents(KVConnectorKVEvents):
|
|
|
164
173
|
self._aggregator.increment_workers(count)
|
|
165
174
|
|
|
166
175
|
def get_all_events(self) -> list[KVCacheEvent]:
|
|
167
|
-
"""Return all buffered events."""
|
|
168
|
-
return self.
|
|
176
|
+
"""Return all buffered events in worker order."""
|
|
177
|
+
return [event for batch in self._batches for event in batch]
|
|
169
178
|
|
|
170
179
|
def get_number_of_workers(self) -> int:
|
|
171
180
|
"""Return the number of contributing workers."""
|
|
@@ -175,6 +184,7 @@ class LMCacheMPKVEvents(KVConnectorKVEvents):
|
|
|
175
184
|
"""Clear buffered events and reset the worker count."""
|
|
176
185
|
self._aggregator.clear_events()
|
|
177
186
|
self._aggregator.reset_workers()
|
|
187
|
+
self._batches.clear()
|
|
178
188
|
|
|
179
189
|
|
|
180
190
|
# Helper functions
|
|
@@ -727,7 +737,8 @@ class LMCacheMPConnector(KVConnectorBase_V1, SupportsHMA):
|
|
|
727
737
|
extra_config=vllm_config.kv_transfer_config.kv_connector_extra_config,
|
|
728
738
|
)
|
|
729
739
|
self.request_trackers: dict[str, LMCacheMPRequestTracker] = {}
|
|
730
|
-
|
|
740
|
+
# Worker events aggregated per step, awaiting take_events().
|
|
741
|
+
self._kv_cache_events: list[KVCacheEvent] = []
|
|
731
742
|
|
|
732
743
|
# Align-mode Mamba keeps one speculative block per draft token at
|
|
733
744
|
# the tail of a request's block list.
|
|
@@ -1124,8 +1135,10 @@ class LMCacheMPConnector(KVConnectorBase_V1, SupportsHMA):
|
|
|
1124
1135
|
"""Return worker-side KV cache events collected since the last step.
|
|
1125
1136
|
|
|
1126
1137
|
Returns:
|
|
1127
|
-
A vLLM KV event container with
|
|
1128
|
-
|
|
1138
|
+
A vLLM KV event container with ``BlockStored`` events for LMCache
|
|
1139
|
+
stores (own completed stores and stores learned from the MP
|
|
1140
|
+
server) and ``BlockRemoved`` events for CPU evictions, or None
|
|
1141
|
+
when disabled or when nothing happened.
|
|
1129
1142
|
"""
|
|
1130
1143
|
if not self._enable_kv_events:
|
|
1131
1144
|
return None
|
|
@@ -1133,21 +1146,27 @@ class LMCacheMPConnector(KVConnectorBase_V1, SupportsHMA):
|
|
|
1133
1146
|
if not events:
|
|
1134
1147
|
return None
|
|
1135
1148
|
|
|
1136
|
-
blocks = [
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1149
|
+
blocks: list[KVCacheEvent] = []
|
|
1150
|
+
for event in events:
|
|
1151
|
+
block_hashes = [
|
|
1152
|
+
_convert_kv_event_hash(block_hash) for block_hash in event.block_hashes
|
|
1153
|
+
]
|
|
1154
|
+
if isinstance(event, CacheRemoveEvent):
|
|
1155
|
+
blocks.append(
|
|
1156
|
+
BlockRemoved(block_hashes=block_hashes, medium=event.medium)
|
|
1157
|
+
)
|
|
1158
|
+
continue
|
|
1159
|
+
blocks.append(
|
|
1160
|
+
BlockStored(
|
|
1161
|
+
block_hashes=block_hashes,
|
|
1162
|
+
parent_block_hash=_convert_kv_event_hash(event.parent_block_hash),
|
|
1163
|
+
token_ids=event.token_ids,
|
|
1164
|
+
lora_id=event.lora_id,
|
|
1165
|
+
block_size=event.block_size,
|
|
1166
|
+
medium=event.medium,
|
|
1167
|
+
lora_name=event.lora_name,
|
|
1168
|
+
)
|
|
1148
1169
|
)
|
|
1149
|
-
for event in events
|
|
1150
|
-
]
|
|
1151
1170
|
kv_events = LMCacheMPKVEvents(num_workers=1)
|
|
1152
1171
|
kv_events.add_events(blocks)
|
|
1153
1172
|
return kv_events
|
|
@@ -1487,13 +1506,8 @@ class LMCacheMPConnector(KVConnectorBase_V1, SupportsHMA):
|
|
|
1487
1506
|
"""
|
|
1488
1507
|
kv_cache_events = connector_output.kv_cache_events
|
|
1489
1508
|
if kv_cache_events and isinstance(kv_cache_events, LMCacheMPKVEvents):
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
else:
|
|
1493
|
-
self._kv_cache_events.add_events(kv_cache_events.get_all_events())
|
|
1494
|
-
self._kv_cache_events.increment_workers(
|
|
1495
|
-
kv_cache_events.get_number_of_workers()
|
|
1496
|
-
)
|
|
1509
|
+
# One aggregated batch per step keeps the workers' event order.
|
|
1510
|
+
self._kv_cache_events.extend(kv_cache_events.aggregate().get_all_events())
|
|
1497
1511
|
|
|
1498
1512
|
if not self.lazy_offload:
|
|
1499
1513
|
return
|
|
@@ -1577,14 +1591,13 @@ class LMCacheMPConnector(KVConnectorBase_V1, SupportsHMA):
|
|
|
1577
1591
|
"""
|
|
1578
1592
|
Take the KV cache events from the connector.
|
|
1579
1593
|
|
|
1580
|
-
|
|
1581
|
-
|
|
1594
|
+
Returns:
|
|
1595
|
+
The KV cache events collected since the last call, in the order
|
|
1596
|
+
the workers reported them. The buffer is cleared.
|
|
1582
1597
|
"""
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
self._kv_cache_events.clear_events()
|
|
1587
|
-
self._kv_cache_events = None
|
|
1598
|
+
events = self._kv_cache_events
|
|
1599
|
+
self._kv_cache_events = []
|
|
1600
|
+
return events
|
|
1588
1601
|
|
|
1589
1602
|
def has_pending_push_work(self) -> bool:
|
|
1590
1603
|
"""Return whether vLLM should keep stepping for pending push work.
|