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,639 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ from dataclasses import dataclass
4
+ from typing import TYPE_CHECKING, Any, Optional, Union
5
+ import asyncio
6
+ import threading
7
+ import time
8
+ import uuid
9
+
10
+ # Third Party
11
+ import msgspec
12
+ import zmq
13
+
14
+ # First Party
15
+ from lmcache.logging import init_logger
16
+ from lmcache.v1.memory_management import (
17
+ MemoryObj,
18
+ )
19
+
20
+ if TYPE_CHECKING:
21
+ # Third Party
22
+ from nixl._api import NixlAgent
23
+
24
+ # First Party
25
+ from lmcache.v1.rpc_utils import get_zmq_context, get_zmq_socket
26
+ from lmcache.v1.transfer_channel.abstract import BaseTransferChannel
27
+ from lmcache.v1.transfer_channel.transfer_utils import (
28
+ InitSideMsgBase,
29
+ InitSideRetMsgBase,
30
+ SideMsg,
31
+ )
32
+
33
+ logger = init_logger(__name__)
34
+
35
+
36
+ class NixlMsgBase(msgspec.Struct, tag=True):
37
+ """Base class for all nixl-related messages"""
38
+
39
+ pass
40
+
41
+
42
+ class NixlInitRequest(NixlMsgBase):
43
+ local_meta_bytes: bytes # Metadata from the sender nixl agent
44
+
45
+
46
+ class NixlMemRegRequest(NixlMsgBase):
47
+ remote_agent_name: bytes
48
+ local_id: str
49
+ local_xfer_dlist_bytes: bytes
50
+
51
+
52
+ class NixlInitResponse(NixlMsgBase):
53
+ remote_agent_name: bytes
54
+ remote_meta_bytes: bytes # Metadata from the receiver nixl agent
55
+
56
+
57
+ class NixlMemRegResponse(NixlMsgBase):
58
+ remote_xfer_dlist_bytes: bytes # Serialized transfer descriptors for the receiver
59
+
60
+
61
+ NixlMsg = Union[
62
+ NixlInitRequest, NixlInitResponse, NixlMemRegRequest, NixlMemRegResponse
63
+ ]
64
+
65
+
66
+ class NixlChannel(BaseTransferChannel):
67
+ def __init__(
68
+ self,
69
+ async_mode: bool = False,
70
+ device: Optional[str] = None,
71
+ **kwargs,
72
+ ):
73
+ assert "role" in kwargs
74
+ assert "buffer_ptr" in kwargs
75
+ assert "buffer_size" in kwargs
76
+ assert "align_bytes" in kwargs
77
+ assert "tp_rank" in kwargs
78
+ assert "peer_init_url" in kwargs
79
+
80
+ if "backends" in kwargs:
81
+ backends = kwargs["backends"]
82
+ else:
83
+ backends = ["UCX"]
84
+
85
+ self.role = kwargs["role"]
86
+
87
+ self.nixl_wrapper = NixlAgentWrapper(
88
+ buffer_ptr=kwargs["buffer_ptr"],
89
+ buffer_size=kwargs["buffer_size"],
90
+ page_size=kwargs["align_bytes"],
91
+ tp_rank=kwargs["tp_rank"],
92
+ backends=backends,
93
+ device=device,
94
+ )
95
+ self.nixl_agent = self.nixl_wrapper.agent
96
+
97
+ # Used for P2P
98
+ self.peer_lookup_url = kwargs.get("peer_lookup_url", None)
99
+
100
+ self.running = True
101
+ self.remote_xfer_handlers_dict: dict[
102
+ str, NixlAgent.nixl_prepped_dlist_handle
103
+ ] = {}
104
+
105
+ self.side_channels: list[zmq.Socket] = []
106
+ self.running_threads: list[threading.Thread] = []
107
+
108
+ self.async_mode = async_mode
109
+ if self.async_mode:
110
+ self.zmq_context = get_zmq_context(use_asyncio=True)
111
+ else:
112
+ self.zmq_context = get_zmq_context(use_asyncio=False)
113
+ self.peer_init_url = kwargs["peer_init_url"]
114
+ self.event_loop = kwargs.get("event_loop", None)
115
+
116
+ self._init_side_channels()
117
+
118
+ ############################################################
119
+ # Initialization functions
120
+ ############################################################
121
+ def lazy_init_peer_connection(
122
+ self,
123
+ local_id: str,
124
+ peer_id: str,
125
+ peer_init_url: str,
126
+ init_side_msg: Optional[InitSideMsgBase] = None,
127
+ ) -> Optional[InitSideRetMsgBase]:
128
+ # Initialize temporary socket for nixl initialization
129
+ init_tmp_socket = get_zmq_socket(
130
+ self.zmq_context,
131
+ peer_init_url,
132
+ "tcp",
133
+ zmq.REQ,
134
+ "connect",
135
+ )
136
+
137
+ # Build and send init request
138
+ nixl_init_req = NixlInitRequest(
139
+ local_meta_bytes=self.nixl_agent.get_agent_metadata(),
140
+ )
141
+ init_tmp_socket.send(msgspec.msgpack.encode(nixl_init_req))
142
+
143
+ # Wait remote agent metadata and register remote agent
144
+ nixl_init_resp_bytes = init_tmp_socket.recv()
145
+ nixl_init_resp = msgspec.msgpack.decode(nixl_init_resp_bytes, type=NixlMsg)
146
+ remote_meta_bytes = nixl_init_resp.remote_meta_bytes
147
+ remote_agent_name = self.nixl_agent.add_remote_agent(remote_meta_bytes)
148
+
149
+ # Register remote memory
150
+ local_xfer_dlist_bytes = self.nixl_agent.get_serialized_descs(
151
+ self.nixl_wrapper.xfer_descs
152
+ )
153
+ nixl_mem_reg_req = NixlMemRegRequest(
154
+ remote_agent_name=nixl_init_resp.remote_agent_name,
155
+ local_id=local_id,
156
+ local_xfer_dlist_bytes=local_xfer_dlist_bytes,
157
+ )
158
+ init_tmp_socket.send(msgspec.msgpack.encode(nixl_mem_reg_req))
159
+ nixl_mem_reg_resp_bytes = init_tmp_socket.recv()
160
+ nixl_mem_reg_resp = msgspec.msgpack.decode(
161
+ nixl_mem_reg_resp_bytes, type=NixlMsg
162
+ )
163
+
164
+ remote_xfer_dlist_bytes = nixl_mem_reg_resp.remote_xfer_dlist_bytes
165
+ remote_xfer_dlist = self.nixl_agent.deserialize_descs(remote_xfer_dlist_bytes)
166
+ remote_xfer_handlers = self.nixl_agent.prep_xfer_dlist(
167
+ remote_agent_name, remote_xfer_dlist
168
+ )
169
+ self.remote_xfer_handlers_dict[peer_id] = remote_xfer_handlers
170
+
171
+ # Send side message if any
172
+ init_ret_msg: Optional[InitSideRetMsgBase] = None
173
+ if init_side_msg is not None:
174
+ init_ret_msg = self.send_init_side_msg(
175
+ init_tmp_socket,
176
+ init_side_msg,
177
+ )
178
+
179
+ init_tmp_socket.close()
180
+ return init_ret_msg
181
+
182
+ async def async_lazy_init_peer_connection(
183
+ self,
184
+ local_id: str,
185
+ peer_id: str,
186
+ peer_init_url: str,
187
+ init_side_msg: Optional[InitSideMsgBase] = None,
188
+ ) -> Optional[InitSideRetMsgBase]:
189
+ # Initialize temporary socket for nixl initialization
190
+ init_tmp_socket = get_zmq_socket(
191
+ self.zmq_context,
192
+ peer_init_url,
193
+ "tcp",
194
+ zmq.REQ,
195
+ "connect",
196
+ )
197
+ # Build and send init request
198
+ nixl_init_req = NixlInitRequest(
199
+ local_meta_bytes=self.nixl_agent.get_agent_metadata(),
200
+ )
201
+ await init_tmp_socket.send(msgspec.msgpack.encode(nixl_init_req))
202
+ # Wait remote agent metadata and register remote agent
203
+ nixl_init_resp_bytes = await init_tmp_socket.recv()
204
+ nixl_init_resp = msgspec.msgpack.decode(nixl_init_resp_bytes, type=NixlMsg)
205
+ remote_meta_bytes = nixl_init_resp.remote_meta_bytes
206
+ remote_agent_name = self.nixl_agent.add_remote_agent(remote_meta_bytes)
207
+
208
+ # Register remote memory
209
+ local_xfer_dlist_bytes = self.nixl_agent.get_serialized_descs(
210
+ self.nixl_wrapper.xfer_descs
211
+ )
212
+ nixl_mem_reg_req = NixlMemRegRequest(
213
+ remote_agent_name=nixl_init_resp.remote_agent_name,
214
+ local_id=local_id,
215
+ local_xfer_dlist_bytes=local_xfer_dlist_bytes,
216
+ )
217
+
218
+ await init_tmp_socket.send(msgspec.msgpack.encode(nixl_mem_reg_req))
219
+ nixl_mem_reg_resp_bytes = await init_tmp_socket.recv()
220
+ nixl_mem_reg_resp = msgspec.msgpack.decode(
221
+ nixl_mem_reg_resp_bytes, type=NixlMsg
222
+ )
223
+
224
+ remote_xfer_dlist_bytes = nixl_mem_reg_resp.remote_xfer_dlist_bytes
225
+ remote_xfer_dlist = self.nixl_agent.deserialize_descs(remote_xfer_dlist_bytes)
226
+ remote_xfer_handlers = self.nixl_agent.prep_xfer_dlist(
227
+ remote_agent_name, remote_xfer_dlist
228
+ )
229
+ self.remote_xfer_handlers_dict[peer_id] = remote_xfer_handlers
230
+
231
+ # Send side message if any
232
+ init_ret_msg: Optional[InitSideRetMsgBase] = None
233
+ if init_side_msg is not None:
234
+ init_ret_msg = await self.async_send_init_side_msg(
235
+ init_tmp_socket,
236
+ init_side_msg,
237
+ )
238
+
239
+ init_tmp_socket.close()
240
+ return init_ret_msg
241
+
242
+ def remote_xfer_handler_exists(self, receiver_or_sender_id: str) -> bool:
243
+ return receiver_or_sender_id in self.remote_xfer_handlers_dict
244
+
245
+ def _init_side_channels(self):
246
+ if self.peer_init_url is None:
247
+ return
248
+
249
+ if self.async_mode:
250
+ # Start listening coroutine for initialization side channel
251
+ asyncio.run_coroutine_threadsafe(self._async_init_loop(), self.event_loop)
252
+ else:
253
+ # Start listening thread for initialization side channel
254
+ self.init_thread = threading.Thread(target=self._init_loop, daemon=True)
255
+ self.init_thread.start()
256
+ self.running_threads.append(self.init_thread)
257
+
258
+ def _handle_init_msg(
259
+ self, req: Union[NixlMsg, InitSideMsgBase]
260
+ ) -> Union[NixlMsg, InitSideRetMsgBase]:
261
+ resp: Union[NixlMsg, InitSideRetMsgBase]
262
+ if isinstance(req, NixlInitRequest):
263
+ agent_name = self.nixl_agent.add_remote_agent(req.local_meta_bytes)
264
+
265
+ resp = NixlInitResponse(
266
+ remote_agent_name=agent_name,
267
+ remote_meta_bytes=self.nixl_agent.get_agent_metadata(),
268
+ )
269
+
270
+ logger.info("Replying initialization response")
271
+
272
+ elif isinstance(req, NixlMemRegRequest):
273
+ local_xfer_descs = self.nixl_agent.get_serialized_descs(
274
+ self.nixl_wrapper.xfer_descs
275
+ )
276
+
277
+ remote_xfer_dlist_bytes = req.local_xfer_dlist_bytes
278
+ remote_xfer_dlist = self.nixl_agent.deserialize_descs(
279
+ remote_xfer_dlist_bytes
280
+ )
281
+ remote_xfer_handlers = self.nixl_agent.prep_xfer_dlist(
282
+ req.remote_agent_name, remote_xfer_dlist
283
+ )
284
+ self.remote_xfer_handlers_dict[req.local_id] = remote_xfer_handlers
285
+
286
+ resp = NixlMemRegResponse(
287
+ remote_xfer_dlist_bytes=local_xfer_descs,
288
+ )
289
+
290
+ logger.info("Replying mem register response")
291
+ elif isinstance(req, InitSideMsgBase):
292
+ resp = self.handle_init_side_msg(req)
293
+ logger.info("Replying P2P init side response")
294
+ else:
295
+ raise ValueError(f"Unsupported InitMsg type: {type(req)}")
296
+
297
+ return resp
298
+
299
+ def _init_loop(self):
300
+ # Initialize initialization side channels
301
+ self.init_side_channel = get_zmq_socket(
302
+ self.zmq_context,
303
+ self.peer_init_url,
304
+ "tcp",
305
+ zmq.REP,
306
+ "bind",
307
+ )
308
+ self.side_channels.append(self.init_side_channel)
309
+
310
+ # NOTE: Initialization has to be two stages:
311
+ # (1) Exchanging the metadata.
312
+ # (2) Registering the memory descriptors.
313
+ # Otherwise, there's a chance that nixl got stuck
314
+ # (handle always give "PROC" status) during the first request.
315
+ # (3) Exchanging side messages if any. This depends on the backend
316
+ # that uses the channel.
317
+ while self.running:
318
+ try:
319
+ req_bytes = self.init_side_channel.recv()
320
+
321
+ logger.info("Received initialization request")
322
+
323
+ req = msgspec.msgpack.decode(req_bytes, type=Union[NixlMsg, SideMsg])
324
+
325
+ resp = self._handle_init_msg(req)
326
+
327
+ self.init_side_channel.send(msgspec.msgpack.encode(resp))
328
+
329
+ except Exception as e:
330
+ logger.error("Failed to process initialization loop: %s", str(e))
331
+ if self.running:
332
+ time.sleep(0.01)
333
+
334
+ async def _async_init_loop(self):
335
+ # Initialize initialization side channels
336
+ self.init_side_channel = get_zmq_socket(
337
+ self.zmq_context,
338
+ self.peer_init_url,
339
+ "tcp",
340
+ zmq.REP,
341
+ "bind",
342
+ )
343
+ self.side_channels.append(self.init_side_channel)
344
+ logger.info("Starting async initialization loop")
345
+
346
+ while self.running:
347
+ try:
348
+ req_bytes = await self.init_side_channel.recv()
349
+
350
+ logger.info("Received initialization request")
351
+
352
+ req = msgspec.msgpack.decode(req_bytes, type=Union[NixlMsg, SideMsg])
353
+
354
+ resp = self._handle_init_msg(req)
355
+
356
+ await self.init_side_channel.send(msgspec.msgpack.encode(resp))
357
+
358
+ except Exception as e:
359
+ logger.error("Failed to process initialization loop: %s", str(e))
360
+ if self.running:
361
+ time.sleep(0.01)
362
+
363
+ ############################################################
364
+ # Utility functions
365
+ ############################################################
366
+
367
+ def get_local_mem_indices(
368
+ self, objects: Union[list[bytes], list[MemoryObj]]
369
+ ) -> list[int]:
370
+ local_indices = []
371
+ if isinstance(objects[0], MemoryObj):
372
+ for mem_obj in objects:
373
+ assert isinstance(mem_obj, MemoryObj)
374
+ local_indices.append(mem_obj.meta.address)
375
+ elif isinstance(objects[0], bytes):
376
+ raise NotImplementedError(
377
+ "Sending raw bytes is not supported in NIXL channel"
378
+ )
379
+ return local_indices
380
+
381
+ ############################################################
382
+ # Send/Recv functions
383
+ ############################################################
384
+
385
+ ### Send and Recv must be called in pair ###
386
+ def batched_send(
387
+ self,
388
+ objects: Union[list[bytes], list[MemoryObj]],
389
+ transfer_spec: Optional[dict] = None,
390
+ ) -> int:
391
+ raise NotImplementedError
392
+
393
+ def batched_recv(
394
+ self,
395
+ buffers: Union[list[bytes], list[MemoryObj]],
396
+ transfer_spec: Optional[dict] = None,
397
+ ) -> int:
398
+ raise NotImplementedError
399
+
400
+ async def async_batched_send(
401
+ self,
402
+ objects: Union[list[bytes], list[MemoryObj]],
403
+ transfer_spec: Optional[dict] = None,
404
+ ) -> int:
405
+ raise NotImplementedError
406
+
407
+ async def async_batched_recv(
408
+ self,
409
+ buffers: Union[list[bytes], list[MemoryObj]],
410
+ transfer_spec: Optional[dict] = None,
411
+ ) -> int:
412
+ raise NotImplementedError
413
+
414
+ ############################################################
415
+ # Read/Write functions
416
+ ############################################################
417
+
418
+ ### Read and Write only need to be called on one side ###
419
+ def batched_write(
420
+ self,
421
+ objects: Union[list[bytes], list[MemoryObj]],
422
+ transfer_spec: Optional[dict] = None,
423
+ ) -> int:
424
+ """
425
+ Write a batch of data through the nixl channel.
426
+
427
+ :param objects: A list of bytes or MemoryObj to be written.
428
+ :param transfer_spec: Additional specifications for the transfer.
429
+
430
+ :return: Number of successfully transferred objects.
431
+ """
432
+ assert transfer_spec is not None
433
+
434
+ handle = self.nixl_agent.make_prepped_xfer(
435
+ "WRITE",
436
+ self.nixl_wrapper.xfer_handler,
437
+ self.get_local_mem_indices(objects),
438
+ self.remote_xfer_handlers_dict[transfer_spec["receiver_id"]],
439
+ transfer_spec["remote_indexes"],
440
+ )
441
+
442
+ self.nixl_agent.transfer(handle)
443
+
444
+ # TODO(Jiayi) tune hyperparameters
445
+ wait_time = 0.001
446
+ while True:
447
+ status = self.nixl_agent.check_xfer_state(handle)
448
+ logger.debug(f"Transfer status: {status}")
449
+
450
+ if status == "ERR":
451
+ logger.error("Error in send operation")
452
+ raise RuntimeError("Failed to send objects to remote peer")
453
+ elif status == "PROC":
454
+ time.sleep(wait_time) # Avoid busy waiting
455
+ continue
456
+ assert status == "DONE", f"Transfer status is {status}, expected DONE"
457
+ # self._proxy_side_channel.send(notif_msg_bytes)
458
+ break
459
+
460
+ return len(objects)
461
+
462
+ def batched_read(
463
+ self,
464
+ buffers: Union[list[bytes], list[MemoryObj]],
465
+ transfer_spec: Optional[dict] = None,
466
+ ) -> int:
467
+ raise NotImplementedError
468
+
469
+ async def async_batched_write(
470
+ self,
471
+ objects: Union[list[bytes], list[MemoryObj]],
472
+ transfer_spec: Optional[dict] = None,
473
+ ) -> int:
474
+ """
475
+ Write a batch of data through the channel.
476
+
477
+ :param objects: A list of bytes or MemoryObj to be written.
478
+ :param transfer_spec: Additional specifications for the transfer.
479
+ Should contain 'receiver_id' and 'remote_indexes'.
480
+
481
+ :return: Number of successfully transferred objects.
482
+ """
483
+
484
+ assert transfer_spec is not None
485
+
486
+ handle = self.nixl_agent.make_prepped_xfer(
487
+ "WRITE",
488
+ self.nixl_wrapper.xfer_handler,
489
+ self.get_local_mem_indices(objects),
490
+ self.remote_xfer_handlers_dict[transfer_spec["receiver_id"]],
491
+ transfer_spec["remote_indexes"],
492
+ )
493
+ self.nixl_agent.transfer(handle)
494
+
495
+ # TODO(Jiayi) tune hyperparameters
496
+ wait_time = 0.001
497
+ while True:
498
+ status = self.nixl_agent.check_xfer_state(handle)
499
+ logger.debug(f"Transfer status: {status}")
500
+
501
+ if status == "ERR":
502
+ logger.error("Error in send operation")
503
+ raise RuntimeError("Failed to send objects to remote peer")
504
+ elif status == "PROC":
505
+ await asyncio.sleep(wait_time) # Avoid busy waiting
506
+ continue
507
+ assert status == "DONE", f"Transfer status is {status}, expected DONE"
508
+ # self._proxy_side_channel.send(notif_msg_bytes)
509
+ break
510
+ return len(objects)
511
+
512
+ async def async_batched_read(
513
+ self,
514
+ buffers: Union[list[bytes], list[MemoryObj]],
515
+ transfer_spec: Optional[dict] = None,
516
+ ) -> int:
517
+ """
518
+ Read a batch of data through the channel.
519
+
520
+ :param buffers: A list of bytes or MemoryObj to store the read data.
521
+ :param transfer_spec: Additional specifications for the transfer.
522
+
523
+ :return: True if the send operation is successful.
524
+ """
525
+
526
+ assert transfer_spec is not None
527
+
528
+ handle = self.nixl_agent.make_prepped_xfer(
529
+ "READ",
530
+ self.nixl_wrapper.xfer_handler,
531
+ self.get_local_mem_indices(buffers),
532
+ self.remote_xfer_handlers_dict[transfer_spec["sender_id"]],
533
+ transfer_spec["remote_indexes"],
534
+ )
535
+ self.nixl_agent.transfer(handle)
536
+
537
+ # TODO(Jiayi) tune hyperparameters
538
+ wait_time = 0.001
539
+ while True:
540
+ status = self.nixl_agent.check_xfer_state(handle)
541
+ logger.debug(f"Transfer status: {status}")
542
+
543
+ if status == "ERR":
544
+ logger.error("Error in send operation")
545
+ raise RuntimeError("Failed to send objects to remote peer")
546
+ elif status == "PROC":
547
+ await asyncio.sleep(wait_time) # Avoid busy waiting
548
+ continue
549
+ assert status == "DONE", f"Transfer status is {status}, expected DONE"
550
+ # self._proxy_side_channel.send(notif_msg_bytes)
551
+ break
552
+ return len(buffers)
553
+
554
+ ############################################################
555
+ # Cleanup-related functions
556
+ ############################################################
557
+
558
+ def close(self):
559
+ self.running = False
560
+ for thread in self.running_threads:
561
+ thread.join()
562
+ self.zmq_context.term()
563
+ self.nixl_agent.deregister_memory(self.nixl_wrapper.reg_descs)
564
+ self.nixl_agent.release_dlist_handle(self.nixl_wrapper.xfer_handler)
565
+
566
+ for remote_xfer_handler in self.remote_xfer_handlers_dict.values():
567
+ self.nixl_agent.release_dlist_handle(remote_xfer_handler)
568
+
569
+
570
+ @dataclass
571
+ class NixlAgentWrapper:
572
+ agent: "NixlAgent"
573
+ reg_descs: Any
574
+ xfer_descs: Any
575
+ xfer_handler: Any
576
+
577
+ def __init__(
578
+ self,
579
+ buffer_ptr: int,
580
+ buffer_size: int,
581
+ page_size: int,
582
+ tp_rank: int,
583
+ backends: list[str],
584
+ device: Optional[str] = None,
585
+ ):
586
+ """
587
+ Initialize the NIXL agent.
588
+
589
+ Args:
590
+ buffer_size (int): The size of the buffer.
591
+ buffer_ptr (int): The pointer to the buffer.
592
+ page_size (int): The page size of NIXL and
593
+ the lmcache memory allocator.
594
+ tp_rank (int): The tensor parallel rank.
595
+ backends (list[str]): The list of backends to use.
596
+
597
+ Returns:
598
+ NixlWrapper: The NIXL agent.
599
+ reg_dlist: the registered memory descriptor list.
600
+ xfer_dlist: the local transfer descriptor list.
601
+ prepped_xfer_handler: the prepped transfer handler.
602
+ """
603
+ try:
604
+ # Third Party
605
+ from nixl._api import nixl_agent as NixlAgent
606
+ from nixl._api import nixl_agent_config
607
+ except ImportError as err:
608
+ raise RuntimeError("NIXL is not available") from err
609
+
610
+ # Handle None backends by setting default to ["UCX"]
611
+ if backends is None:
612
+ backends = ["UCX"]
613
+
614
+ # Create a NIXL agent
615
+ nixl_agent = NixlAgent(
616
+ str(uuid.uuid4()),
617
+ nixl_agent_config(backends=backends),
618
+ )
619
+
620
+ # Register the memory
621
+ # The four fields are (base_addr, length, dev_id, meta_info)
622
+ # https://github.com/ai-dynamo/nixl/blob/main/src/api/cpp/nixl_descriptors.h#L152
623
+ memory_desc = [(buffer_ptr, buffer_size, tp_rank, "")]
624
+ mem_type = "cpu" if device == "cpu" else "cuda"
625
+
626
+ reg_descs = nixl_agent.get_reg_descs(memory_desc, mem_type=mem_type)
627
+ nixl_agent.register_memory(reg_descs)
628
+
629
+ # Create xfer handlers
630
+ xfer_desc = []
631
+ for base_addr in range(buffer_ptr, buffer_ptr + buffer_size, page_size):
632
+ xfer_desc.append((base_addr, page_size, tp_rank))
633
+
634
+ xfer_descs = nixl_agent.get_xfer_descs(xfer_desc, mem_type=mem_type)
635
+ xfer_handler = nixl_agent.prep_xfer_dlist("", xfer_descs, mem_type=mem_type)
636
+ self.agent = nixl_agent
637
+ self.reg_descs = reg_descs
638
+ self.xfer_descs = xfer_descs
639
+ self.xfer_handler = xfer_handler