lmcache-cli 0.4.5.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 (399) hide show
  1. lmcache/__init__.py +84 -0
  2. lmcache/_version.py +24 -0
  3. lmcache/cli/__init__.py +1 -0
  4. lmcache/cli/commands/__init__.py +34 -0
  5. lmcache/cli/commands/base.py +157 -0
  6. lmcache/cli/commands/bench/__init__.py +557 -0
  7. lmcache/cli/commands/bench/engine_bench/__init__.py +1 -0
  8. lmcache/cli/commands/bench/engine_bench/config.py +245 -0
  9. lmcache/cli/commands/bench/engine_bench/interactive/__init__.py +274 -0
  10. lmcache/cli/commands/bench/engine_bench/interactive/config.json +10 -0
  11. lmcache/cli/commands/bench/engine_bench/interactive/schema.py +352 -0
  12. lmcache/cli/commands/bench/engine_bench/interactive/state.py +327 -0
  13. lmcache/cli/commands/bench/engine_bench/interactive/terminal.py +291 -0
  14. lmcache/cli/commands/bench/engine_bench/progress.py +145 -0
  15. lmcache/cli/commands/bench/engine_bench/request_sender.py +232 -0
  16. lmcache/cli/commands/bench/engine_bench/stats.py +275 -0
  17. lmcache/cli/commands/bench/engine_bench/workloads/__init__.py +153 -0
  18. lmcache/cli/commands/bench/engine_bench/workloads/base.py +122 -0
  19. lmcache/cli/commands/bench/engine_bench/workloads/long_doc_permutator.py +435 -0
  20. lmcache/cli/commands/bench/engine_bench/workloads/long_doc_qa.py +281 -0
  21. lmcache/cli/commands/bench/engine_bench/workloads/multi_round_chat.py +337 -0
  22. lmcache/cli/commands/bench/engine_bench/workloads/random_prefill.py +178 -0
  23. lmcache/cli/commands/describe.py +310 -0
  24. lmcache/cli/commands/kvcache.py +133 -0
  25. lmcache/cli/commands/mock.py +75 -0
  26. lmcache/cli/commands/ping.py +113 -0
  27. lmcache/cli/commands/query/__init__.py +155 -0
  28. lmcache/cli/commands/query/prompt.py +134 -0
  29. lmcache/cli/commands/query/request.py +357 -0
  30. lmcache/cli/commands/server.py +99 -0
  31. lmcache/cli/commands/tool/__init__.py +63 -0
  32. lmcache/cli/commands/tool/cache_simulator.py +113 -0
  33. lmcache/cli/commands/trace/__init__.py +505 -0
  34. lmcache/cli/commands/trace/dispatch.py +249 -0
  35. lmcache/cli/commands/trace/driver.py +372 -0
  36. lmcache/cli/commands/trace/stats.py +289 -0
  37. lmcache/cli/documents/lmcache.txt +11 -0
  38. lmcache/cli/main.py +42 -0
  39. lmcache/cli/metrics/__init__.py +29 -0
  40. lmcache/cli/metrics/formatter.py +171 -0
  41. lmcache/cli/metrics/handler.py +94 -0
  42. lmcache/cli/metrics/metrics.py +161 -0
  43. lmcache/cli/metrics/section.py +77 -0
  44. lmcache/connections.py +173 -0
  45. lmcache/integration/__init__.py +2 -0
  46. lmcache/integration/base_service_factory.py +165 -0
  47. lmcache/integration/request_telemetry/__init__.py +1 -0
  48. lmcache/integration/request_telemetry/base.py +51 -0
  49. lmcache/integration/request_telemetry/factory.py +113 -0
  50. lmcache/integration/request_telemetry/fastapi.py +109 -0
  51. lmcache/integration/request_telemetry/noop.py +35 -0
  52. lmcache/integration/sglang/__init__.py +2 -0
  53. lmcache/integration/sglang/sglang_adapter.py +326 -0
  54. lmcache/integration/sglang/utils.py +39 -0
  55. lmcache/integration/vllm/__init__.py +1 -0
  56. lmcache/integration/vllm/lmcache_connector_v1.py +213 -0
  57. lmcache/integration/vllm/lmcache_connector_v1_085.py +150 -0
  58. lmcache/integration/vllm/lmcache_mp_connector_0180.py +1072 -0
  59. lmcache/integration/vllm/tests/test_mm_hash_utils.py +112 -0
  60. lmcache/integration/vllm/utils.py +433 -0
  61. lmcache/integration/vllm/vllm_multi_process_adapter.py +1090 -0
  62. lmcache/integration/vllm/vllm_service_factory.py +339 -0
  63. lmcache/integration/vllm/vllm_v1_adapter.py +1713 -0
  64. lmcache/logging.py +107 -0
  65. lmcache/native_storage_ops.pyi +230 -0
  66. lmcache/non_cuda_equivalents.py +1424 -0
  67. lmcache/observability.py +1958 -0
  68. lmcache/storage_backend/serde/__init__.py +1 -0
  69. lmcache/storage_backend/serde/cachegen_basics.py +210 -0
  70. lmcache/storage_backend/serde/cachegen_decoder.py +207 -0
  71. lmcache/storage_backend/serde/cachegen_encoder.py +394 -0
  72. lmcache/storage_backend/serde/serde.py +75 -0
  73. lmcache/tools/__init__.py +1 -0
  74. lmcache/tools/cache_simulator/README.md +392 -0
  75. lmcache/tools/cache_simulator/__init__.py +1 -0
  76. lmcache/tools/cache_simulator/docs/simulate_example.png +0 -0
  77. lmcache/tools/cache_simulator/docs/sweep_example.png +0 -0
  78. lmcache/tools/cache_simulator/gen_bench_dataset.py +360 -0
  79. lmcache/tools/cache_simulator/lru_cache.py +124 -0
  80. lmcache/tools/cache_simulator/plot_hit_rate.py +231 -0
  81. lmcache/tools/cache_simulator/simulator.py +795 -0
  82. lmcache/tools/controller_benchmark/README.md +161 -0
  83. lmcache/tools/controller_benchmark/__init__.py +1 -0
  84. lmcache/tools/controller_benchmark/__main__.py +331 -0
  85. lmcache/tools/controller_benchmark/benchmark.py +660 -0
  86. lmcache/tools/controller_benchmark/config.py +44 -0
  87. lmcache/tools/controller_benchmark/constants.py +10 -0
  88. lmcache/tools/controller_benchmark/handlers/__init__.py +46 -0
  89. lmcache/tools/controller_benchmark/handlers/admit.py +52 -0
  90. lmcache/tools/controller_benchmark/handlers/base.py +47 -0
  91. lmcache/tools/controller_benchmark/handlers/deregister.py +49 -0
  92. lmcache/tools/controller_benchmark/handlers/evict.py +52 -0
  93. lmcache/tools/controller_benchmark/handlers/heartbeat.py +56 -0
  94. lmcache/tools/controller_benchmark/handlers/p2p_lookup.py +47 -0
  95. lmcache/tools/controller_benchmark/handlers/register.py +56 -0
  96. lmcache/tools/mp_status_viewer/__init__.py +1 -0
  97. lmcache/tools/mp_status_viewer/__main__.py +95 -0
  98. lmcache/usage_context.py +417 -0
  99. lmcache/utils.py +665 -0
  100. lmcache/v1/__init__.py +2 -0
  101. lmcache/v1/api_server/__init__.py +2 -0
  102. lmcache/v1/api_server/__main__.py +537 -0
  103. lmcache/v1/basic_check.py +112 -0
  104. lmcache/v1/cache_controller/__init__.py +9 -0
  105. lmcache/v1/cache_controller/commands/__init__.py +15 -0
  106. lmcache/v1/cache_controller/commands/base.py +35 -0
  107. lmcache/v1/cache_controller/commands/full_sync.py +49 -0
  108. lmcache/v1/cache_controller/config.py +176 -0
  109. lmcache/v1/cache_controller/controller_manager.py +535 -0
  110. lmcache/v1/cache_controller/controllers/__init__.py +11 -0
  111. lmcache/v1/cache_controller/controllers/full_sync_tracker.py +473 -0
  112. lmcache/v1/cache_controller/controllers/kv_controller.py +439 -0
  113. lmcache/v1/cache_controller/controllers/registration_controller.py +282 -0
  114. lmcache/v1/cache_controller/executor.py +463 -0
  115. lmcache/v1/cache_controller/frontend/static/css/style.css +201 -0
  116. lmcache/v1/cache_controller/frontend/static/img/logo.png +0 -0
  117. lmcache/v1/cache_controller/frontend/static/index.html +234 -0
  118. lmcache/v1/cache_controller/frontend/static/js/controller_app.js +660 -0
  119. lmcache/v1/cache_controller/full_sync_sender.py +475 -0
  120. lmcache/v1/cache_controller/locks.py +149 -0
  121. lmcache/v1/cache_controller/message.py +828 -0
  122. lmcache/v1/cache_controller/observability.py +208 -0
  123. lmcache/v1/cache_controller/utils.py +679 -0
  124. lmcache/v1/cache_controller/worker.py +665 -0
  125. lmcache/v1/cache_engine.py +2058 -0
  126. lmcache/v1/cache_interface.py +19 -0
  127. lmcache/v1/check/__init__.py +74 -0
  128. lmcache/v1/check/check_mode_gen.py +86 -0
  129. lmcache/v1/check/check_mode_test_l2_adapter.py +284 -0
  130. lmcache/v1/check/check_mode_test_remote.py +155 -0
  131. lmcache/v1/check/check_mode_test_storage_manager.py +142 -0
  132. lmcache/v1/check/utils.py +571 -0
  133. lmcache/v1/compute/__init__.py +2 -0
  134. lmcache/v1/compute/attention/__init__.py +0 -0
  135. lmcache/v1/compute/attention/abstract.py +39 -0
  136. lmcache/v1/compute/attention/flash_attn.py +129 -0
  137. lmcache/v1/compute/attention/flash_infer_sparse.py +284 -0
  138. lmcache/v1/compute/attention/metadata.py +85 -0
  139. lmcache/v1/compute/attention/utils.py +14 -0
  140. lmcache/v1/compute/blend/__init__.py +7 -0
  141. lmcache/v1/compute/blend/blender.py +168 -0
  142. lmcache/v1/compute/blend/metadata.py +34 -0
  143. lmcache/v1/compute/blend/utils.py +63 -0
  144. lmcache/v1/compute/models/__init__.py +0 -0
  145. lmcache/v1/compute/models/base.py +141 -0
  146. lmcache/v1/compute/models/llama.py +9 -0
  147. lmcache/v1/compute/models/qwen3.py +24 -0
  148. lmcache/v1/compute/models/utils.py +68 -0
  149. lmcache/v1/compute/positional_encoding.py +199 -0
  150. lmcache/v1/config.py +848 -0
  151. lmcache/v1/config_base.py +848 -0
  152. lmcache/v1/distributed/api.py +248 -0
  153. lmcache/v1/distributed/config.py +321 -0
  154. lmcache/v1/distributed/error.py +64 -0
  155. lmcache/v1/distributed/eviction.py +192 -0
  156. lmcache/v1/distributed/eviction_policy/__init__.py +21 -0
  157. lmcache/v1/distributed/eviction_policy/factory.py +27 -0
  158. lmcache/v1/distributed/eviction_policy/lru.py +244 -0
  159. lmcache/v1/distributed/eviction_policy/noop.py +50 -0
  160. lmcache/v1/distributed/internal_api.py +170 -0
  161. lmcache/v1/distributed/l1_manager.py +835 -0
  162. lmcache/v1/distributed/l2_adapters/__init__.py +67 -0
  163. lmcache/v1/distributed/l2_adapters/base.py +360 -0
  164. lmcache/v1/distributed/l2_adapters/config.py +385 -0
  165. lmcache/v1/distributed/l2_adapters/factory.py +205 -0
  166. lmcache/v1/distributed/l2_adapters/fs_l2_adapter.py +747 -0
  167. lmcache/v1/distributed/l2_adapters/fs_native_l2_adapter.py +167 -0
  168. lmcache/v1/distributed/l2_adapters/mock_l2_adapter.py +516 -0
  169. lmcache/v1/distributed/l2_adapters/mooncake_store_l2_adapter.py +135 -0
  170. lmcache/v1/distributed/l2_adapters/native_connector_l2_adapter.py +468 -0
  171. lmcache/v1/distributed/l2_adapters/native_plugin_l2_adapter.py +199 -0
  172. lmcache/v1/distributed/l2_adapters/nixl_store_dynamic_l2_adapter.py +831 -0
  173. lmcache/v1/distributed/l2_adapters/nixl_store_l2_adapter.py +983 -0
  174. lmcache/v1/distributed/l2_adapters/plugin_l2_adapter.py +210 -0
  175. lmcache/v1/distributed/l2_adapters/resp_l2_adapter.py +176 -0
  176. lmcache/v1/distributed/memory_manager.py +179 -0
  177. lmcache/v1/distributed/storage_controller.py +39 -0
  178. lmcache/v1/distributed/storage_controllers/__init__.py +43 -0
  179. lmcache/v1/distributed/storage_controllers/eviction_controller.py +242 -0
  180. lmcache/v1/distributed/storage_controllers/prefetch_controller.py +830 -0
  181. lmcache/v1/distributed/storage_controllers/prefetch_policy.py +193 -0
  182. lmcache/v1/distributed/storage_controllers/store_controller.py +452 -0
  183. lmcache/v1/distributed/storage_controllers/store_policy.py +213 -0
  184. lmcache/v1/distributed/storage_manager.py +532 -0
  185. lmcache/v1/event_manager.py +145 -0
  186. lmcache/v1/exceptions/__init__.py +16 -0
  187. lmcache/v1/gpu_connector/__init__.py +126 -0
  188. lmcache/v1/gpu_connector/gpu_connectors.py +1906 -0
  189. lmcache/v1/gpu_connector/gpu_ops.py +85 -0
  190. lmcache/v1/gpu_connector/hpu_connector.py +326 -0
  191. lmcache/v1/gpu_connector/mock_gpu_connector.py +67 -0
  192. lmcache/v1/gpu_connector/utils.py +890 -0
  193. lmcache/v1/gpu_connector/xpu_connectors.py +916 -0
  194. lmcache/v1/health_monitor/__init__.py +1 -0
  195. lmcache/v1/health_monitor/base.py +587 -0
  196. lmcache/v1/health_monitor/checks/__init__.py +1 -0
  197. lmcache/v1/health_monitor/checks/remote_backend_check.py +304 -0
  198. lmcache/v1/health_monitor/constants.py +36 -0
  199. lmcache/v1/internal_api_server/__init__.py +0 -0
  200. lmcache/v1/internal_api_server/api_registry.py +59 -0
  201. lmcache/v1/internal_api_server/api_server.py +120 -0
  202. lmcache/v1/internal_api_server/common/__init__.py +1 -0
  203. lmcache/v1/internal_api_server/common/env_api.py +22 -0
  204. lmcache/v1/internal_api_server/common/loglevel_api.py +57 -0
  205. lmcache/v1/internal_api_server/common/metrics_api.py +29 -0
  206. lmcache/v1/internal_api_server/common/periodic_thread_api.py +138 -0
  207. lmcache/v1/internal_api_server/common/run_script_api.py +73 -0
  208. lmcache/v1/internal_api_server/common/thread_api.py +63 -0
  209. lmcache/v1/internal_api_server/controller/__init__.py +1 -0
  210. lmcache/v1/internal_api_server/controller/key_stats_api.py +81 -0
  211. lmcache/v1/internal_api_server/controller/worker_info_api.py +136 -0
  212. lmcache/v1/internal_api_server/utils.py +43 -0
  213. lmcache/v1/internal_api_server/vllm/__init__.py +1 -0
  214. lmcache/v1/internal_api_server/vllm/backend_api.py +221 -0
  215. lmcache/v1/internal_api_server/vllm/bypass_api.py +204 -0
  216. lmcache/v1/internal_api_server/vllm/cache_api.py +895 -0
  217. lmcache/v1/internal_api_server/vllm/chunk_statistics_api.py +141 -0
  218. lmcache/v1/internal_api_server/vllm/conf_api.py +147 -0
  219. lmcache/v1/internal_api_server/vllm/freeze_api.py +172 -0
  220. lmcache/v1/internal_api_server/vllm/hot_cache_api.py +184 -0
  221. lmcache/v1/internal_api_server/vllm/inference_api.py +65 -0
  222. lmcache/v1/internal_api_server/vllm/load_fs_chunks_api.py +320 -0
  223. lmcache/v1/internal_api_server/vllm/lookup_api.py +145 -0
  224. lmcache/v1/internal_api_server/vllm/version_api.py +25 -0
  225. lmcache/v1/kv_layer_groups.py +267 -0
  226. lmcache/v1/lazy_memory_allocator.py +284 -0
  227. lmcache/v1/lookup_client/__init__.py +25 -0
  228. lmcache/v1/lookup_client/abstract_client.py +77 -0
  229. lmcache/v1/lookup_client/async_lookup_message.py +50 -0
  230. lmcache/v1/lookup_client/chunk_statistics_lookup_client.py +200 -0
  231. lmcache/v1/lookup_client/factory.py +251 -0
  232. lmcache/v1/lookup_client/hit_limit_lookup_client.py +86 -0
  233. lmcache/v1/lookup_client/lmcache_async_lookup_client.py +407 -0
  234. lmcache/v1/lookup_client/lmcache_lookup_client.py +285 -0
  235. lmcache/v1/lookup_client/lmcache_lookup_client_bypass.py +99 -0
  236. lmcache/v1/lookup_client/mooncake_lookup_client.py +87 -0
  237. lmcache/v1/lookup_client/record_strategies/__init__.py +77 -0
  238. lmcache/v1/lookup_client/record_strategies/base.py +327 -0
  239. lmcache/v1/lookup_client/record_strategies/file_hash.py +130 -0
  240. lmcache/v1/lookup_client/record_strategies/memory_bloom_filter.py +81 -0
  241. lmcache/v1/manager.py +539 -0
  242. lmcache/v1/memory_management.py +2619 -0
  243. lmcache/v1/metadata.py +114 -0
  244. lmcache/v1/mp_observability/AGENTS.override.md +21 -0
  245. lmcache/v1/mp_observability/README.md +204 -0
  246. lmcache/v1/mp_observability/config.py +340 -0
  247. lmcache/v1/mp_observability/event.py +100 -0
  248. lmcache/v1/mp_observability/event_bus.py +313 -0
  249. lmcache/v1/mp_observability/otel_init.py +145 -0
  250. lmcache/v1/mp_observability/subscribers/__init__.py +28 -0
  251. lmcache/v1/mp_observability/subscribers/logging/__init__.py +19 -0
  252. lmcache/v1/mp_observability/subscribers/logging/l1.py +56 -0
  253. lmcache/v1/mp_observability/subscribers/logging/l2.py +73 -0
  254. lmcache/v1/mp_observability/subscribers/logging/lookup_hash.py +209 -0
  255. lmcache/v1/mp_observability/subscribers/logging/mp_server.py +90 -0
  256. lmcache/v1/mp_observability/subscribers/logging/sm.py +59 -0
  257. lmcache/v1/mp_observability/subscribers/metrics/__init__.py +20 -0
  258. lmcache/v1/mp_observability/subscribers/metrics/l0_lifecycle.py +290 -0
  259. lmcache/v1/mp_observability/subscribers/metrics/l1.py +55 -0
  260. lmcache/v1/mp_observability/subscribers/metrics/l1_lifecycle.py +166 -0
  261. lmcache/v1/mp_observability/subscribers/metrics/l2.py +121 -0
  262. lmcache/v1/mp_observability/subscribers/metrics/sm.py +69 -0
  263. lmcache/v1/mp_observability/subscribers/tracing/__init__.py +12 -0
  264. lmcache/v1/mp_observability/subscribers/tracing/mp_server.py +333 -0
  265. lmcache/v1/mp_observability/subscribers/tracing/span_registry.py +148 -0
  266. lmcache/v1/mp_observability/trace/__init__.py +50 -0
  267. lmcache/v1/mp_observability/trace/codecs.py +255 -0
  268. lmcache/v1/mp_observability/trace/decorator.py +147 -0
  269. lmcache/v1/mp_observability/trace/format.py +132 -0
  270. lmcache/v1/mp_observability/trace/lifecycle.py +83 -0
  271. lmcache/v1/mp_observability/trace/reader.py +167 -0
  272. lmcache/v1/mp_observability/trace/recorder.py +300 -0
  273. lmcache/v1/multiprocess/__init__.py +0 -0
  274. lmcache/v1/multiprocess/affinity_pool.py +102 -0
  275. lmcache/v1/multiprocess/blend_server_v2.py +891 -0
  276. lmcache/v1/multiprocess/config.py +253 -0
  277. lmcache/v1/multiprocess/custom_types.py +281 -0
  278. lmcache/v1/multiprocess/futures.py +194 -0
  279. lmcache/v1/multiprocess/gpu_context.py +511 -0
  280. lmcache/v1/multiprocess/http_server.py +235 -0
  281. lmcache/v1/multiprocess/mp_runtime_plugin_launcher.py +130 -0
  282. lmcache/v1/multiprocess/mq.py +732 -0
  283. lmcache/v1/multiprocess/protocol.py +86 -0
  284. lmcache/v1/multiprocess/protocols/README.md +213 -0
  285. lmcache/v1/multiprocess/protocols/__init__.py +127 -0
  286. lmcache/v1/multiprocess/protocols/base.py +89 -0
  287. lmcache/v1/multiprocess/protocols/blend.py +109 -0
  288. lmcache/v1/multiprocess/protocols/blend_v2.py +57 -0
  289. lmcache/v1/multiprocess/protocols/controller.py +53 -0
  290. lmcache/v1/multiprocess/protocols/debug.py +34 -0
  291. lmcache/v1/multiprocess/protocols/engine.py +146 -0
  292. lmcache/v1/multiprocess/protocols/observability.py +39 -0
  293. lmcache/v1/multiprocess/server.py +1134 -0
  294. lmcache/v1/multiprocess/session.py +190 -0
  295. lmcache/v1/multiprocess/token_hasher.py +441 -0
  296. lmcache/v1/offload_server/__init__.py +17 -0
  297. lmcache/v1/offload_server/abstract_server.py +37 -0
  298. lmcache/v1/offload_server/message.py +30 -0
  299. lmcache/v1/offload_server/zmq_server.py +122 -0
  300. lmcache/v1/periodic_thread.py +579 -0
  301. lmcache/v1/pin_monitor.py +246 -0
  302. lmcache/v1/plugin/__init__.py +0 -0
  303. lmcache/v1/plugin/runtime_plugin_launcher.py +211 -0
  304. lmcache/v1/protocol.py +317 -0
  305. lmcache/v1/rpc/__init__.py +17 -0
  306. lmcache/v1/rpc/transport.py +105 -0
  307. lmcache/v1/rpc/zmq_transport.py +213 -0
  308. lmcache/v1/rpc_utils.py +165 -0
  309. lmcache/v1/server/__init__.py +2 -0
  310. lmcache/v1/server/__main__.py +170 -0
  311. lmcache/v1/server/storage_backend/__init__.py +21 -0
  312. lmcache/v1/server/storage_backend/abstract_backend.py +80 -0
  313. lmcache/v1/server/storage_backend/local_backend.py +75 -0
  314. lmcache/v1/server/utils.py +21 -0
  315. lmcache/v1/standalone/__init__.py +1 -0
  316. lmcache/v1/standalone/__main__.py +583 -0
  317. lmcache/v1/standalone/manager.py +80 -0
  318. lmcache/v1/standalone/standalone_service_factory.py +86 -0
  319. lmcache/v1/storage_backend/__init__.py +313 -0
  320. lmcache/v1/storage_backend/abstract_backend.py +445 -0
  321. lmcache/v1/storage_backend/audit_backend.py +233 -0
  322. lmcache/v1/storage_backend/batched_message_sender.py +222 -0
  323. lmcache/v1/storage_backend/cache_policy/__init__.py +45 -0
  324. lmcache/v1/storage_backend/cache_policy/base_policy.py +87 -0
  325. lmcache/v1/storage_backend/cache_policy/fifo.py +58 -0
  326. lmcache/v1/storage_backend/cache_policy/lfu.py +105 -0
  327. lmcache/v1/storage_backend/cache_policy/lru.py +81 -0
  328. lmcache/v1/storage_backend/cache_policy/mru.py +61 -0
  329. lmcache/v1/storage_backend/connector/__init__.py +443 -0
  330. lmcache/v1/storage_backend/connector/audit_adapter.py +77 -0
  331. lmcache/v1/storage_backend/connector/audit_connector.py +320 -0
  332. lmcache/v1/storage_backend/connector/base_connector.py +379 -0
  333. lmcache/v1/storage_backend/connector/blackhole_adapter.py +21 -0
  334. lmcache/v1/storage_backend/connector/blackhole_connector.py +37 -0
  335. lmcache/v1/storage_backend/connector/eic_adapter.py +31 -0
  336. lmcache/v1/storage_backend/connector/eic_connector.py +757 -0
  337. lmcache/v1/storage_backend/connector/external_adapter.py +79 -0
  338. lmcache/v1/storage_backend/connector/fs_adapter.py +51 -0
  339. lmcache/v1/storage_backend/connector/fs_connector.py +403 -0
  340. lmcache/v1/storage_backend/connector/infinistore_adapter.py +56 -0
  341. lmcache/v1/storage_backend/connector/infinistore_connector.py +177 -0
  342. lmcache/v1/storage_backend/connector/instrumented_connector.py +219 -0
  343. lmcache/v1/storage_backend/connector/lm_adapter.py +31 -0
  344. lmcache/v1/storage_backend/connector/lm_connector.py +176 -0
  345. lmcache/v1/storage_backend/connector/mock_adapter.py +57 -0
  346. lmcache/v1/storage_backend/connector/mock_connector.py +349 -0
  347. lmcache/v1/storage_backend/connector/mooncakestore_adapter.py +43 -0
  348. lmcache/v1/storage_backend/connector/mooncakestore_connector.py +614 -0
  349. lmcache/v1/storage_backend/connector/redis_adapter.py +181 -0
  350. lmcache/v1/storage_backend/connector/redis_connector.py +828 -0
  351. lmcache/v1/storage_backend/connector/s3_adapter.py +59 -0
  352. lmcache/v1/storage_backend/connector/s3_connector.py +699 -0
  353. lmcache/v1/storage_backend/connector/sagemaker_hyperpod_adapter.py +233 -0
  354. lmcache/v1/storage_backend/connector/sagemaker_hyperpod_connector.py +987 -0
  355. lmcache/v1/storage_backend/connector/valkey_adapter.py +114 -0
  356. lmcache/v1/storage_backend/connector/valkey_connector.py +627 -0
  357. lmcache/v1/storage_backend/gds_backend.py +1199 -0
  358. lmcache/v1/storage_backend/job_executor/__init__.py +0 -0
  359. lmcache/v1/storage_backend/job_executor/base_executor.py +34 -0
  360. lmcache/v1/storage_backend/job_executor/pq_executor.py +235 -0
  361. lmcache/v1/storage_backend/local_cpu_backend.py +810 -0
  362. lmcache/v1/storage_backend/local_disk_backend.py +656 -0
  363. lmcache/v1/storage_backend/maru_backend.py +734 -0
  364. lmcache/v1/storage_backend/naive_serde/__init__.py +50 -0
  365. lmcache/v1/storage_backend/naive_serde/cachegen_basics.py +133 -0
  366. lmcache/v1/storage_backend/naive_serde/cachegen_decoder.py +135 -0
  367. lmcache/v1/storage_backend/naive_serde/cachegen_encoder.py +83 -0
  368. lmcache/v1/storage_backend/naive_serde/kivi_serde.py +22 -0
  369. lmcache/v1/storage_backend/naive_serde/naive_serde.py +18 -0
  370. lmcache/v1/storage_backend/naive_serde/serde.py +37 -0
  371. lmcache/v1/storage_backend/native_clients/connector_client_base.py +165 -0
  372. lmcache/v1/storage_backend/native_clients/resp_client.py +35 -0
  373. lmcache/v1/storage_backend/nixl_storage_backend.py +1400 -0
  374. lmcache/v1/storage_backend/p2p_backend.py +788 -0
  375. lmcache/v1/storage_backend/path_sharder.py +117 -0
  376. lmcache/v1/storage_backend/pd_backend.py +646 -0
  377. lmcache/v1/storage_backend/plugins/dax_backend.py +1443 -0
  378. lmcache/v1/storage_backend/plugins/rust_raw_block_backend.py +1361 -0
  379. lmcache/v1/storage_backend/remote_backend.py +624 -0
  380. lmcache/v1/storage_backend/resp_client.py +227 -0
  381. lmcache/v1/storage_backend/storage_backend_listener.py +19 -0
  382. lmcache/v1/storage_backend/storage_manager.py +1352 -0
  383. lmcache/v1/system_detection.py +110 -0
  384. lmcache/v1/token_database.py +551 -0
  385. lmcache/v1/transfer_channel/__init__.py +83 -0
  386. lmcache/v1/transfer_channel/abstract.py +285 -0
  387. lmcache/v1/transfer_channel/mock_memory_channel.py +156 -0
  388. lmcache/v1/transfer_channel/nixl_channel.py +639 -0
  389. lmcache/v1/transfer_channel/py_socket_channel.py +260 -0
  390. lmcache/v1/transfer_channel/transfer_utils.py +63 -0
  391. lmcache/v1/utils/__init__.py +1 -0
  392. lmcache/v1/utils/bloom_filter.py +109 -0
  393. lmcache/v1/utils/cache_utils.py +125 -0
  394. lmcache_cli-0.4.5.dev0.dist-info/METADATA +185 -0
  395. lmcache_cli-0.4.5.dev0.dist-info/RECORD +399 -0
  396. lmcache_cli-0.4.5.dev0.dist-info/WHEEL +5 -0
  397. lmcache_cli-0.4.5.dev0.dist-info/entry_points.txt +2 -0
  398. lmcache_cli-0.4.5.dev0.dist-info/licenses/LICENSE +201 -0
  399. lmcache_cli-0.4.5.dev0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,194 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ from typing import Generic, Optional, TypeVar
