lmcache-cli 0.4.8.dev38__py3-none-any.whl → 0.5.0rc2.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/__init__.py +8 -0
- lmcache/_version.py +3 -3
- lmcache/cli/commands/__init__.py +2 -2
- lmcache/cli/commands/base.py +97 -0
- lmcache/cli/commands/bench/__init__.py +8 -54
- lmcache/cli/commands/bench/engine_bench/__init__.py +48 -0
- lmcache/cli/commands/bench/engine_bench/command.py +6 -24
- lmcache/cli/commands/bench/l2_adapter_bench/__init__.py +37 -1
- lmcache/cli/commands/bench/l2_adapter_bench/command.py +6 -44
- lmcache/cli/commands/bench/l2_adapter_bench/runner.py +15 -2
- lmcache/cli/commands/bench/server_bench/__init__.py +37 -1
- lmcache/cli/commands/bench/server_bench/command.py +37 -56
- lmcache/cli/commands/bench/server_bench/helpers.py +43 -2
- lmcache/cli/commands/query/__init__.py +5 -61
- lmcache/cli/commands/query/engine_command.py +91 -113
- lmcache/cli/commands/query/kvcache_command.py +18 -39
- lmcache/cli/commands/quota/__init__.py +5 -76
- lmcache/cli/commands/quota/delete_command.py +37 -64
- lmcache/cli/commands/quota/get_command.py +41 -67
- lmcache/cli/commands/quota/list_command.py +33 -57
- lmcache/cli/commands/quota/set_command.py +50 -77
- lmcache/cli/commands/server.py +2 -0
- lmcache/cli/commands/tool/__init__.py +5 -49
- lmcache/cli/commands/tool/cache_simulator/__init__.py +21 -0
- lmcache/cli/commands/tool/cache_simulator/gen_dataset_command.py +48 -0
- lmcache/cli/commands/tool/cache_simulator/simulate_command.py +46 -0
- lmcache/cli/commands/tool/cache_simulator/sweep_command.py +45 -0
- lmcache/cli/commands/tool/transfer_channel_benchmark.py +64 -41
- lmcache/cli/commands/trace/__init__.py +5 -117
- lmcache/cli/commands/trace/{driver.py → _driver.py} +2 -2
- lmcache/cli/commands/trace/info_command.py +46 -67
- lmcache/cli/commands/trace/replay_command.py +24 -38
- lmcache/integration/sglang/multi_process_adapter.py +33 -26
- lmcache/integration/vllm/lmcache_mp_connector.py +77 -8
- lmcache/integration/vllm/vllm_multi_process_adapter.py +201 -72
- lmcache/native_storage_ops.pyi +60 -0
- lmcache/observability.py +1 -1
- lmcache/usage_context.py +2 -2
- lmcache/utils.py +1 -1
- lmcache/v1/config.py +1 -1
- lmcache/v1/config_base.py +4 -4
- lmcache/v1/distributed/bitmap_ops/README.md +57 -0
- lmcache/v1/distributed/bitmap_ops/__init__.py +31 -0
- lmcache/v1/distributed/bitmap_ops/fold.py +339 -0
- lmcache/v1/distributed/config.py +18 -0
- lmcache/v1/distributed/l2_adapters/base.py +5 -1
- lmcache/v1/distributed/l2_adapters/dax_l2_adapter.py +4 -2
- lmcache/v1/distributed/l2_adapters/fault_inject_l2_adapter.py +5 -3
- lmcache/v1/distributed/l2_adapters/fs_l2_adapter.py +4 -2
- lmcache/v1/distributed/l2_adapters/hfbucket_l2_adapter.py +4 -2
- lmcache/v1/distributed/l2_adapters/mock_l2_adapter.py +4 -2
- lmcache/v1/distributed/l2_adapters/native_connector_l2_adapter.py +2 -1
- lmcache/v1/distributed/l2_adapters/nixl_store_dynamic_l2_adapter.py +3 -1
- lmcache/v1/distributed/l2_adapters/nixl_store_l2_adapter.py +3 -1
- lmcache/v1/distributed/l2_adapters/p2p_l2_adapter.py +406 -0
- lmcache/v1/distributed/l2_adapters/raw_block_l2_adapter.py +4 -2
- lmcache/v1/distributed/l2_adapters/s3_l2_adapter.py +10 -3
- lmcache/v1/distributed/l2_adapters/serde_wrapper.py +4 -2
- lmcache/v1/distributed/storage_controllers/adapter_lifecycle.py +45 -0
- lmcache/v1/distributed/storage_controllers/eviction_controller.py +30 -3
- lmcache/v1/distributed/storage_controllers/prefetch_controller.py +241 -31
- lmcache/v1/distributed/storage_controllers/store_controller.py +187 -20
- lmcache/v1/distributed/storage_manager.py +248 -63
- lmcache/v1/distributed/transfer_channel/abstract.py +17 -0
- lmcache/v1/distributed/transfer_channel/impl/nixl_impl.py +51 -17
- lmcache/v1/gpu_connector/gpu_connectors.py +3 -1
- lmcache/v1/gpu_connector/kv_format/__init__.py +30 -0
- lmcache/v1/gpu_connector/kv_format/contiguity.py +147 -0
- lmcache/v1/gpu_connector/kv_format/detection.py +47 -0
- lmcache/v1/gpu_connector/kv_format/detectors/__init__.py +11 -0
- lmcache/v1/gpu_connector/kv_format/detectors/base.py +52 -0
- lmcache/v1/gpu_connector/kv_format/detectors/registry.py +43 -0
- lmcache/v1/gpu_connector/kv_format/detectors/sglang.py +67 -0
- lmcache/v1/gpu_connector/kv_format/detectors/trtllm.py +61 -0
- lmcache/v1/gpu_connector/kv_format/detectors/vllm.py +72 -0
- lmcache/v1/gpu_connector/kv_format/specs/__init__.py +22 -0
- lmcache/v1/gpu_connector/kv_format/specs/base.py +176 -0
- lmcache/v1/gpu_connector/kv_format/specs/nb_nl_two_bs_nh_hs.py +59 -0
- lmcache/v1/gpu_connector/kv_format/specs/nb_nl_two_nh_bs_hs.py +61 -0
- lmcache/v1/gpu_connector/kv_format/specs/nl_x_nb_bs_hs.py +58 -0
- lmcache/v1/gpu_connector/kv_format/specs/nl_x_nb_nh_bs_two_hs.py +63 -0
- lmcache/v1/gpu_connector/kv_format/specs/nl_x_nb_two_bs_nh_hs.py +60 -0
- lmcache/v1/gpu_connector/kv_format/specs/nl_x_nb_two_nh_bs_hs.py +62 -0
- lmcache/v1/gpu_connector/kv_format/specs/nl_x_nbbs_one_hs.py +63 -0
- lmcache/v1/gpu_connector/kv_format/specs/nl_x_two_nb_bs_nh_hs.py +60 -0
- lmcache/v1/gpu_connector/kv_format/specs/nl_x_two_nb_nh_bs_hs.py +61 -0
- lmcache/v1/gpu_connector/kv_format/specs/registry.py +56 -0
- lmcache/v1/gpu_connector/kv_format/specs/two_x_nl_x_nb_bs_nh_hs.py +61 -0
- lmcache/v1/gpu_connector/kv_format/specs/two_x_nl_x_nbbs_nh_hs.py +65 -0
- lmcache/v1/gpu_connector/kv_format/types.py +52 -0
- lmcache/v1/gpu_connector/musa_connectors.py +23 -14
- lmcache/v1/gpu_connector/utils.py +164 -1058
- lmcache/v1/lookup_client/lmcache_lookup_client.py +3 -3
- lmcache/v1/lookup_client/lmcache_lookup_client_bypass.py +1 -1
- lmcache/v1/memory_management.py +7 -7
- lmcache/v1/mp_coordinator/blend_client.py +35 -14
- lmcache/v1/mp_coordinator/blend_directory.py +196 -40
- lmcache/v1/mp_coordinator/http_apis/blend_directory_api.py +5 -1
- lmcache/v1/mp_coordinator/http_apis/instances_api.py +2 -0
- lmcache/v1/mp_coordinator/registrar.py +19 -1
- lmcache/v1/mp_coordinator/registry.py +4 -0
- lmcache/v1/mp_coordinator/schemas.py +75 -4
- lmcache/v1/multiprocess/config.py +113 -0
- lmcache/v1/multiprocess/custom_types.py +87 -58
- lmcache/v1/multiprocess/http_server.py +26 -6
- lmcache/v1/multiprocess/modules/blend_v3.py +8 -10
- lmcache/v1/multiprocess/modules/lookup.py +38 -0
- lmcache/v1/multiprocess/modules/p2p_controller.py +338 -10
- lmcache/v1/multiprocess/mp_runtime_plugin_launcher.py +1 -1
- lmcache/v1/multiprocess/mq.py +7 -7
- lmcache/v1/multiprocess/protocols/base.py +1 -0
- lmcache/v1/multiprocess/protocols/blend_v3.py +2 -2
- lmcache/v1/multiprocess/protocols/engine.py +11 -0
- lmcache/v1/multiprocess/server.py +23 -2
- lmcache/v1/platform/cpu/shm.py +9 -7
- lmcache/v1/platform/musa/__init__.py +2 -0
- lmcache/v1/platform/musa/native_kv_transfer.py +486 -0
- lmcache/v1/platform/musa/ops.py +91 -0
- lmcache/v1/rpc_utils.py +1 -1
- lmcache/v1/storage_backend/connector/valkey_connector.py +32 -3
- lmcache/v1/storage_backend/pd_backend_async.py +86 -47
- lmcache/v1/token_database.py +2 -2
- {lmcache_cli-0.4.8.dev38.dist-info → lmcache_cli-0.5.0rc2.dev0.dist-info}/METADATA +1 -1
- {lmcache_cli-0.4.8.dev38.dist-info → lmcache_cli-0.5.0rc2.dev0.dist-info}/RECORD +135 -99
- lmcache_cli-0.5.0rc2.dev0.dist-info/scm_file_list.json +1976 -0
- lmcache_cli-0.5.0rc2.dev0.dist-info/scm_version.json +8 -0
- lmcache/cli/commands/tool/cache_simulator.py +0 -113
- lmcache/v1/gpu_connector/musa_native.py +0 -218
- /lmcache/cli/commands/query/{prompt.py → _prompt.py} +0 -0
- /lmcache/cli/commands/query/{request.py → _request.py} +0 -0
- /lmcache/cli/commands/quota/{helpers.py → _helpers.py} +0 -0
- /lmcache/cli/commands/trace/{dispatch.py → _dispatch.py} +0 -0
- /lmcache/cli/commands/trace/{stats.py → _stats.py} +0 -0
- {lmcache_cli-0.4.8.dev38.dist-info → lmcache_cli-0.5.0rc2.dev0.dist-info}/WHEEL +0 -0
- {lmcache_cli-0.4.8.dev38.dist-info → lmcache_cli-0.5.0rc2.dev0.dist-info}/entry_points.txt +0 -0
- {lmcache_cli-0.4.8.dev38.dist-info → lmcache_cli-0.5.0rc2.dev0.dist-info}/licenses/LICENSE +0 -0
- {lmcache_cli-0.4.8.dev38.dist-info → lmcache_cli-0.5.0rc2.dev0.dist-info}/top_level.txt +0 -0
lmcache/__init__.py
CHANGED
|
@@ -74,6 +74,14 @@ def _get_backend() -> Any:
|
|
|
74
74
|
import torch
|
|
75
75
|
|
|
76
76
|
backend_candidates = [
|
|
77
|
+
# Keep backend priority aligned with _detect_device().
|
|
78
|
+
# MUSA currently uses a Python adapter under the platform package,
|
|
79
|
+
# unlike the compiled XPU/CUDA extension modules.
|
|
80
|
+
(
|
|
81
|
+
"lmcache.v1.platform.musa.ops",
|
|
82
|
+
"musa_ops",
|
|
83
|
+
lambda: hasattr(torch, "musa") and torch.musa.is_available(), # type: ignore[attr-defined]
|
|
84
|
+
),
|
|
77
85
|
(
|
|
78
86
|
"lmcache.xpu_ops",
|
|
79
87
|
"xpu_ops",
|
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.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.5.0rc2.dev0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 5, 0, 'rc2', 'dev0')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g389b9cfcb'
|
lmcache/cli/commands/__init__.py
CHANGED
|
@@ -8,7 +8,7 @@ automatically — no edits to this file are required.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# First Party
|
|
11
|
-
from lmcache.cli.commands.base import BaseCommand
|
|
11
|
+
from lmcache.cli.commands.base import BaseCommand, CompositeCommand
|
|
12
12
|
from lmcache.v1.utils.subclass_discovery import discover_subclasses
|
|
13
13
|
|
|
14
14
|
|
|
@@ -37,4 +37,4 @@ def _discover_commands() -> list[BaseCommand]:
|
|
|
37
37
|
|
|
38
38
|
ALL_COMMANDS: list[BaseCommand] = _discover_commands()
|
|
39
39
|
|
|
40
|
-
__all__ = ["ALL_COMMANDS", "BaseCommand"]
|
|
40
|
+
__all__ = ["ALL_COMMANDS", "BaseCommand", "CompositeCommand"]
|
lmcache/cli/commands/base.py
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
"""Abstract base class and shared helpers for CLI subcommands."""
|
|
3
3
|
|
|
4
|
+
# Future
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
4
7
|
# Standard
|
|
5
8
|
import abc
|
|
6
9
|
import argparse
|
|
10
|
+
import sys
|
|
7
11
|
|
|
8
12
|
# First Party
|
|
9
13
|
from lmcache.cli.metrics import (
|
|
@@ -12,6 +16,9 @@ from lmcache.cli.metrics import (
|
|
|
12
16
|
StreamHandler,
|
|
13
17
|
get_formatter,
|
|
14
18
|
)
|
|
19
|
+
from lmcache.logging import init_logger
|
|
20
|
+
|
|
21
|
+
logger = init_logger(__name__)
|
|
15
22
|
|
|
16
23
|
|
|
17
24
|
class BaseCommand(abc.ABC):
|
|
@@ -125,6 +132,96 @@ class BaseCommand(abc.ABC):
|
|
|
125
132
|
return metrics
|
|
126
133
|
|
|
127
134
|
|
|
135
|
+
class CompositeCommand(BaseCommand):
|
|
136
|
+
"""Base class for commands that contain auto-discovered sub-subcommands.
|
|
137
|
+
|
|
138
|
+
Subclasses only need to implement :meth:`name` and :meth:`help`.
|
|
139
|
+
Sub-subcommands are discovered automatically by scanning the package
|
|
140
|
+
for concrete :class:`BaseCommand` subclasses.
|
|
141
|
+
|
|
142
|
+
Example::
|
|
143
|
+
|
|
144
|
+
class QueryCommand(CompositeCommand):
|
|
145
|
+
def name(self) -> str:
|
|
146
|
+
return "query"
|
|
147
|
+
|
|
148
|
+
def help(self) -> str:
|
|
149
|
+
return "Run one inference request and report metrics."
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
def add_arguments(self, _parser: argparse.ArgumentParser) -> None:
|
|
153
|
+
"""No top-level arguments; all args are registered by subcommands."""
|
|
154
|
+
|
|
155
|
+
def register(self, subparsers: argparse._SubParsersAction) -> None:
|
|
156
|
+
"""Register this command and auto-discover all sub-subcommands.
|
|
157
|
+
|
|
158
|
+
Scans the package where this class is defined for concrete
|
|
159
|
+
:class:`BaseCommand` subclasses and registers each one as a
|
|
160
|
+
nested subcommand.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
subparsers: The subparsers action from the root parser.
|
|
164
|
+
"""
|
|
165
|
+
# Deferred import to avoid circular dependency
|
|
166
|
+
# First Party
|
|
167
|
+
from lmcache.v1.utils.subclass_discovery import discover_subclasses
|
|
168
|
+
|
|
169
|
+
parser = subparsers.add_parser(
|
|
170
|
+
self.name(),
|
|
171
|
+
help=self.help(),
|
|
172
|
+
description=self.help(),
|
|
173
|
+
)
|
|
174
|
+
inner = parser.add_subparsers(
|
|
175
|
+
dest=f"{self.name()}_target",
|
|
176
|
+
required=True,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# Discover subcommands in the package where the concrete
|
|
180
|
+
# CompositeCommand subclass is defined. Exclude the module
|
|
181
|
+
# that defines the composite command itself (the __init__.py).
|
|
182
|
+
package = self.__class__.__module__
|
|
183
|
+
|
|
184
|
+
def _raise(module_name: str, exc: Exception) -> None:
|
|
185
|
+
raise exc
|
|
186
|
+
|
|
187
|
+
self._subcmds: dict[str, BaseCommand] = {}
|
|
188
|
+
for cls in discover_subclasses(
|
|
189
|
+
package,
|
|
190
|
+
BaseCommand, # type: ignore[type-abstract]
|
|
191
|
+
module_filter=lambda name: not name.startswith("_"),
|
|
192
|
+
require_defined_in_module=True,
|
|
193
|
+
on_import_error=_raise,
|
|
194
|
+
):
|
|
195
|
+
# Skip the composite command class itself
|
|
196
|
+
if cls is self.__class__:
|
|
197
|
+
continue
|
|
198
|
+
inst = cls()
|
|
199
|
+
self._subcmds[inst.name()] = inst
|
|
200
|
+
inst.register(inner)
|
|
201
|
+
|
|
202
|
+
logger.debug(
|
|
203
|
+
"CompositeCommand[%s] discovered subcommands: %s",
|
|
204
|
+
self.name(),
|
|
205
|
+
list(self._subcmds.keys()),
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
def execute(self, args: argparse.Namespace) -> None:
|
|
209
|
+
"""Dispatch to the appropriate sub-subcommand.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
args: Parsed CLI arguments.
|
|
213
|
+
"""
|
|
214
|
+
target = getattr(args, f"{self.name()}_target", None)
|
|
215
|
+
subcmd = self._subcmds.get(target) if target else None
|
|
216
|
+
if subcmd is None:
|
|
217
|
+
print(
|
|
218
|
+
f"Unknown {self.name()} target: {target}",
|
|
219
|
+
file=sys.stderr,
|
|
220
|
+
)
|
|
221
|
+
sys.exit(1)
|
|
222
|
+
subcmd.execute(args)
|
|
223
|
+
|
|
224
|
+
|
|
128
225
|
def _add_output_args(parser: argparse.ArgumentParser) -> None:
|
|
129
226
|
"""Add the common ``--format`` and ``--output`` flags.
|
|
130
227
|
|
|
@@ -1,30 +1,17 @@
|
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
"""``lmcache bench`` command — sustained performance benchmarking.
|
|
2
|
+
"""``lmcache bench`` command — sustained performance benchmarking.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
Sub-subcommands are auto-discovered from sub-packages in this package.
|
|
5
|
+
To add a new benchmark, create a sub-package with a concrete
|
|
6
|
+
:class:`BaseCommand` subclass in its ``__init__.py`` — no edits to
|
|
7
|
+
this file are required.
|
|
8
|
+
"""
|
|
7
9
|
|
|
8
10
|
# First Party
|
|
9
|
-
from lmcache.cli.commands.base import
|
|
10
|
-
from lmcache.cli.commands.bench.engine_bench.command import (
|
|
11
|
-
register_engine_parser,
|
|
12
|
-
run_engine_bench,
|
|
13
|
-
)
|
|
14
|
-
from lmcache.cli.commands.bench.l2_adapter_bench.command import (
|
|
15
|
-
register_l2_parser,
|
|
16
|
-
run_l2_adapter_bench,
|
|
17
|
-
)
|
|
18
|
-
from lmcache.cli.commands.bench.server_bench.command import (
|
|
19
|
-
register_server_parser,
|
|
20
|
-
run_server_bench,
|
|
21
|
-
)
|
|
22
|
-
from lmcache.logging import init_logger
|
|
11
|
+
from lmcache.cli.commands.base import CompositeCommand
|
|
23
12
|
|
|
24
|
-
logger = init_logger(__name__)
|
|
25
13
|
|
|
26
|
-
|
|
27
|
-
class BenchCommand(BaseCommand):
|
|
14
|
+
class BenchCommand(CompositeCommand):
|
|
28
15
|
"""CLI command for sustained performance benchmarking."""
|
|
29
16
|
|
|
30
17
|
def name(self) -> str:
|
|
@@ -32,36 +19,3 @@ class BenchCommand(BaseCommand):
|
|
|
32
19
|
|
|
33
20
|
def help(self) -> str:
|
|
34
21
|
return "Run sustained performance benchmarks."
|
|
35
|
-
|
|
36
|
-
def add_arguments(self, _parser: argparse.ArgumentParser) -> None:
|
|
37
|
-
pass # args registered in register() via subparsers
|
|
38
|
-
|
|
39
|
-
def register(self, subparsers: argparse._SubParsersAction) -> None:
|
|
40
|
-
parser = subparsers.add_parser(
|
|
41
|
-
self.name(),
|
|
42
|
-
help=self.help(),
|
|
43
|
-
description="Run sustained performance benchmarks.",
|
|
44
|
-
)
|
|
45
|
-
inner = parser.add_subparsers(
|
|
46
|
-
dest="bench_target",
|
|
47
|
-
required=True,
|
|
48
|
-
metavar="{engine,server,l2}",
|
|
49
|
-
)
|
|
50
|
-
register_engine_parser(inner, self.execute)
|
|
51
|
-
register_server_parser(inner, self.execute)
|
|
52
|
-
register_l2_parser(inner, self.execute)
|
|
53
|
-
|
|
54
|
-
def execute(self, args: argparse.Namespace) -> None:
|
|
55
|
-
handlers = {
|
|
56
|
-
"engine": lambda a: run_engine_bench(self, a),
|
|
57
|
-
"server": lambda a: run_server_bench(self, a),
|
|
58
|
-
"l2": lambda a: run_l2_adapter_bench(self, a),
|
|
59
|
-
}
|
|
60
|
-
handler = handlers.get(args.bench_target)
|
|
61
|
-
if handler is None:
|
|
62
|
-
print(
|
|
63
|
-
f"Unknown bench target: {args.bench_target}",
|
|
64
|
-
file=sys.stderr,
|
|
65
|
-
)
|
|
66
|
-
sys.exit(1)
|
|
67
|
-
handler(args)
|
|
@@ -1 +1,49 @@
|
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""``lmcache bench engine`` subpackage.
|
|
3
|
+
|
|
4
|
+
Exposes :class:`EngineBenchCommand` for auto-discovery by
|
|
5
|
+
:class:`~lmcache.cli.commands.base.CompositeCommand`.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Standard
|
|
9
|
+
import argparse
|
|
10
|
+
|
|
11
|
+
# First Party
|
|
12
|
+
from lmcache.cli.commands.base import BaseCommand
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class EngineBenchCommand(BaseCommand):
|
|
16
|
+
"""Benchmark an inference engine."""
|
|
17
|
+
|
|
18
|
+
def name(self) -> str:
|
|
19
|
+
return "engine"
|
|
20
|
+
|
|
21
|
+
def help(self) -> str:
|
|
22
|
+
return "Benchmark an inference engine."
|
|
23
|
+
|
|
24
|
+
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
|
|
25
|
+
# First Party
|
|
26
|
+
from lmcache.cli.commands.bench.engine_bench.command import (
|
|
27
|
+
add_engine_arguments,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
add_engine_arguments(parser)
|
|
31
|
+
|
|
32
|
+
def register(self, subparsers: argparse._SubParsersAction) -> None:
|
|
33
|
+
"""Register without the common output args (--format/--output).
|
|
34
|
+
|
|
35
|
+
The engine bench manages its own output lifecycle (CSV/JSON export,
|
|
36
|
+
--quiet) so the generic _add_output_args flags are not applicable
|
|
37
|
+
and would only clutter ``-h`` output.
|
|
38
|
+
"""
|
|
39
|
+
parser = subparsers.add_parser(self.name(), help=self.help())
|
|
40
|
+
self.add_arguments(parser)
|
|
41
|
+
parser.set_defaults(func=self.execute)
|
|
42
|
+
|
|
43
|
+
def execute(self, args: argparse.Namespace) -> None:
|
|
44
|
+
# First Party
|
|
45
|
+
from lmcache.cli.commands.bench.engine_bench.command import (
|
|
46
|
+
run_engine_bench,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
run_engine_bench(self, args)
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
"""``lmcache bench engine`` subcommand implementation.
|
|
3
3
|
|
|
4
|
-
This module
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
:func:`register_engine_parser`.
|
|
4
|
+
This module provides argument registration via :func:`add_engine_arguments`
|
|
5
|
+
and the execution orchestrator :func:`run_engine_bench` for the inference
|
|
6
|
+
engine benchmark.
|
|
8
7
|
"""
|
|
9
8
|
|
|
10
9
|
# Future
|
|
@@ -55,26 +54,12 @@ _LDQA_MAX_OUTPUT_LENGTH_DEFAULT = 128
|
|
|
55
54
|
# ---------------------------------------------------------------------------
|
|
56
55
|
|
|
57
56
|
|
|
58
|
-
def
|
|
59
|
-
|
|
60
|
-
dispatch_func,
|
|
61
|
-
) -> argparse.ArgumentParser:
|
|
62
|
-
"""Register the ``lmcache bench engine`` subcommand parser.
|
|
57
|
+
def add_engine_arguments(parser: argparse.ArgumentParser) -> None:
|
|
58
|
+
"""Add ``lmcache bench engine`` arguments to *parser*.
|
|
63
59
|
|
|
64
60
|
Args:
|
|
65
|
-
|
|
66
|
-
dispatch_func: Function to bind via ``set_defaults(func=...)``.
|
|
67
|
-
Typically ``BenchCommand.execute`` so that the outer
|
|
68
|
-
dispatcher can route the call back into
|
|
69
|
-
:func:`run_engine_bench`.
|
|
70
|
-
|
|
71
|
-
Returns:
|
|
72
|
-
The created ``ArgumentParser`` (mostly for testing).
|
|
61
|
+
parser: The ``ArgumentParser`` for the engine bench subcommand.
|
|
73
62
|
"""
|
|
74
|
-
parser = subparsers.add_parser(
|
|
75
|
-
"engine",
|
|
76
|
-
help="Benchmark an inference engine.",
|
|
77
|
-
)
|
|
78
63
|
|
|
79
64
|
# --- Config file ---
|
|
80
65
|
parser.add_argument(
|
|
@@ -337,9 +322,6 @@ def register_engine_parser(
|
|
|
337
322
|
help="Number of requests to send (default: 50).",
|
|
338
323
|
)
|
|
339
324
|
|
|
340
|
-
parser.set_defaults(func=dispatch_func)
|
|
341
|
-
return parser
|
|
342
|
-
|
|
343
325
|
|
|
344
326
|
# ---------------------------------------------------------------------------
|
|
345
327
|
# Argument resolution helpers
|
|
@@ -1,2 +1,38 @@
|
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
"""
|
|
2
|
+
"""``lmcache bench l2`` subpackage.
|
|
3
|
+
|
|
4
|
+
Exposes :class:`L2AdapterBenchCommand` for auto-discovery by
|
|
5
|
+
:class:`~lmcache.cli.commands.base.CompositeCommand`.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Standard
|
|
9
|
+
import argparse
|
|
10
|
+
|
|
11
|
+
# First Party
|
|
12
|
+
from lmcache.cli.commands.base import BaseCommand
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class L2AdapterBenchCommand(BaseCommand):
|
|
16
|
+
"""Benchmark an L2 adapter (store / lookup / load)."""
|
|
17
|
+
|
|
18
|
+
def name(self) -> str:
|
|
19
|
+
return "l2"
|
|
20
|
+
|
|
21
|
+
def help(self) -> str:
|
|
22
|
+
return "Benchmark an L2 adapter (store / lookup / load)."
|
|
23
|
+
|
|
24
|
+
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
|
|
25
|
+
# First Party
|
|
26
|
+
from lmcache.cli.commands.bench.l2_adapter_bench.command import (
|
|
27
|
+
add_l2_arguments,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
add_l2_arguments(parser)
|
|
31
|
+
|
|
32
|
+
def execute(self, args: argparse.Namespace) -> None:
|
|
33
|
+
# First Party
|
|
34
|
+
from lmcache.cli.commands.bench.l2_adapter_bench.command import (
|
|
35
|
+
run_l2_adapter_bench,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
run_l2_adapter_bench(self, args)
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
"""``lmcache bench l2`` subcommand implementation.
|
|
3
3
|
|
|
4
|
-
This module
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
:func:`register_l2_parser`.
|
|
4
|
+
This module provides argument registration via :func:`add_l2_arguments`
|
|
5
|
+
and the execution orchestrator :func:`run_l2_adapter_bench` for the L2
|
|
6
|
+
adapter benchmark.
|
|
8
7
|
"""
|
|
9
8
|
|
|
10
9
|
# Future
|
|
@@ -16,15 +15,6 @@ import argparse
|
|
|
16
15
|
import os
|
|
17
16
|
import sys
|
|
18
17
|
|
|
19
|
-
# First Party
|
|
20
|
-
# Reuse the common helper that wires up ``--format / --output /
|
|
21
|
-
# --quiet`` onto a subparser. ``BenchCommand.register`` is overridden
|
|
22
|
-
# and creates inner subparsers manually, bypassing the auto-wiring
|
|
23
|
-
# that ``BaseCommand.register`` normally performs, so we attach those
|
|
24
|
-
# common flags ourselves only on the L2 subparser. The ``engine`` and
|
|
25
|
-
# ``kvcache`` subparsers intentionally stay untouched.
|
|
26
|
-
from lmcache.cli.commands.base import _add_output_args
|
|
27
|
-
|
|
28
18
|
if TYPE_CHECKING:
|
|
29
19
|
# First Party
|
|
30
20
|
from lmcache.cli.commands.base import BaseCommand
|
|
@@ -36,32 +26,12 @@ if TYPE_CHECKING:
|
|
|
36
26
|
# ---------------------------------------------------------------------------
|
|
37
27
|
|
|
38
28
|
|
|
39
|
-
def
|
|
40
|
-
|
|
41
|
-
dispatch_func,
|
|
42
|
-
) -> argparse.ArgumentParser:
|
|
43
|
-
"""Register the ``lmcache bench l2`` subcommand parser.
|
|
29
|
+
def add_l2_arguments(parser: argparse.ArgumentParser) -> None:
|
|
30
|
+
"""Add ``lmcache bench l2`` arguments to *parser*.
|
|
44
31
|
|
|
45
32
|
Args:
|
|
46
|
-
|
|
47
|
-
dispatch_func: Function to bind via ``set_defaults(func=...)``.
|
|
48
|
-
Typically ``BenchCommand.execute`` so that the outer
|
|
49
|
-
dispatcher can route the call back into
|
|
50
|
-
:func:`run_l2_adapter_bench`.
|
|
51
|
-
|
|
52
|
-
Returns:
|
|
53
|
-
The created ``ArgumentParser`` (mostly for testing).
|
|
33
|
+
parser: The ``ArgumentParser`` for the L2 bench subcommand.
|
|
54
34
|
"""
|
|
55
|
-
parser = subparsers.add_parser(
|
|
56
|
-
"l2",
|
|
57
|
-
help="Benchmark an L2 adapter (store / lookup / load).",
|
|
58
|
-
description=(
|
|
59
|
-
"Benchmark L2 adapters using the standard LMCache adapter "
|
|
60
|
-
"configuration mechanism (parse_args_to_l2_adapters_config "
|
|
61
|
-
"+ create_l2_adapter). Any registered adapter type can be "
|
|
62
|
-
"tested without code changes."
|
|
63
|
-
),
|
|
64
|
-
)
|
|
65
35
|
|
|
66
36
|
parser.add_argument(
|
|
67
37
|
"--l2-adapter",
|
|
@@ -153,14 +123,6 @@ def register_l2_parser(
|
|
|
153
123
|
help="Run only the specified operation (default: run all).",
|
|
154
124
|
)
|
|
155
125
|
|
|
156
|
-
# Common ``--format / --output / --quiet`` flags. Attached only
|
|
157
|
-
# to the L2 subparser; the ``engine`` and ``kvcache`` subparsers
|
|
158
|
-
# intentionally keep their existing arguments unchanged.
|
|
159
|
-
_add_output_args(parser)
|
|
160
|
-
|
|
161
|
-
parser.set_defaults(func=dispatch_func)
|
|
162
|
-
return parser
|
|
163
|
-
|
|
164
126
|
|
|
165
127
|
# ---------------------------------------------------------------------------
|
|
166
128
|
# Core benchmark runner
|
|
@@ -20,7 +20,7 @@ import time
|
|
|
20
20
|
|
|
21
21
|
# First Party
|
|
22
22
|
from lmcache.native_storage_ops import Bitmap
|
|
23
|
-
from lmcache.v1.distributed.api import ObjectKey
|
|
23
|
+
from lmcache.v1.distributed.api import MemoryLayoutDesc, ObjectKey
|
|
24
24
|
from lmcache.v1.distributed.internal_api import L2StoreResult
|
|
25
25
|
from lmcache.v1.memory_management import MemoryObj
|
|
26
26
|
|
|
@@ -37,6 +37,10 @@ LogFn = Callable[[str], None]
|
|
|
37
37
|
KeyProvider = Callable[[int], list[list[ObjectKey]]]
|
|
38
38
|
ObjProvider = Callable[[int], list[list[MemoryObj]]]
|
|
39
39
|
|
|
40
|
+
# TODO: bench passes a placeholder layout_desc; a real layout may be
|
|
41
|
+
# required here in the future (e.g. when benchmarking the P2P adapter).
|
|
42
|
+
_PLACEHOLDER_LAYOUT_DESC = MemoryLayoutDesc(shapes=[], dtypes=[])
|
|
43
|
+
|
|
40
44
|
|
|
41
45
|
def _bitmap_count(bitmap: Bitmap | None) -> int:
|
|
42
46
|
"""Count how many bits are set in *bitmap*. Returns 0 when None."""
|
|
@@ -217,6 +221,11 @@ def bench_lookup(
|
|
|
217
221
|
expected_hit_count=expected_hit_count,
|
|
218
222
|
)
|
|
219
223
|
|
|
224
|
+
log(
|
|
225
|
+
"bench_lookup uses a placeholder MemoryLayoutDesc; this may need a "
|
|
226
|
+
"real layout for layout-sensitive adapters"
|
|
227
|
+
)
|
|
228
|
+
|
|
220
229
|
for r in range(rounds):
|
|
221
230
|
keys_batches = keys_for_round(r)
|
|
222
231
|
assert len(keys_batches) == in_flight
|
|
@@ -224,7 +233,11 @@ def bench_lookup(
|
|
|
224
233
|
t0 = time.perf_counter()
|
|
225
234
|
task_ids: list[int] = []
|
|
226
235
|
for i in range(in_flight):
|
|
227
|
-
task_ids.append(
|
|
236
|
+
task_ids.append(
|
|
237
|
+
adapter.submit_lookup_and_lock_task(
|
|
238
|
+
keys_batches[i], _PLACEHOLDER_LAYOUT_DESC
|
|
239
|
+
)
|
|
240
|
+
)
|
|
228
241
|
|
|
229
242
|
results = _wait_lookup_finished(adapter, task_ids, 60.0)
|
|
230
243
|
t1 = time.perf_counter()
|
|
@@ -1,2 +1,38 @@
|
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
"""
|
|
2
|
+
"""``lmcache bench server`` subpackage.
|
|
3
|
+
|
|
4
|
+
Exposes :class:`ServerBenchCommand` for auto-discovery by
|
|
5
|
+
:class:`~lmcache.cli.commands.base.CompositeCommand`.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Standard
|
|
9
|
+
import argparse
|
|
10
|
+
|
|
11
|
+
# First Party
|
|
12
|
+
from lmcache.cli.commands.base import BaseCommand
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ServerBenchCommand(BaseCommand):
|
|
16
|
+
"""End-to-end test for LMCache MP cache server."""
|
|
17
|
+
|
|
18
|
+
def name(self) -> str:
|
|
19
|
+
return "server"
|
|
20
|
+
|
|
21
|
+
def help(self) -> str:
|
|
22
|
+
return "End-to-end test for LMCache MP cache server (GPU mode)."
|
|
23
|
+
|
|
24
|
+
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
|
|
25
|
+
# First Party
|
|
26
|
+
from lmcache.cli.commands.bench.server_bench.command import (
|
|
27
|
+
add_server_arguments,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
add_server_arguments(parser)
|
|
31
|
+
|
|
32
|
+
def execute(self, args: argparse.Namespace) -> None:
|
|
33
|
+
# First Party
|
|
34
|
+
from lmcache.cli.commands.bench.server_bench.command import (
|
|
35
|
+
run_server_bench,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
run_server_bench(self, args)
|