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,129 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ from typing import TYPE_CHECKING
4
+
5
+ # Third Party
6
+ from vllm.attention import Attention
7
+ from vllm.v1.attention.backends.flash_attn import FlashAttentionImpl
8
+ from vllm.vllm_flash_attn import flash_attn_varlen_func, get_scheduler_metadata
9
+ import torch
10
+
11
+ # First Party
12
+ from lmcache.v1.compute.attention.abstract import AttentionInterface
13
+ from lmcache.v1.compute.attention.metadata import LMCFlashAttnMetadata
14
+
15
+ if TYPE_CHECKING:
16
+ # First Party
17
+ from lmcache.v1.compute.attention.metadata import LMCAttnMetadata
18
+
19
+
20
+ class LMCFlashAttnBackend(AttentionInterface):
21
+ """
22
+ FlashAttention backend for LMCache.
23
+ This backend uses the FlashAttention implementation
24
+ for efficient attention computation.
25
+ """
26
+
27
+ def __init__(
28
+ self,
29
+ vllm_attn: Attention,
30
+ ):
31
+ self.vllm_attn = vllm_attn
32
+ self.vllm_attn_impl: FlashAttentionImpl = vllm_attn.impl
33
+
34
+ # TODO(Jiayi): remove this hardcode
35
+ self.aot_schedule = False
36
+
37
+ idx = torch.cuda.current_device()
38
+ self.device = torch.device(f"cuda:{idx}")
39
+
40
+ def forward_contiguous(
41
+ self,
42
+ query: torch.Tensor,
43
+ key: torch.Tensor,
44
+ value: torch.Tensor,
45
+ output: torch.Tensor,
46
+ attn_metadata: "LMCAttnMetadata",
47
+ **kwargs,
48
+ ) -> torch.Tensor:
49
+ assert isinstance(attn_metadata, LMCFlashAttnMetadata)
50
+
51
+ cu_seqlens_q = attn_metadata.query_start_loc
52
+ seqused_k = attn_metadata.seq_lens
53
+ cu_seqlens_k = attn_metadata.cu_seqlens_k
54
+ max_seqlen_q = attn_metadata.max_query_len
55
+ max_seqlen_k = attn_metadata.max_seq_len
56
+
57
+ descale_shape = (cu_seqlens_q.shape[0] - 1, key.shape[1])
58
+
59
+ # TODO(Jiayi): Figure out how to use aot_schedule.
60
+ scheduler_metadata = self._schedule(
61
+ batch_size=1, # NOTE(Jiayi): Assuming batch size is 1,
62
+ # since we are processing request by request.
63
+ cu_query_lens=cu_seqlens_q,
64
+ max_query_len=max_seqlen_q,
65
+ seqlens=seqused_k,
66
+ max_seq_len=max_seqlen_k,
67
+ causal=True, # Assuming causal attention
68
+ )
69
+
70
+ flash_attn_varlen_func(
71
+ q=query, # contiguous
72
+ k=key, # contiguous
73
+ v=value, # contiguous
74
+ out=output,
75
+ cu_seqlens_q=cu_seqlens_q,
76
+ max_seqlen_q=max_seqlen_q,
77
+ cu_seqlens_k=cu_seqlens_k,
78
+ # seqused_k=seqused_k,
79
+ max_seqlen_k=max_seqlen_k,
80
+ softmax_scale=self.vllm_attn_impl.scale,
81
+ causal=True,
82
+ alibi_slopes=self.vllm_attn_impl.alibi_slopes,
83
+ window_size=self.vllm_attn_impl.sliding_window,
84
+ block_table=None,
85
+ softcap=self.vllm_attn_impl.logits_soft_cap,
86
+ scheduler_metadata=scheduler_metadata,
87
+ fa_version=self.vllm_attn_impl.vllm_flash_attn_version,
88
+ q_descale=self.vllm_attn._q_scale.expand(descale_shape),
89
+ k_descale=self.vllm_attn._k_scale.expand(descale_shape),
90
+ v_descale=self.vllm_attn._v_scale.expand(descale_shape),
91
+ )
92
+
93
+ return output
94
+
95
+ def _schedule(
96
+ self, batch_size, cu_query_lens, max_query_len, seqlens, max_seq_len, causal
97
+ ):
98
+ if self.aot_schedule:
99
+ return get_scheduler_metadata(
100
+ batch_size=batch_size,
101
+ max_seqlen_q=max_query_len,
102
+ max_seqlen_k=max_seq_len,
103
+ cache_seqlens=seqlens,
104
+ num_heads_q=self.vllm_attn_impl.num_heads_q,
105
+ num_heads_kv=self.vllm_attn_impl.num_heads_kv,
106
+ headdim=self.vllm_attn_impl.headdim,
107
+ page_size=self.vllm_attn_impl.block_size,
108
+ cu_seqlens_q=cu_query_lens,
109
+ causal=causal,
110
+ window_size=self.vllm_attn_impl.aot_sliding_window,
111
+ )
112
+ return None
113
+
114
+ def init_attn_metadata(
115
+ self,
116
+ input_ids: torch.tensor,
117
+ **kwargs,
118
+ ) -> LMCFlashAttnMetadata:
119
+ seq_len = input_ids.shape[0]
120
+ device = input_ids.device
121
+ return LMCFlashAttnMetadata(
122
+ query_start_loc=torch.tensor(
123
+ [0, seq_len], dtype=torch.int32, device=device
124
+ ),
125
+ seq_lens=torch.tensor([seq_len], device=device),
126
+ cu_seqlens_k=torch.tensor([0, seq_len], dtype=torch.int32, device=device),
127
+ max_query_len=seq_len,
128
+ max_seq_len=seq_len,
129
+ )
@@ -0,0 +1,284 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ from typing import TYPE_CHECKING, Optional, Tuple, Union
4
+ import math
5
+
6
+ # Third Party
7
+ from flashinfer import VariableBlockSparseAttentionWrapper
8
+ from flashinfer.page import block_sparse_indices_to_vector_sparse_offsets
9
+ from flashinfer.utils import (
10
+ TensorLayout,
11
+ _check_pos_encoding_mode,
12
+ check_shape_dtype_device,
13
+ device_support_pdl,
14
+ )
15
+ from vllm.attention import Attention
16
+ from vllm.v1.attention.backends.flashinfer import FlashInferImpl
17
+ import flashinfer
18
+ import torch
19
+
20
+ # First Party
21
+ from lmcache.v1.compute.attention.abstract import AttentionInterface
22
+ from lmcache.v1.compute.attention.metadata import LMCFlashInferSparseMetadata
23
+
24
+ if TYPE_CHECKING:
25
+ # First Party
26
+ from lmcache.v1.compute.attention.metadata import LMCAttnMetadata
27
+
28
+
29
+ # NOTE(Jiayi): This flashinfer version is 0.3.1.
30
+ class HackBSAWrapper(VariableBlockSparseAttentionWrapper):
31
+ def run(
32
+ self,
33
+ q: torch.Tensor,
34
+ k: torch.Tensor,
35
+ v: torch.Tensor,
36
+ out: Optional[torch.Tensor] = None,
37
+ lse: Optional[torch.Tensor] = None,
38
+ return_lse: bool = False,
39
+ enable_pdl: Optional[bool] = None,
40
+ ) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]:
41
+ """
42
+ This is adapted from https://github.com/flashinfer-ai/flashinfer/blob/cc5ab77370dd9a489357a47e34315d9a8f3ad5fb/flashinfer/sparse.py#L1073
43
+
44
+ Compute block-sparse attention between Q/K/V tensors.
45
+
46
+ Parameters
47
+ ----------
48
+ q : torch.Tensor
49
+ The query tensor with shape ``(qo_len, num_qo_heads, head_dim)``.
50
+ k : torch.Tensor
51
+ The key tensor with shape ``(kv_len, num_kv_heads, head_dim)``.
52
+ v : torch.Tensor
53
+ The value tensor with shape ``(kv_len, num_kv_heads, head_dim)``.
54
+ out : Optional[torch.Tensor]
55
+ The output tensor, if not provided, will be allocated internally.
56
+ lse : Optional[torch.Tensor]
57
+ The log-sum-exp of attention logits, if not provided, will be
58
+ allocated internally.
59
+ return_lse : bool
60
+ Whether to return the log-sum-exp of attention logits
61
+ enable_pdl : bool
62
+ Whether to enable Programmatic Dependent Launch (PDL). See https://docs.nvidia.com/cuda/cuda-c-programming-guide/#programmatic-dependent-launch-and-synchronization
63
+ Only supported for >= sm90, and currently only for FA2 and CUDA core decode.
64
+
65
+ Returns
66
+ -------
67
+ Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]
68
+ If :attr:`return_lse` is ``False``, the attention output, shape:
69
+ ``[M, num_qo_heads, head_dim]``.
70
+ If :attr:`return_lse` is ``True``, a tuple of two tensors:
71
+
72
+ * The attention output, shape: ``[M, num_qo_heads, head_dim]``.
73
+ * The logsumexp of attention output, shape: ``[M, num_qo_heads]``.
74
+ """
75
+
76
+ if enable_pdl is None:
77
+ enable_pdl = device_support_pdl(q.device)
78
+
79
+ pos_encoding_mode = self._pos_encoding_mode
80
+ logits_soft_cap = self._logits_soft_cap
81
+ sm_scale = self._sm_scale
82
+ rope_scale = self._rope_scale
83
+ rope_theta = self._rope_theta
84
+ _check_pos_encoding_mode(pos_encoding_mode)
85
+ if logits_soft_cap is None:
86
+ logits_soft_cap = 0.0
87
+ if sm_scale is None:
88
+ sm_scale = 1.0 / math.sqrt(q.size(-1))
89
+ if rope_scale is None:
90
+ rope_scale = 1.0
91
+ if rope_theta is None:
92
+ rope_theta = 1e4
93
+
94
+ # 1 denotes page size
95
+ k = k.reshape(-1, 1, *k.shape[-2:])
96
+ v = v.reshape(-1, 1, *v.shape[-2:])
97
+
98
+ stride_block = k.stride(0)
99
+ stride_n = k.stride(1)
100
+
101
+ if return_lse:
102
+ if lse is None:
103
+ lse = torch.empty(
104
+ (q.size(0), q.size(1)), dtype=torch.float32, device=q.device
105
+ )
106
+ else:
107
+ check_shape_dtype_device(
108
+ lse, (q.size(0), q.size(1)), torch.float32, q.device, "lse"
109
+ )
110
+
111
+ if out is None:
112
+ out = torch.empty_like(q, dtype=self._o_dtype)
113
+ else:
114
+ check_shape_dtype_device(out, q.shape, self._o_dtype, q.device, "out")
115
+
116
+ if self._backend == "fa3":
117
+ if (
118
+ self._vector_sparse_indices_buffer.numel()
119
+ <= self._paged_kv_indices_buf.numel()
120
+ ):
121
+ raise ValueError(
122
+ "_vector_sparse_indices_buffer is not large enough. "
123
+ "Please increase the buffer size."
124
+ )
125
+
126
+ sparse_indices = block_sparse_indices_to_vector_sparse_offsets(
127
+ self._paged_kv_indices_buf,
128
+ self._paged_kv_indptr_buf,
129
+ self._vector_sparse_indices_buffer, # output
130
+ self._vector_sparse_indptr_buffer,
131
+ self._kv_lens_buffer,
132
+ stride_block // stride_n,
133
+ 1, # stride_n // stride_n
134
+ 1, # block_size
135
+ )
136
+ sparse_indptr = self._vector_sparse_indptr_buffer
137
+ else:
138
+ sparse_indices = self._paged_kv_indices_buf
139
+ sparse_indptr = self._paged_kv_indptr_buf
140
+
141
+ self._cached_module.paged_run(
142
+ self._float_workspace_buffer,
143
+ self._int_workspace_buffer,
144
+ self._plan_info,
145
+ q,
146
+ k,
147
+ v,
148
+ self._qo_indptr,
149
+ sparse_indptr,
150
+ sparse_indices,
151
+ self._paged_kv_last_page_len,
152
+ out,
153
+ lse,
154
+ self._mask_mode,
155
+ TensorLayout[self._kv_layout].value,
156
+ -1, # window_left
157
+ enable_pdl,
158
+ # ADDITIONAL_FUNC_PARAMS
159
+ # Not supported yet
160
+ None, # packed_mask_buf
161
+ None, # mask_indptr_buf
162
+ None, # alibi_slopes_buf
163
+ None,
164
+ None,
165
+ None,
166
+ logits_soft_cap,
167
+ sm_scale,
168
+ None, # scale_q
169
+ None, # scale_k
170
+ None, # scale_v
171
+ rope_scale,
172
+ rope_theta,
173
+ 0, # token_pos_in_items_len
174
+ )
175
+
176
+ return (out, lse) if return_lse else out
177
+
178
+
179
+ class LMCFlashInferSparseBackend(AttentionInterface):
180
+ """
181
+ FlashAttention backend for LMCache.
182
+ This backend uses the FlashAttention implementation
183
+ for efficient attention computation.
184
+ """
185
+
186
+ # Workspace buffer size in bytes (128 MiB)
187
+ _WORKSPACE_BUFFER_SIZE_BYTES = 128 * 1024 * 1024
188
+
189
+ def __init__(
190
+ self,
191
+ vllm_attn: Attention,
192
+ ):
193
+ self.vllm_attn = vllm_attn
194
+ self.vllm_attn_impl: FlashInferImpl = vllm_attn.impl
195
+
196
+ idx = torch.cuda.current_device()
197
+ self.device = torch.device(f"cuda:{idx}")
198
+
199
+ self.workspace_buffer = torch.empty(
200
+ self._WORKSPACE_BUFFER_SIZE_BYTES, dtype=torch.uint8, device=self.device
201
+ )
202
+
203
+ self.num_qo_heads = self.vllm_attn_impl.num_heads
204
+ self.num_kv_heads = self.vllm_attn_impl.num_kv_heads
205
+ self.head_dim = self.vllm_attn_impl.head_size
206
+
207
+ self.sm_scale = self.vllm_attn_impl.scale
208
+ self.window_left = self.vllm_attn_impl.window_left
209
+ self.logits_soft_cap = self.vllm_attn_impl.logits_soft_cap
210
+
211
+ self.k_scale = vllm_attn._k_scale_float
212
+ self.v_scale = vllm_attn._v_scale_float
213
+
214
+ def forward_contiguous(
215
+ self,
216
+ query: torch.Tensor,
217
+ key: torch.Tensor,
218
+ value: torch.Tensor,
219
+ output: torch.Tensor,
220
+ attn_metadata: "LMCAttnMetadata",
221
+ **kwargs,
222
+ ) -> torch.Tensor:
223
+ assert isinstance(attn_metadata, LMCFlashInferSparseMetadata)
224
+ is_causal = attn_metadata.is_causal
225
+ if is_causal:
226
+ output = flashinfer.prefill.single_prefill_with_kv_cache(
227
+ q=query,
228
+ k=key,
229
+ v=value,
230
+ scale_q=None,
231
+ scale_k=self.k_scale,
232
+ scale_v=self.v_scale,
233
+ o_dtype=query.dtype,
234
+ custom_mask=None,
235
+ packed_custom_mask=None,
236
+ causal=True,
237
+ kv_layout="NHD",
238
+ pos_encoding_mode="NONE",
239
+ use_fp16_qk_reduction=False,
240
+ sm_scale=self.sm_scale,
241
+ window_left=self.window_left,
242
+ logits_soft_cap=self.logits_soft_cap,
243
+ rope_scale=None,
244
+ rope_theta=None,
245
+ backend="auto",
246
+ return_lse=False,
247
+ )
248
+ else:
249
+ output = attn_metadata.wrapper.run(query, key, value, output)
250
+ return output
251
+
252
+ def init_attn_metadata(
253
+ self,
254
+ input_ids: torch.Tensor,
255
+ **kwargs,
256
+ ) -> LMCFlashInferSparseMetadata:
257
+ """
258
+ Initialize non-sparse attention metadata first.
259
+ """
260
+
261
+ wrapper = HackBSAWrapper(self.workspace_buffer)
262
+ seq_len = len(input_ids)
263
+
264
+ # TODO(Jiayi): remove this hardcode
265
+ sparse_blk_row_size = 32
266
+ sparse_blk_col_size = 32
267
+
268
+ num_block_col = seq_len // sparse_blk_col_size
269
+ last_col_len = seq_len % sparse_blk_col_size
270
+ block_col_sizes = torch.tensor(
271
+ [sparse_blk_col_size] * num_block_col, device=self.device
272
+ )
273
+ block_col_sizes[-1] += last_col_len
274
+ return LMCFlashInferSparseMetadata(
275
+ wrapper,
276
+ seq_len,
277
+ self.num_qo_heads,
278
+ self.num_kv_heads,
279
+ self.head_dim,
280
+ block_col_sizes,
281
+ sparse_blk_row_size,
282
+ sparse_blk_col_size,
283
+ is_causal=True,
284
+ )
@@ -0,0 +1,85 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ from abc import abstractmethod
4
+ from dataclasses import dataclass
5
+ from typing import TYPE_CHECKING
6
+ import abc
7
+
8
+ # Third Party
9
+ import torch
10
+
11
+ if TYPE_CHECKING:
12
+ # First Party
13
+ from lmcache.v1.compute.attention.flash_infer_sparse import HackBSAWrapper
14
+
15
+
16
+ @dataclass
17
+ class LMCAttnMetadata(metaclass=abc.ABCMeta):
18
+ @abstractmethod
19
+ def update_from_top_indices(self, top_indices: torch.Tensor):
20
+ raise NotImplementedError("This method should be implemented in subclasses.")
21
+
22
+
23
+ @dataclass
24
+ class LMCFlashAttnMetadata(LMCAttnMetadata):
25
+ query_start_loc: torch.Tensor
26
+ seq_lens: torch.Tensor
27
+ cu_seqlens_k: torch.Tensor
28
+ max_query_len: torch.Tensor
29
+ max_seq_len: torch.Tensor
30
+
31
+ def update_from_top_indices(self, top_indices: torch.Tensor):
32
+ top_k_num = len(top_indices)
33
+ self.max_query_len = top_k_num
34
+ device = self.query_start_loc.device
35
+ dtype = self.query_start_loc.dtype
36
+ self.query_start_loc = torch.tensor([0, top_k_num], dtype=dtype, device=device)
37
+
38
+
39
+ @dataclass
40
+ class LMCFlashInferSparseMetadata(LMCAttnMetadata):
41
+ wrapper: "HackBSAWrapper"
42
+ seq_len: int
43
+ num_qo_heads: int
44
+ num_kv_heads: int
45
+ head_dim: int
46
+ block_col_sizes: torch.Tensor
47
+ sparse_blk_row_size: int = 32 # TODO(Jiayi): make this tunable
48
+ sparse_blk_col_size: int = 32 # TODO(Jiayi): make this tunable
49
+ is_causal: bool = True
50
+ q_data_dtype: torch.dtype = torch.bfloat16 # TODO(Jiayi): remove hardcode
51
+
52
+ def update_from_top_indices(self, top_indices: torch.Tensor):
53
+ # self.is_causal = False
54
+ device = top_indices.device
55
+ top_k_num = len(top_indices)
56
+ num_block_row = top_k_num // self.sparse_blk_row_size
57
+ block_row_sizes = torch.tensor(
58
+ [self.sparse_blk_row_size] * num_block_row, device=device
59
+ )
60
+ block_row_sizes[-1] += top_k_num % self.sparse_blk_row_size
61
+
62
+ block_mask_map = torch.zeros(
63
+ num_block_row, len(self.block_col_sizes), dtype=torch.bool, device=device
64
+ )
65
+ cols = torch.arange(block_mask_map.size(1), device=device).expand(
66
+ block_mask_map.size(0), -1
67
+ )
68
+
69
+ # NOTE(Jiayi): select every `sparse_blk_row_size`-th index from top_indices
70
+ # to approximate the attention mask at block level.
71
+ top_indices_slice = top_indices[
72
+ self.sparse_blk_row_size - 1 :: self.sparse_blk_row_size
73
+ ]
74
+ top_indices_slice //= self.sparse_blk_col_size
75
+ mask = cols < top_indices_slice.unsqueeze(1)
76
+ block_mask_map[mask] = 1
77
+ self.wrapper.plan(
78
+ block_mask_map.expand(self.num_kv_heads, -1, -1),
79
+ block_row_sizes.expand(self.num_kv_heads, -1),
80
+ self.block_col_sizes.expand(self.num_kv_heads, -1),
81
+ self.num_qo_heads,
82
+ self.num_kv_heads,
83
+ self.head_dim,
84
+ q_data_type=self.q_data_dtype,
85
+ )
@@ -0,0 +1,14 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Local
3
+ from .flash_attn import LMCFlashAttnBackend
4
+ from .flash_infer_sparse import LMCFlashInferSparseBackend
5
+
6
+
7
+ def infer_attn_backend_from_vllm(vllm_attn, enable_sparse=False):
8
+ attn_name = type(vllm_attn.impl).__name__
9
+ if attn_name == "FlashInferImpl" and enable_sparse:
10
+ return LMCFlashInferSparseBackend(vllm_attn)
11
+ elif attn_name == "FlashAttentionImpl" and not enable_sparse:
12
+ return LMCFlashAttnBackend(vllm_attn)
13
+ else:
14
+ raise ValueError(f"Attention backend {attn_name} is not supported in LMCache.")
@@ -0,0 +1,7 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # First Party
3
+ from lmcache.v1.compute.blend.utils import LMCBlenderBuilder
4
+
5
+ __all__ = [
6
+ "LMCBlenderBuilder",
7
+ ]
@@ -0,0 +1,168 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ from typing import Optional, Union
4
+
5
+ # Third Party
6
+ import torch
7
+
8
+ # First Party
9
+ from lmcache.logging import init_logger
10
+ from lmcache.v1.compute.attention.metadata import LMCAttnMetadata
11
+ from lmcache.v1.compute.blend.metadata import LMCBlendCommonMetadata, LMCBlendMetadata
12
+ from lmcache.v1.compute.models.utils import infer_model_from_vllm
13
+ from lmcache.v1.config import LMCacheEngineConfig
14
+
15
+ logger = init_logger(__name__)
16
+
17
+
18
+ class LMCBlender:
19
+ """
20
+ Cache-blender backend for LMCache.
21
+ This backend uses the Blender implementation for efficient blending computation.
22
+ """
23
+
24
+ def __init__(
25
+ self,
26
+ cache_engine,
27
+ gpu_connector,
28
+ vllm_model,
29
+ config: LMCacheEngineConfig,
30
+ ):
31
+ self.cache_engine = cache_engine
32
+ self.gpu_connector = gpu_connector
33
+
34
+ enable_sparse = False
35
+ if config.extra_config is not None:
36
+ enable_sparse = config.extra_config.get("enable_sparse", False)
37
+
38
+ self.layerwise_model = infer_model_from_vllm(vllm_model, self, enable_sparse)
39
+
40
+ # TODO: remove this hardcode
41
+ self.num_layers = len(vllm_model.model.layers)
42
+
43
+ # TODO(Jiayi): support threshold-based blending
44
+ # TODO(Jiayi): support different ratios for different layers
45
+ # TODO(Jiayi): support "skipping blending if hit too short"
46
+ self.common_metadata = LMCBlendCommonMetadata(
47
+ check_layers=config.blend_check_layers,
48
+ recomp_ratios=config.blend_recompute_ratios,
49
+ thresholds=config.blend_thresholds,
50
+ )
51
+
52
+ # This will be set during the blending process
53
+ self.metadata = LMCBlendMetadata(
54
+ imp_indices=None,
55
+ attn_mask=None,
56
+ positions=None,
57
+ )
58
+
59
+ def process_qkv(
60
+ self,
61
+ q: torch.Tensor,
62
+ k: torch.Tensor,
63
+ v: torch.Tensor,
64
+ residual: torch.Tensor,
65
+ layer_id: int,
66
+ attn_output: Optional[torch.Tensor],
67
+ attn_metadata: LMCAttnMetadata,
68
+ ):
69
+ logger.debug(f"Blender is processing KV for layer {layer_id}")
70
+ old_k, old_v = self.gpu_connector.get_kv(layer_id)
71
+
72
+ if attn_output is None:
73
+ attn_output = torch.empty(
74
+ q.shape,
75
+ dtype=q.dtype,
76
+ device=q.device,
77
+ )
78
+
79
+ # perform positional encoding
80
+ if self.metadata.positions is None:
81
+ self.metadata.positions = torch.arange(
82
+ q.shape[0], device=q.device, dtype=torch.int64
83
+ )
84
+ layer = self.layerwise_model.vllm_model.model.layers[layer_id]
85
+ attn_layer = layer.self_attn
86
+ q, k = attn_layer.rotary_emb(self.metadata.positions, q, k)
87
+
88
+ if layer_id in self.common_metadata.check_layers:
89
+ diff_k = torch.sum(
90
+ (k.to(torch.float32) - old_k.to(torch.float32)) ** 2, dim=[1]
91
+ )
92
+ total_len = diff_k.shape[0]
93
+
94
+ assert self.common_metadata.recomp_ratios is not None
95
+
96
+ # TODO(Jiayi): remove `[0]` hardcode
97
+ topk_num = int(total_len * self.common_metadata.recomp_ratios[0])
98
+ topk_num = max(topk_num, 1)
99
+
100
+ top_indices = torch.topk(diff_k, k=topk_num).indices
101
+ top_indices, _ = torch.sort(top_indices)
102
+
103
+ k, v = k[top_indices], v[top_indices]
104
+ q = q[top_indices]
105
+ residual = residual[top_indices]
106
+
107
+ logger.debug(f"Number of indices picked: {len(top_indices)}")
108
+
109
+ self.metadata.imp_indices = top_indices
110
+ self.metadata.positions = self.metadata.positions[top_indices]
111
+ attn_output = attn_output[:topk_num]
112
+
113
+ attn_metadata.update_from_top_indices(top_indices)
114
+
115
+ if self.metadata.imp_indices is not None:
116
+ old_k[self.metadata.imp_indices] = k
117
+ old_v[self.metadata.imp_indices] = v
118
+ return q, old_k, old_v, residual, attn_output, attn_metadata
119
+ else:
120
+ return q, k, v, residual, attn_output, attn_metadata
121
+
122
+ # NOTE(Jiayi): Exposing this `blend_layer` interface as we might
123
+ # want to ochestrate the blending process elsewhere
124
+ def blend_layer(
125
+ self,
126
+ tokens: torch.Tensor,
127
+ mask: Optional[torch.Tensor] = None,
128
+ **kwargs,
129
+ ):
130
+ """
131
+ Perform layerwiese retrieve + blending.
132
+ """
133
+
134
+ # TODO(Jiayi): store is currently not included in this function
135
+
136
+ layerwise_model_executor = self.layerwise_model.compute_layer(tokens)
137
+ layerwise_retriever = self.cache_engine.retrieve_layer(tokens, mask, **kwargs)
138
+
139
+ next(layerwise_retriever)
140
+ yield
141
+
142
+ for i in range(self.num_layers):
143
+ next(layerwise_retriever)
144
+ next(layerwise_model_executor)
145
+ yield
146
+
147
+ next(layerwise_retriever)
148
+
149
+ self.metadata.clean()
150
+ yield
151
+
152
+ def blend(
153
+ self,
154
+ tokens: Union[torch.Tensor, list[int]],
155
+ mask: Optional[torch.Tensor] = None,
156
+ **kwargs,
157
+ ):
158
+ """
159
+ Perform blending for the given tokens.
160
+ """
161
+
162
+ if isinstance(tokens, list):
163
+ tokens = torch.tensor(tokens).cuda()
164
+
165
+ layerwise_blender = self.blend_layer(tokens, mask, **kwargs)
166
+
167
+ for i in range(self.num_layers + 2):
168
+ next(layerwise_blender)