lmcache-cli 0.4.8.dev42__py3-none-any.whl → 0.5.1.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.
Files changed (134) hide show
  1. lmcache/__init__.py +8 -0
  2. lmcache/_version.py +3 -3
  3. lmcache/cli/commands/__init__.py +2 -2
  4. lmcache/cli/commands/base.py +97 -0
  5. lmcache/cli/commands/bench/__init__.py +8 -54
  6. lmcache/cli/commands/bench/engine_bench/__init__.py +48 -0
  7. lmcache/cli/commands/bench/engine_bench/command.py +6 -24
  8. lmcache/cli/commands/bench/l2_adapter_bench/__init__.py +37 -1
  9. lmcache/cli/commands/bench/l2_adapter_bench/command.py +6 -44
  10. lmcache/cli/commands/bench/l2_adapter_bench/runner.py +15 -2
  11. lmcache/cli/commands/bench/server_bench/__init__.py +37 -1
  12. lmcache/cli/commands/bench/server_bench/command.py +37 -56
  13. lmcache/cli/commands/bench/server_bench/helpers.py +43 -2
  14. lmcache/cli/commands/query/__init__.py +5 -61
  15. lmcache/cli/commands/query/engine_command.py +91 -113
  16. lmcache/cli/commands/query/kvcache_command.py +18 -39
  17. lmcache/cli/commands/quota/__init__.py +5 -76
  18. lmcache/cli/commands/quota/delete_command.py +37 -64
  19. lmcache/cli/commands/quota/get_command.py +41 -67
  20. lmcache/cli/commands/quota/list_command.py +33 -57
  21. lmcache/cli/commands/quota/set_command.py +50 -77
  22. lmcache/cli/commands/server.py +2 -0
  23. lmcache/cli/commands/tool/__init__.py +5 -49
  24. lmcache/cli/commands/tool/cache_simulator/__init__.py +21 -0
  25. lmcache/cli/commands/tool/cache_simulator/gen_dataset_command.py +48 -0
  26. lmcache/cli/commands/tool/cache_simulator/simulate_command.py +46 -0
  27. lmcache/cli/commands/tool/cache_simulator/sweep_command.py +45 -0
  28. lmcache/cli/commands/tool/transfer_channel_benchmark.py +64 -41
  29. lmcache/cli/commands/trace/__init__.py +5 -117
  30. lmcache/cli/commands/trace/{driver.py → _driver.py} +2 -2
  31. lmcache/cli/commands/trace/info_command.py +46 -67
  32. lmcache/cli/commands/trace/replay_command.py +24 -38
  33. lmcache/integration/sglang/multi_process_adapter.py +33 -26
  34. lmcache/integration/vllm/lmcache_mp_connector.py +77 -8
  35. lmcache/integration/vllm/vllm_multi_process_adapter.py +201 -72
  36. lmcache/native_storage_ops.pyi +60 -0
  37. lmcache/observability.py +1 -1
  38. lmcache/usage_context.py +2 -2
  39. lmcache/utils.py +1 -1
  40. lmcache/v1/config.py +1 -1
  41. lmcache/v1/config_base.py +4 -4
  42. lmcache/v1/distributed/bitmap_ops/README.md +57 -0
  43. lmcache/v1/distributed/bitmap_ops/__init__.py +31 -0
  44. lmcache/v1/distributed/bitmap_ops/fold.py +339 -0
  45. lmcache/v1/distributed/config.py +18 -0
  46. lmcache/v1/distributed/l2_adapters/base.py +5 -1
  47. lmcache/v1/distributed/l2_adapters/dax_l2_adapter.py +4 -2
  48. lmcache/v1/distributed/l2_adapters/fault_inject_l2_adapter.py +5 -3
  49. lmcache/v1/distributed/l2_adapters/fs_l2_adapter.py +4 -2
  50. lmcache/v1/distributed/l2_adapters/hfbucket_l2_adapter.py +4 -2
  51. lmcache/v1/distributed/l2_adapters/mock_l2_adapter.py +4 -2
  52. lmcache/v1/distributed/l2_adapters/native_connector_l2_adapter.py +2 -1
  53. lmcache/v1/distributed/l2_adapters/nixl_store_dynamic_l2_adapter.py +3 -1
  54. lmcache/v1/distributed/l2_adapters/nixl_store_l2_adapter.py +3 -1
  55. lmcache/v1/distributed/l2_adapters/p2p_l2_adapter.py +406 -0
  56. lmcache/v1/distributed/l2_adapters/raw_block_l2_adapter.py +4 -2
  57. lmcache/v1/distributed/l2_adapters/s3_l2_adapter.py +10 -3
  58. lmcache/v1/distributed/l2_adapters/serde_wrapper.py +4 -2
  59. lmcache/v1/distributed/storage_controllers/adapter_lifecycle.py +45 -0
  60. lmcache/v1/distributed/storage_controllers/eviction_controller.py +30 -3
  61. lmcache/v1/distributed/storage_controllers/prefetch_controller.py +241 -31
  62. lmcache/v1/distributed/storage_controllers/store_controller.py +187 -20
  63. lmcache/v1/distributed/storage_manager.py +248 -63
  64. lmcache/v1/distributed/transfer_channel/abstract.py +17 -0
  65. lmcache/v1/distributed/transfer_channel/impl/nixl_impl.py +51 -17
  66. lmcache/v1/gpu_connector/gpu_connectors.py +3 -1
  67. lmcache/v1/gpu_connector/kv_format/__init__.py +30 -0
  68. lmcache/v1/gpu_connector/kv_format/contiguity.py +147 -0
  69. lmcache/v1/gpu_connector/kv_format/detection.py +47 -0
  70. lmcache/v1/gpu_connector/kv_format/detectors/__init__.py +11 -0
  71. lmcache/v1/gpu_connector/kv_format/detectors/base.py +52 -0
  72. lmcache/v1/gpu_connector/kv_format/detectors/registry.py +43 -0
  73. lmcache/v1/gpu_connector/kv_format/detectors/sglang.py +67 -0
  74. lmcache/v1/gpu_connector/kv_format/detectors/trtllm.py +61 -0
  75. lmcache/v1/gpu_connector/kv_format/detectors/vllm.py +72 -0
  76. lmcache/v1/gpu_connector/kv_format/specs/__init__.py +22 -0
  77. lmcache/v1/gpu_connector/kv_format/specs/base.py +176 -0
  78. lmcache/v1/gpu_connector/kv_format/specs/nb_nl_two_bs_nh_hs.py +59 -0
  79. lmcache/v1/gpu_connector/kv_format/specs/nb_nl_two_nh_bs_hs.py +61 -0
  80. lmcache/v1/gpu_connector/kv_format/specs/nl_x_nb_bs_hs.py +58 -0
  81. lmcache/v1/gpu_connector/kv_format/specs/nl_x_nb_nh_bs_two_hs.py +63 -0
  82. lmcache/v1/gpu_connector/kv_format/specs/nl_x_nb_two_bs_nh_hs.py +60 -0
  83. lmcache/v1/gpu_connector/kv_format/specs/nl_x_nb_two_nh_bs_hs.py +62 -0
  84. lmcache/v1/gpu_connector/kv_format/specs/nl_x_nbbs_one_hs.py +63 -0
  85. lmcache/v1/gpu_connector/kv_format/specs/nl_x_two_nb_bs_nh_hs.py +60 -0
  86. lmcache/v1/gpu_connector/kv_format/specs/nl_x_two_nb_nh_bs_hs.py +61 -0
  87. lmcache/v1/gpu_connector/kv_format/specs/registry.py +56 -0
  88. lmcache/v1/gpu_connector/kv_format/specs/two_x_nl_x_nb_bs_nh_hs.py +61 -0
  89. lmcache/v1/gpu_connector/kv_format/specs/two_x_nl_x_nbbs_nh_hs.py +65 -0
  90. lmcache/v1/gpu_connector/kv_format/types.py +52 -0
  91. lmcache/v1/gpu_connector/musa_connectors.py +23 -14
  92. lmcache/v1/gpu_connector/utils.py +164 -1058
  93. lmcache/v1/lookup_client/lmcache_lookup_client.py +3 -3
  94. lmcache/v1/lookup_client/lmcache_lookup_client_bypass.py +1 -1
  95. lmcache/v1/memory_management.py +7 -7
  96. lmcache/v1/mp_coordinator/http_apis/instances_api.py +2 -0
  97. lmcache/v1/mp_coordinator/registrar.py +19 -1
  98. lmcache/v1/mp_coordinator/registry.py +4 -0
  99. lmcache/v1/mp_coordinator/schemas.py +4 -0
  100. lmcache/v1/multiprocess/config.py +113 -0
  101. lmcache/v1/multiprocess/custom_types.py +87 -58
  102. lmcache/v1/multiprocess/http_server.py +26 -6
  103. lmcache/v1/multiprocess/modules/blend_v3.py +3 -3
  104. lmcache/v1/multiprocess/modules/lookup.py +38 -0
  105. lmcache/v1/multiprocess/modules/p2p_controller.py +338 -10
  106. lmcache/v1/multiprocess/mp_runtime_plugin_launcher.py +1 -1
  107. lmcache/v1/multiprocess/mq.py +7 -7
  108. lmcache/v1/multiprocess/protocols/base.py +1 -0
  109. lmcache/v1/multiprocess/protocols/blend_v3.py +2 -2
  110. lmcache/v1/multiprocess/protocols/engine.py +11 -0
  111. lmcache/v1/multiprocess/server.py +23 -2
  112. lmcache/v1/platform/cpu/shm.py +9 -7
  113. lmcache/v1/platform/musa/__init__.py +2 -0
  114. lmcache/v1/platform/musa/native_kv_transfer.py +486 -0
  115. lmcache/v1/platform/musa/ops.py +91 -0
  116. lmcache/v1/rpc_utils.py +1 -1
  117. lmcache/v1/storage_backend/connector/valkey_connector.py +32 -3
  118. lmcache/v1/storage_backend/pd_backend_async.py +86 -47
  119. lmcache/v1/token_database.py +2 -2
  120. {lmcache_cli-0.4.8.dev42.dist-info → lmcache_cli-0.5.1.dev0.dist-info}/METADATA +1 -1
  121. {lmcache_cli-0.4.8.dev42.dist-info → lmcache_cli-0.5.1.dev0.dist-info}/RECORD +132 -96
  122. lmcache_cli-0.5.1.dev0.dist-info/scm_file_list.json +1976 -0
  123. lmcache_cli-0.5.1.dev0.dist-info/scm_version.json +8 -0
  124. lmcache/cli/commands/tool/cache_simulator.py +0 -113
  125. lmcache/v1/gpu_connector/musa_native.py +0 -218
  126. /lmcache/cli/commands/query/{prompt.py → _prompt.py} +0 -0
  127. /lmcache/cli/commands/query/{request.py → _request.py} +0 -0
  128. /lmcache/cli/commands/quota/{helpers.py → _helpers.py} +0 -0
  129. /lmcache/cli/commands/trace/{dispatch.py → _dispatch.py} +0 -0
  130. /lmcache/cli/commands/trace/{stats.py → _stats.py} +0 -0
  131. {lmcache_cli-0.4.8.dev42.dist-info → lmcache_cli-0.5.1.dev0.dist-info}/WHEEL +0 -0
  132. {lmcache_cli-0.4.8.dev42.dist-info → lmcache_cli-0.5.1.dev0.dist-info}/entry_points.txt +0 -0
  133. {lmcache_cli-0.4.8.dev42.dist-info → lmcache_cli-0.5.1.dev0.dist-info}/licenses/LICENSE +0 -0
  134. {lmcache_cli-0.4.8.dev42.dist-info → lmcache_cli-0.5.1.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.4.8.dev42'
22
- __version_tuple__ = version_tuple = (0, 4, 8, 'dev42')
21
+ __version__ = version = '0.5.1.dev0'
22
+ __version_tuple__ = version_tuple = (0, 5, 1, 'dev0')
23
23
 
24
- __commit_id__ = commit_id = 'g9ffb104f3'
24
+ __commit_id__ = commit_id = 'g389b9cfcb'
@@ -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"]
@@ -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
- # Standard
5
- import argparse
6
- import sys
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 BaseCommand
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 owns the full registration + execution flow for the
5
- inference engine benchmark. ``BenchCommand`` only forwards CLI dispatch
6
- to :func:`run_engine_bench` and parser registration to
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 register_engine_parser(
59
- subparsers: argparse._SubParsersAction,
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
- subparsers: The ``bench`` subparsers action.
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
- """L2 adapter benchmark subpackage for ``lmcache bench l2``."""
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 owns the full registration + execution flow for the L2
5
- adapter benchmark. ``BenchCommand`` only forwards CLI dispatch to
6
- :func:`run_l2_adapter_bench` and parser registration to
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 register_l2_parser(
40
- subparsers: argparse._SubParsersAction,
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
- subparsers: The ``bench`` subparsers action.
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(adapter.submit_lookup_and_lock_task(keys_batches[i]))
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
- """Server benchmark subpackage for ``lmcache bench server``."""
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)