4
+ import threading
5
+
6
+ # Third Party
7
+ import torch
8
+
9
+ T = TypeVar("T")
10
+
11
+
12
+ class MessagingFuture(Generic[T]):
13
+ def __init__(self):
14
+ self.is_done_ = threading.Event()
15
+ self.result_ = None
16
+
17
+ def query(self) -> bool:
18
+ """
19
+ Check if the future is done.
20
+
21
+ Returns:
22
+ bool: True if the future is done, False otherwise.
23
+ """
24
+ return self.is_done_.is_set()
25
+
26
+ def wait(self, timeout: Optional[float] = None) -> bool:
27
+ """
28
+ Wait for the future to be done.
29
+
30
+ Args:
31
+ timeout (Optional[float]): Maximum time to wait in seconds.
32
+ If None, wait indefinitely.
33
+
34
+ Returns:
35
+ bool: True if the future is done, False if the timeout was reached.
36
+ """
37
+ return self.is_done_.wait(timeout)
38
+
39
+ def result(self, timeout: Optional[float] = None) -> T:
40
+ """
41
+ Get the result of the future.
42
+
43
+ Args:
44
+ timeout (Optional[float]): Maximum time to wait in seconds.
45
+ If None, wait indefinitely.
46
+
47
+ Returns:
48
+ T: The result of the future.
49
+
50
+ Raises:
51
+ TimeoutError: If the future is not done within the timeout.
52
+ """
53
+ flag = self.wait(timeout)
54
+ if not flag:
55
+ raise TimeoutError("Future result not available within timeout")
56
+ return self.result_
57
+
58
+ def set_result(self, result: T) -> None:
59
+ """
60
+ Set the result of the future and mark it as done. This function is NOT
61
+ SUPPOSED TO BE CALLED by users directly. It should be only called by
62
+ the messaging system when the result is available.
63
+
64
+ Args:
65
+ result (T): The result to set.
66
+ """
67
+ self.result_ = result
68
+ self.is_done_.set()
69
+
70
+ def to_cuda_future(
71
+ self,
72
+ device: torch.cuda.device | None = None,
73
+ ) -> "CUDAMessagingFuture":
74
+ # TODO: need extra type checking for the future type
75
+ return CUDAMessagingFuture.FromMessagingFuture(self, device) # type: ignore
76
+
77
+
78
+ class CUDAMessagingFuture(MessagingFuture[T]):
79
+ """
80
+ The future class that wraps both result and a CUDA IPC event.
81
+ The `query`, `wait`, and `result` methods will pend on both the
82
+ original future and the CUDA event.
83
+ The original future should return tuple[bytes, T], where the first
84
+ element is the serialized CUDA event.
85
+ """
86
+
87
+ def __init__(
88
+ self,
89
+ raw_future: MessagingFuture[tuple[bytes, T]],
90
+ device: torch.cuda.device | None = None,
91
+ ) -> None:
92
+ super().__init__()
93
+ self.raw_future_ = raw_future
94
+ self.event_: torch.cuda.Event | None = None
95
+ self.result_: T | None = None
96
+ self.device_ = device if device is not None else torch.cuda.current_device()
97
+
98
+ def _on_raw_future_complete(self):
99
+ """
100
+ Update the CUDA event and result when the raw future is complete.
101
+ """
102
+ event_bytes, result = self.raw_future_.result()
103
+ self.result_ = result
104
+
105
+ # Deserialize the CUDA event
106
+ self.event_ = torch.cuda.Event.from_ipc_handle(self.device_, event_bytes)
107
+
108
+ def wait(self, timeout: Optional[float] = None) -> bool:
109
+ """
110
+ Wait for the future to be done, with the CUDA stream.
111
+
112
+ Args:
113
+ timeout (Optional[float]): Maximum time to wait for the UNDERLYING
114
+ RAW FUTURE in seconds. The exact timeout is not guaranteed
115
+ when waiting on the CUDA event. (NOTE: this could be improved
116
+ with careful threading management)
117
+
118
+ Returns:
119
+ bool: True if the future is done, False if the timeout was reached.
120
+
121
+ Raises:
122
+ ValueError: if the timeout is not None.
123
+
124
+ Notes:
125
+ This function does not support waiting for a specific time.
126
+ """
127
+ if self.event_:
128
+ self.event_.synchronize()
129
+ return True
130
+
131
+ flag = self.raw_future_.wait(timeout)
132
+ if not flag:
133
+ return False
134
+
135
+ self._on_raw_future_complete()
136
+
137
+ assert self.event_ is not None
138
+ self.event_.synchronize()
139
+
140
+ return True
141
+
142
+ def result(self, timeout: Optional[float] = None) -> T:
143
+ """
144
+ Get the result of the future.
145
+
146
+ Args:
147
+ timeout (Optional[float]): Maximum time to wait for the UNDERLYING
148
+ RAW FUTURE in seconds. The exact timeout is not guaranteed
149
+ when waiting on the CUDA event. (NOTE: this could be improved
150
+ with careful threading management)
151
+
152
+ Returns:
153
+ T: The result of the future.
154
+
155
+ Raises:
156
+ TimeoutError: If the future is not done within the timeout.
157
+ """
158
+ flag = self.wait(timeout)
159
+ if not flag:
160
+ raise TimeoutError(
161
+ "CUDAMessagingFuture result not available within timeout"
162
+ )
163
+
164
+ assert self.result_ is not None
165
+ return self.result_
166
+
167
+ def query(self) -> bool:
168
+ """
169
+ Check if the future is done.
170
+
171
+ Returns:
172
+ bool: True if the future is done, False otherwise.
173
+ """
174
+ if self.event_:
175
+ return self.event_.query()
176
+
177
+ if self.raw_future_.query():
178
+ self._on_raw_future_complete()
179
+ assert self.event_ is not None
180
+ return self.event_.query()
181
+
182
+ return False
183
+
184
+ def set_result(self, result: T) -> None:
185
+ raise NotImplementedError(
186
+ "CUDAMessagingFuture does not support set_result directly"
187
+ )
188
+
189
+ @staticmethod
190
+ def FromMessagingFuture(
191
+ raw_future: MessagingFuture[tuple[bytes, T]],
192
+ device: torch.cuda.device | None = None,
193
+ ) -> "CUDAMessagingFuture[T]":
194
+ return CUDAMessagingFuture(raw_future, device)
@@ -0,0 +1,511 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """
3
+ GPU Cache Context management for LMCache multiprocessing.
4
+
5
+ This module provides GPU-side KV cache management functionality, including:
6
+ - GPUCacheContext: Manages shape and pointers to vLLM GPU KV cache tensors
7
+ - Helper functions for tensor operations and key resolution
8
+ """
9
+
10
+ # Standard
11
+ import array
12
+
13
+ # Third Party
14
+ import cupy
15
+ import torch
16
+
17
+ # First Party
18
+ from lmcache.logging import init_logger
19
+ from lmcache.utils import EngineType
20
+ from lmcache.v1.gpu_connector.utils import (
21
+ LayoutHints,
22
+ discover_gpu_kv_format,
23
+ get_attention_backend,
24
+ get_block_size,
25
+ get_concrete_gpu_kv_shape,
26
+ get_dtype,
27
+ get_gpu_kv_shape_description,
28
+ get_head_size,
29
+ get_hidden_dim_size,
30
+ get_num_blocks,
31
+ get_num_heads,
32
+ get_num_layers,
33
+ is_mla,
34
+ )
35
+ from lmcache.v1.kv_layer_groups import KVLayerGroupsManager
36
+
37
+ if torch.cuda.is_available():
38
+ import lmcache.c_ops as lmc_ops
39
+
40
+ # First Party
41
+ from lmcache.v1.multiprocess.custom_types import (
42
+ KVCache,
43
+ )
44
+
45
+ logger = init_logger(__name__)
46
+
47
+
48
+ def unwrap_kv_cache_tensors(kv_caches: KVCache) -> list[torch.Tensor]:
49
+ unwrapped_tensors = []
50
+ for ipc_wrapper in kv_caches:
51
+ tensor = ipc_wrapper.to_tensor()
52
+ unwrapped_tensors.append(tensor)
53
+ return unwrapped_tensors
54
+
55
+
56
+ def list_to_gpu_tensor(lis: list[int], device: torch.device) -> torch.Tensor:
57
+ return torch.frombuffer(array.array("l", lis), dtype=torch.long).to(
58
+ device, non_blocking=True
59
+ )
60
+
61
+
62
+ class GPUCacheContext:
63
+ """
64
+ Manages the shape and pointers to vLLM GPU KV cache tensors.
65
+ """
66
+
67
+ def __init__(
68
+ self,
69
+ kv_caches: KVCache,
70
+ lmcache_chunk_size: int = 256,
71
+ layout_hints: LayoutHints | None = None,
72
+ ):
73
+ self.kv_caches_ = unwrap_kv_cache_tensors(kv_caches)
74
+ self.device_ = self.kv_caches_[0].device
75
+
76
+ # Pointers
77
+ pointers_list = [t.data_ptr() for t in self.kv_caches_]
78
+ self.kv_cache_pointers_ = list_to_gpu_tensor(pointers_list, self.device_)
79
+
80
+ # TODO support creating GPUCacheContext for SGLang
81
+ self.gpu_kv_format_ = discover_gpu_kv_format(
82
+ self.kv_caches_,
83
+ EngineType.VLLM,
84
+ layout_hints=layout_hints,
85
+ )
86
+ self.is_mla_ = is_mla(self.gpu_kv_format_)
87
+ self.num_layers_ = get_num_layers(self.kv_caches_, self.gpu_kv_format_)
88
+ self.num_blocks_ = get_num_blocks(self.kv_caches_, self.gpu_kv_format_)
89
+ self.block_size_ = get_block_size(self.kv_caches_, self.gpu_kv_format_)
90
+
91
+ # Build per-layer KV groups (grouped by shape and dtype)
92
+ self.kv_layer_groups_manager_ = KVLayerGroupsManager()
93
+ self.kv_layer_groups_manager_.build_kv_layer_groups_from_list(self.kv_caches_)
94
+
95
+ # Per-group attributes: hidden_dim_size, num_heads, head_size,
96
+ # shape_desc, and kv_pointers — all derived from the representative
97
+ # first layer of each group. MLA formats have no independent num_heads
98
+ # dimension; use nh=1 so the kernel thread block has a single row.
99
+ kv_size = 1 if self.is_mla_ else 2
100
+ self.hidden_dim_sizes_: list[int] = []
101
+ self.group_num_heads_: list[int] = []
102
+ self.group_head_sizes_: list[int] = []
103
+ self.shape_descs_: list[lmc_ops.PageBufferShapeDesc] = []
104
+ self.group_kv_pointers_: list[torch.Tensor] = []
105
+ for group in self.kv_layer_groups_manager_.kv_layer_groups:
106
+ rep = [self.kv_caches_[group.layer_indices[0]]]
107
+ hidden_dim = get_hidden_dim_size(rep, self.gpu_kv_format_)
108
+ nh = 1 if self.is_mla_ else get_num_heads(rep, self.gpu_kv_format_)
109
+ hs = get_head_size(rep, self.gpu_kv_format_)
110
+
111
+ self.hidden_dim_sizes_.append(hidden_dim)
112
+ self.group_num_heads_.append(nh)
113
+ self.group_head_sizes_.append(hs)
114
+
115
+ sd = lmc_ops.PageBufferShapeDesc()
116
+ sd.kv_size = kv_size
117
+ sd.nl = group.num_layers
118
+ sd.nb = self.num_blocks_
119
+ sd.bs = self.block_size_
120
+ sd.nh = nh
121
+ sd.hs = hs
122
+ sd.element_size = rep[0].element_size()
123
+ self.shape_descs_.append(sd)
124
+
125
+ self.group_kv_pointers_.append(
126
+ list_to_gpu_tensor(
127
+ [self.kv_caches_[i].data_ptr() for i in group.layer_indices],
128
+ self.device_,
129
+ )
130
+ )
131
+
132
+ # Pre-allocated GPU buffer for block IDs (up to 1M elements).
133
+ # The caller copies block_ids into this buffer before launching the
134
+ # block-level kernel. Single-thread assumption: no lock needed.
135
+ _MAX_BLOCK_IDS = 1_000_000
136
+ self.block_ids_buffer_ = torch.empty(
137
+ _MAX_BLOCK_IDS, dtype=torch.long, device=self.device_
138
+ )
139
+
140
+ # Temporary GPU buffer for transfers — a single flat uint8 buffer
141
+ # laid out in chunk-major order so that each chunk's data matches
142
+ # the layout of a MemoryObj.raw_data (all groups concatenated):
143
+ #
144
+ # [ chunk_0: group_0_bytes | group_1_bytes | ... ]
145
+ # [ chunk_1: group_0_bytes | group_1_bytes | ... ]
146
+ # ...
147
+ #
148
+ # This lets callers copy an entire chunk to/from a MemoryObj with a
149
+ # single memcpy, without needing to know the per-group layout.
150
+ # max_batch_size is the max number of chunks processed concurrently.
151
+ self.max_batch_size = 4
152
+ self.lmcache_chunk_size = lmcache_chunk_size
153
+ # Byte size of one chunk entry (= one chunk across all groups).
154
+ # tmp_chunk_group_offsets_[g] is the byte offset of group g within
155
+ # a single chunk; tmp_chunk_group_offsets_[num_groups] ==
156
+ # tmp_chunk_bytes_.
157
+ self.tmp_chunk_group_offsets_: list[int] = [0]
158
+ for group_idx, group in enumerate(
159
+ self.kv_layer_groups_manager_.kv_layer_groups
160
+ ):
161
+ shape = self.get_kv_buffer_shape(lmcache_chunk_size, group_idx)
162
+ byte_size = shape.numel() * group.dtype.itemsize
163
+ self.tmp_chunk_group_offsets_.append(
164
+ self.tmp_chunk_group_offsets_[-1] + byte_size
165
+ )
166
+ self.tmp_chunk_bytes_ = self.tmp_chunk_group_offsets_[-1]
167
+ self.tmp_gpu_buffer_ = torch.empty(
168
+ self.tmp_chunk_bytes_ * self.max_batch_size,
169
+ dtype=torch.uint8,
170
+ device=self.device_,
171
+ )
172
+
173
+ # Cuda streams
174
+ self.cuda_stream_ = torch.cuda.Stream(device=self.device_)
175
+ self.cupy_stream_ = cupy.cuda.ExternalStream(
176
+ self.cuda_stream_.cuda_stream, self.device_.index
177
+ )
178
+
179
+ _, high_priority = torch.cuda.Stream.priority_range()
180
+ self.high_priority_cuda_stream_ = torch.cuda.Stream(
181
+ device=self.device_, priority=high_priority
182
+ )
183
+ self.high_priority_cupy_stream_ = cupy.cuda.ExternalStream(
184
+ self.high_priority_cuda_stream_.cuda_stream, self.device_.index
185
+ )
186
+
187
+ # Extra initialization
188
+ self.cupy_stream_.launch_host_func(
189
+ lambda logger: logger.info(
190
+ "Initialized cuda stream on device %s", str(self.device_)
191
+ ),
192
+ logger,
193
+ )
194
+
195
+ @property
196
+ def dtype(self) -> torch.dtype:
197
+ return get_dtype(self.kv_caches_, self.gpu_kv_format_)
198
+
199
+ @property
200
+ def device(self) -> torch.device:
201
+ return self.device_
202
+
203
+ @property
204
+ def kv_tensors(self) -> list[torch.Tensor]:
205
+ return self.kv_caches_
206
+
207
+ @property
208
+ def kv_pointers(self) -> torch.Tensor:
209
+ """
210
+ Returns a GPU tensor of the KV cache pointers
211
+ """
212
+ return self.kv_cache_pointers_
213
+
214
+ @property
215
+ def stream(self) -> torch.cuda.Stream:
216
+ """
217
+ Returns the CUDA stream for KV cache operations
218
+ """
219
+ return self.cuda_stream_
220
+
221
+ @property
222
+ def cupy_stream(self) -> cupy.cuda.Stream:
223
+ return self.cupy_stream_
224
+
225
+ @property
226
+ def high_priority_stream(self) -> torch.cuda.Stream:
227
+ return self.high_priority_cuda_stream_
228
+
229
+ @property
230
+ def high_priority_cupy_stream(self) -> cupy.cuda.Stream:
231
+ return self.high_priority_cupy_stream_
232
+
233
+ @property
234
+ def block_size(self) -> int:
235
+ """
236
+ Returns the block size (number of tokens per block)
237
+ """
238
+ return self.block_size_
239
+
240
+ @property
241
+ def num_layers(self) -> int:
242
+ """
243
+ Returns the number of layers in the model
244
+ """
245
+ return self.num_layers_
246
+
247
+ @property
248
+ def num_blocks(self) -> int:
249
+ """
250
+ Returns the number of blocks in the KV cache
251
+ """
252
+ return self.num_blocks_
253
+
254
+ @property
255
+ def is_mla(self) -> bool:
256
+ """
257
+ Returns whether the model uses MLA
258
+ """
259
+ return self.is_mla_
260
+
261
+ @property
262
+ def hidden_dim_sizes(self) -> list[int]:
263
+ """Returns the hidden dimension sizes for each KV layer group."""
264
+ return self.hidden_dim_sizes_
265
+
266
+ def get_shape_desc(self, group_idx: int) -> "lmc_ops.PageBufferShapeDesc":
267
+ """Returns the PageBufferShapeDesc for the given KV layer group."""
268
+ return self.shape_descs_[group_idx]
269
+
270
+ @property
271
+ def kv_layer_groups_manager(self) -> KVLayerGroupsManager:
272
+ """Returns the KV layer groups manager."""
273
+ return self.kv_layer_groups_manager_
274
+
275
+ def gpu_kv_format_name(self) -> str:
276
+ """Returns the GPU KV format enum name (e.g. ``'NL_X_TWO_NB_BS_NH_HS'``)."""
277
+ return self.gpu_kv_format_.name
278
+
279
+ @property
280
+ def gpu_kv_shape(self) -> str:
281
+ """Returns a human-readable shape description of the GPU KV cache layout."""
282
+ return get_gpu_kv_shape_description(self.gpu_kv_format_)
283
+
284
+ @property
285
+ def attention_backend(self) -> str:
286
+ """Returns the attention backend name."""
287
+ return get_attention_backend(self.gpu_kv_format_)
288
+
289
+ @property
290
+ def concrete_gpu_kv_shape(self) -> str:
291
+ """Returns the GPU KV shape with actual numeric values substituted."""
292
+ return get_concrete_gpu_kv_shape(self.kv_caches_, self.gpu_kv_format_)
293
+
294
+ def get_group_kv_pointers(self, group_idx: int) -> torch.Tensor:
295
+ """Returns the pre-computed GPU tensor of KV cache pointers for the
296
+ given group."""
297
+ return self.group_kv_pointers_[group_idx]
298
+
299
+ def get_tmp_gpu_buffer_flat(self, chunk_idx: int) -> torch.Tensor:
300
+ """Returns the flat uint8 view of the temporary GPU buffer for the
301
+ given chunk index, covering all KV layer groups.
302
+
303
+ The returned tensor will fit a memory full object corresponding
304
+ ``self.chunk_size`` tokens, so it can be copied to/from a MemoryObj
305
+ with a single memcpy.
306
+
307
+ Args:
308
+ chunk_idx: Chunk index (0 <= chunk_idx < max_batch_size).
309
+ """
310
+ if chunk_idx >= self.max_batch_size:
311
+ raise ValueError(
312
+ f"chunk_idx {chunk_idx} exceeds max_batch_size {self.max_batch_size}"
313
+ )
314
+ start = chunk_idx * self.tmp_chunk_bytes_
315
+ return self.tmp_gpu_buffer_[start : start + self.tmp_chunk_bytes_]
316
+
317
+ def get_tmp_chunk_gpu_buffer(self, group_idx: int = 0) -> torch.Tensor:
318
+ """
319
+ Returns a view of the temporary GPU buffer for the given group,
320
+ sized for a single chunk of ``lmcache_chunk_size`` tokens.
321
+
322
+ Args:
323
+ group_idx: Index of the KV layer group (default 0).
324
+ """
325
+ group = self.kv_layer_groups_manager_.kv_layer_groups[group_idx]
326
+ shape = self.get_kv_buffer_shape(self.lmcache_chunk_size, group_idx)
327
+ start = self.tmp_chunk_group_offsets_[group_idx]
328
+ end = self.tmp_chunk_group_offsets_[group_idx + 1]
329
+ return self.tmp_gpu_buffer_[start:end].view(group.dtype).view(shape)
330
+
331
+ def get_tmp_chunk_gpu_buffer_batched(
332
+ self, batch_size: int, group_idx: int = 0
333
+ ) -> list[torch.Tensor]:
334
+ """
335
+ Returns a list of ``batch_size`` non-overlapping views into the
336
+ pre-allocated temporary GPU buffer for the given group, each
337
+ sized for ``lmcache_chunk_size`` tokens.
338
+
339
+ Args:
340
+ batch_size: Number of concurrent requests (must be <= max_batch_size).
341
+ group_idx: Index of the KV layer group (default 0).
342
+ """
343
+ if batch_size > self.max_batch_size:
344
+ raise ValueError(
345
+ f"batch_size {batch_size} exceeds max_batch_size {self.max_batch_size}"
346
+ )
347
+ group = self.kv_layer_groups_manager_.kv_layer_groups[group_idx]
348
+ shape = self.get_kv_buffer_shape(self.lmcache_chunk_size, group_idx)
349
+ g_start = self.tmp_chunk_group_offsets_[group_idx]
350
+ g_end = self.tmp_chunk_group_offsets_[group_idx + 1]
351
+ chunk = self.tmp_chunk_bytes_
352
+ return [
353
+ self.tmp_gpu_buffer_[i * chunk + g_start : i * chunk + g_end]
354
+ .view(group.dtype)
355
+ .view(shape)
356
+ for i in range(batch_size)
357
+ ]
358
+
359
+ def stage_block_ids(self, block_ids: list[int]) -> torch.Tensor:
360
+ """Copy block_ids into the pre-allocated GPU buffer and return a
361
+ view of the occupied region. Uses non-blocking copy via a pinned
362
+ CPU tensor created from the list's underlying buffer.
363
+
364
+ Args:
365
+ block_ids: Block indices as a Python list of ints.
366
+
367
+ Returns:
368
+ A GPU int64 tensor view into the pre-allocated buffer.
369
+ """
370
+ n = len(block_ids)
371
+ cpu_tensor = torch.frombuffer(array.array("l", block_ids), dtype=torch.long)
372
+ buf = self.block_ids_buffer_[:n]
373
+ buf.copy_(cpu_tensor, non_blocking=True)
374
+ return buf
375
+
376
+ def get_kv_buffer_shape(self, num_tokens: int, group_idx: int = 0) -> torch.Size:
377
+ """
378
+ Returns the shape of the KV buffer for the given number of tokens.
379
+
380
+ Args:
381
+ num_tokens: Number of tokens.
382
+ group_idx: Index of the KV layer group (default 0).
383
+ """
384
+ group = self.kv_layer_groups_manager_.kv_layer_groups[group_idx]
385
+ num_layers_in_group = group.num_layers
386
+ hidden_dim = self.hidden_dim_sizes[group_idx]
387
+ if self.is_mla_:
388
+ return torch.Size((1, num_layers_in_group, num_tokens, hidden_dim))
389
+ else:
390
+ return torch.Size((2, num_layers_in_group, num_tokens, hidden_dim))
391
+
392
+ def cache_size_per_token(self) -> int:
393
+ """
394
+ Returns the cache size per token (in bytes), summed across all groups.
395
+ """
396
+ total = 0
397
+ for group_idx, group in enumerate(
398
+ self.kv_layer_groups_manager_.kv_layer_groups
399
+ ):
400
+ numels = self.get_kv_buffer_shape(1, group_idx).numel()
401
+ total += numels * group.dtype.itemsize
402
+ return total
403
+
404
+
405
+ class PlainGPUCacheContext:
406
+ """
407
+ A plain GPU cache context that have a single contiguous 2LTD buffer
408
+ """
409
+
410
+ def __init__(self, kv_caches: KVCache, lmcache_chunk_size: int = 256):
411
+ assert len(kv_caches) == 1, (
412
+ "PlainGPUCacheContext only supports a single KV cache tensor"
413
+ )
414
+
415
+ # KV cache basics
416
+ self._kv_cache = unwrap_kv_cache_tensors(kv_caches)[0]
417
+ self._device = self._kv_cache.device
418
+
419
+ # Shape related
420
+ shape = self._kv_cache.shape
421
+ assert len(shape) == 4, "Expected [2, L, T, D] for plain GPU cache"
422
+
423
+ self._num_layers = shape[1]
424
+ self._num_tokens = shape[2]
425
+ self._hidden_dim_size = shape[3]
426
+
427
+ # Temporary buffer
428
+ tmp_buffer_shape = self.get_kv_buffer_shape(lmcache_chunk_size)
429
+ self._tmp_gpu_buffer = torch.empty(
430
+ tmp_buffer_shape, dtype=self.dtype, device=self.device
431
+ )
432
+
433
+ # Cuda streams
434
+ self._cuda_stream = torch.cuda.Stream(device=self._device)
435
+ self._cupy_stream = cupy.cuda.ExternalStream(
436
+ self._cuda_stream.cuda_stream, self._device.index
437
+ )
438
+
439
+ _, high_priority = torch.cuda.Stream.priority_range()
440
+ self._high_priority_cuda_stream = torch.cuda.Stream(
441
+ device=self._device, priority=high_priority
442
+ )
443
+ self._high_priority_cupy_stream = cupy.cuda.ExternalStream(
444
+ self._high_priority_cuda_stream.cuda_stream, self._device.index
445
+ )
446
+
447
+ # Extra initialization
448
+ self._cupy_stream.launch_host_func(
449
+ lambda logger: logger.info(
450
+ "Initialized cuda stream on device %s", str(self._device)
451
+ ),
452
+ logger,
453
+ )
454
+
455
+ def get_kv_buffer_shape(self, num_tokens: int) -> torch.Size:
456
+ """
457
+ Returns the shape of the KV buffer for the given number of tokens
458
+ """
459
+ return torch.Size((2, self._num_layers, num_tokens, self._hidden_dim_size))
460
+
461
+ def get_tmp_gpu_buffer(self, num_tokens: int) -> torch.Tensor:
462
+ """
463
+ Returns the temporary GPU buffer for transfers
464
+ """
465
+ return self._tmp_gpu_buffer[:, :, :num_tokens, :]
466
+
467
+ def slice_kv_cache_on_tokens(self, start: int, end: int) -> torch.Tensor:
468
+ """
469
+ Slices the KV cache tensor on the token dimension
470
+ """
471
+ return self._kv_cache[:, :, start:end, :]
472
+
473
+ @property
474
+ def dtype(self) -> torch.dtype:
475
+ return self._kv_cache.dtype
476
+
477
+ @property
478
+ def device(self) -> torch.device:
479
+ return self._device
480
+
481
+ @property
482
+ def stream(self) -> torch.cuda.Stream:
483
+ return self._cuda_stream
484
+
485
+ @property
486
+ def cupy_stream(self) -> cupy.cuda.Stream:
487
+ return self._cupy_stream
488
+
489
+ @property
490
+ def high_priority_stream(self) -> torch.cuda.Stream:
491
+ return self._high_priority_cuda_stream
492
+
493
+ @property
494
+ def high_priority_cupy_stream(self) -> cupy.cuda.Stream:
495
+ return self._high_priority_cupy_stream
496
+
497
+ @property
498
+ def num_layers(self) -> int:
499
+ return self._num_layers
500
+
501
+ @property
502
+ def num_tokens(self) -> int:
503
+ return self._num_tokens
504
+
505
+ @property
506
+ def hidden_dim_size(self) -> int:
507
+ return self._hidden_dim_size
508
+
509
+ @property
510
+ def kv_cache_tensor(self) -> torch.Tensor:
511
+ return self._kv_cache