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,161 @@
1
+ # LMCache Controller ZMQ Benchmark Tool
2
+
3
+ This tool performs load testing on LMCache Controller using ZMQ interface to measure message throughput, latency, and system performance.
4
+
5
+ ## Overview
6
+
7
+ The benchmark tool simulates multiple instances and workers sending various types of messages to the LMCache Controller:
8
+
9
+ - **BatchedKVOperationMsg**: admit/evict messages via pull socket
10
+ - **BatchedP2PLookupMsg**: p2p_lookup messages via reply socket
11
+ - **RegisterMsg/DeRegisterMsg/HeartbeatMsg**: worker lifecycle messages
12
+
13
+ ### Key Components
14
+
15
+ - **constants.py**: Defines ZMQ socket timeouts and other constants
16
+ - **config.py**: `ZMQBenchmarkConfig` dataclass for benchmark configuration
17
+ - **handlers/**: Operation handlers using Strategy Pattern with dynamic discovery
18
+ - Each operation has its own file (e.g., `admit.py`, `evict.py`)
19
+ - Automatically discovers and registers all handlers at import time
20
+ - Add new operations by creating a new handler file - no need to modify existing code
21
+ - **benchmark.py**: `ZMQControllerBenchmark` class with core logic
22
+ - **__main__.py**: Argument parsing and main entry point
23
+
24
+ ## Prerequisites
25
+
26
+ - A running LMCache Controller instance
27
+ - Python 3.10+
28
+ - Required dependencies: `zmq`, `msgspec`, `psutil`
29
+
30
+ ## Quick Start
31
+
32
+ ### Basic Usage
33
+ - Start the controller
34
+ ```bash
35
+ python3 -m lmcache.v1.api_server --host 0.0.0.0 --port 9009 \
36
+ --monitor-ports "{\"pull\":7555,\"reply\":7556}" \
37
+ --lmcache-worker-timeout 100 --health-check-interval 10
38
+ ```
39
+
40
+ - Start the benchmark
41
+ ```bash
42
+ python3 -m lmcache.tools.controller_benchmark \
43
+ --monitor-ports "{\"pull\":7555,\"reply\":7556}" \
44
+ --num-instances 50 --num-workers 1 --num-keys 1000000 --batch-size 100 \
45
+ --operations "admit:35,evict:29,heartbeat:1,p2p_lookup:35"
46
+ ```
47
+
48
+
49
+ ## Command Line Options
50
+
51
+ | Option | Default | Description |
52
+ |--------|---------|-------------|
53
+ | `--controller-host` | `localhost` | Controller host address |
54
+ | `--monitor-ports` | `{"pull":8100,"reply":8101}` | Monitor ports in JSON format |
55
+ | `--duration` | `60` | Benchmark duration in seconds |
56
+ | `--batch-size` | `50` | Number of KV operations per batch message |
57
+ | `--operations` | `admit:70,evict:25,heartbeat:5` | Operation distribution (name:percentage) |
58
+ | `--num-instances` | `10` | Number of instances to simulate |
59
+ | `--num-workers` | `1` | Number of workers per instance |
60
+ | `--num-locations` | `1` | Number of storage locations |
61
+ | `--num-keys` | `10000` | Number of unique keys |
62
+ | `--num-hashes` | `100` | Number of hashes for P2P lookup operations |
63
+ | `--no-register-first` | `false` | Skip pre-registering workers before benchmark |
64
+
65
+ ## Operation Types
66
+
67
+ The benchmark supports the following operation types:
68
+
69
+ | Operation | Description |
70
+ |-----------|-------------------------------------------|
71
+ | `admit` | Simulates KV cache admission (adds entries) |
72
+ | `evict` | Simulates KV cache eviction (removes entries) |
73
+ | `p2p_lookup` | Simulates p2p batch lookup messages |
74
+ | `register` | Simulates worker registration |
75
+ | `deregister` | Simulates worker deregistration |
76
+
77
+ ### Adding New Operations
78
+
79
+ To add a new operation, simply create a new handler file in `handlers/` directory:
80
+
81
+ 1. Create `handlers/your_operation.py` implementing `OperationHandler` base class
82
+ 2. Define `operation_name` property and implement required methods
83
+ 3. The handler will be automatically discovered and registered
84
+
85
+ No need to modify existing code - the system uses dynamic discovery!
86
+
87
+ ## Output Metrics
88
+
89
+ The benchmark reports:
90
+
91
+ - **Overall QPS**: Total messages per second
92
+ - **Per-operation QPS**: Messages per second for each operation type
93
+ - **Latency statistics**: avg, min, max, p95 (in milliseconds)
94
+ - **Error counts**: Number of failed operations
95
+ - **Memory usage**: System memory usage during the test
96
+
97
+ ### Sample Output
98
+
99
+ The following is a sample output from the benchmark ran in my macbook m4 pro.
100
+
101
+ ```
102
+ ================================================================================
103
+ LMCache Controller ZMQ Benchmark Results
104
+ ================================================================================
105
+
106
+ Configuration:
107
+ Controller URL: 127.0.0.1:7555
108
+ Duration: 60 seconds
109
+ Batch Size: 100
110
+ Operations: {'admit': 35.0, 'evict': 29.0, 'heartbeat': 1.0, 'p2p_lookup': 35.0}
111
+ Instances: 50, Workers: 1, Locations: 1, Keys: 1000000
112
+
113
+ Overall Performance:
114
+ Total Requests: 270035
115
+ Total Messages: 26736200
116
+ Total Time: 60.00s
117
+ Overall RPS (Requests/sec): 4500.58
118
+ Overall QPS (Messages/sec): 445602.80
119
+
120
+ Per-Operation Performance:
121
+ admit:
122
+ RPS (Requests/sec): 1575.23
123
+ QPS (Messages/sec): 157523.14
124
+ Latency - Avg: 0.016ms, Min: 0.007ms, Max: 0.249ms, P95: 0.031ms
125
+ Errors: 0
126
+ evict:
127
+ RPS (Requests/sec): 1305.13
128
+ QPS (Messages/sec): 130513.18
129
+ Latency - Avg: 0.016ms, Min: 0.007ms, Max: 1.201ms, P95: 0.031ms
130
+ Errors: 0
131
+ heartbeat:
132
+ RPS (Requests/sec): 45.00
133
+ QPS (Messages/sec): 45.00
134
+ Latency - Avg: 0.010ms, Min: 0.003ms, Max: 0.138ms, P95: 0.024ms
135
+ Errors: 0
136
+ p2p_lookup:
137
+ RPS (Requests/sec): 1575.21
138
+ QPS (Messages/sec): 157521.48
139
+ Latency - Avg: 0.440ms, Min: 0.150ms, Max: 6.291ms, P95: 0.843ms
140
+ Errors: 0
141
+
142
+ System Metrics:
143
+ Memory Usage - Avg: 62.3%, Max: 63.5%
144
+ ================================================================================
145
+ ```
146
+
147
+ ## Troubleshooting
148
+
149
+ ### Send Timeout Error
150
+
151
+ If you see "Send timeout - Controller may not be running", ensure:
152
+ 1. The LMCache Controller is running
153
+ 2. The `--controller-host` and `--monitor-ports` are correct
154
+ 3. No firewall is blocking the connection
155
+
156
+ ### High Error Rate
157
+
158
+ If you observe high error rates:
159
+ 1. Reduce `--batch-size` to decrease message size
160
+ 2. Increase controller resources
161
+ 3. Check network connectivity
@@ -0,0 +1 @@
1
+ # SPDX-License-Identifier: Apache-2.0
@@ -0,0 +1,331 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ LMCache Controller ZMQ Benchmark Tool - CLI Entry Point
4
+
5
+ This tool performs load testing on LMCache Controller using ZMQ interface
6
+ to measure message throughput, latency, and system performance.
7
+
8
+ Test operations:
9
+ - BatchedKVOperationMsg: admit/evict messages via PUSH socket
10
+ - RegisterMsg/DeRegisterMsg/HeartbeatMsg: worker lifecycle messages
11
+ """
12
+
13
+ # SPDX-License-Identifier: Apache-2.0
14
+
15
+ # Standard
16
+ from typing import Dict, List
17
+ import argparse
18
+ import asyncio
19
+ import json
20
+ import multiprocessing
21
+ import statistics
22
+
23
+ # First Party
24
+ from lmcache.logging import init_logger
25
+ from lmcache.tools.controller_benchmark.benchmark import (
26
+ BenchmarkResults,
27
+ OperationStats,
28
+ ZMQControllerBenchmark,
29
+ )
30
+ from lmcache.tools.controller_benchmark.config import ZMQBenchmarkConfig
31
+
32
+ logger = init_logger(__name__)
33
+
34
+
35
+ def run_single_process(config: ZMQBenchmarkConfig) -> BenchmarkResults:
36
+ """Run benchmark in a single process and return results"""
37
+ benchmark = ZMQControllerBenchmark(config)
38
+ asyncio.run(benchmark.run_benchmark())
39
+ benchmark.print_results()
40
+ return benchmark.get_results()
41
+
42
+
43
+ def aggregate_results(
44
+ results_list: List[BenchmarkResults], operations: Dict[str, float]
45
+ ) -> BenchmarkResults:
46
+ """Aggregate results from multiple processes"""
47
+ aggregated = BenchmarkResults()
48
+
49
+ if not results_list:
50
+ return aggregated
51
+
52
+ # Sum up totals
53
+ aggregated.total_requests = sum(r.total_requests for r in results_list)
54
+ aggregated.total_messages = sum(r.total_messages for r in results_list)
55
+ aggregated.total_time = max(r.total_time for r in results_list)
56
+ aggregated.overall_rps = sum(r.overall_rps for r in results_list)
57
+ aggregated.overall_qps = sum(r.overall_qps for r in results_list)
58
+
59
+ # Aggregate memory usage
60
+ for r in results_list:
61
+ aggregated.memory_usage.extend(r.memory_usage)
62
+
63
+ # Aggregate per-operation stats
64
+ for op_name in operations.keys():
65
+ op_stats_list = [
66
+ r.operations[op_name] for r in results_list if op_name in r.operations
67
+ ]
68
+ if op_stats_list:
69
+ # Sum QPS and RPS
70
+ total_qps = sum(s.qps for s in op_stats_list)
71
+ total_rps = sum(s.rps for s in op_stats_list)
72
+
73
+ # Average latencies (weighted by RPS would be more accurate,
74
+ # but simple average is acceptable)
75
+ min_latencies = [s.min_latency for s in op_stats_list if s.min_latency > 0]
76
+ max_latencies = [s.max_latency for s in op_stats_list if s.max_latency > 0]
77
+ p95_latencies = [s.p95_latency for s in op_stats_list if s.p95_latency > 0]
78
+
79
+ aggregated.operations[op_name] = OperationStats(
80
+ qps=total_qps,
81
+ rps=total_rps,
82
+ avg_latency=(
83
+ sum(s.avg_latency * s.rps for s in op_stats_list) / total_rps
84
+ if total_rps > 0
85
+ else 0.0
86
+ ),
87
+ min_latency=min(min_latencies) if min_latencies else 0.0,
88
+ max_latency=max(max_latencies) if max_latencies else 0.0,
89
+ p95_latency=(
90
+ sum(s.p95_latency * s.rps for s in op_stats_list) / total_rps
91
+ if total_rps > 0 and p95_latencies
92
+ else 0.0
93
+ ),
94
+ errors=sum(s.errors for s in op_stats_list),
95
+ )
96
+
97
+ return aggregated
98
+
99
+
100
+ def print_aggregated_results(
101
+ results: BenchmarkResults,
102
+ config: ZMQBenchmarkConfig,
103
+ num_processes: int,
104
+ ):
105
+ """Print aggregated benchmark results from all processes"""
106
+ print("\n" + "=" * 80)
107
+ print(
108
+ "LMCache Controller ZMQ Benchmark - AGGREGATED RESULTS (%d processes)"
109
+ % num_processes
110
+ )
111
+ print("=" * 80)
112
+
113
+ print("\nConfiguration:")
114
+ print(" Controller URL: %s" % config.controller_pull_url)
115
+ print(" Duration: %d seconds" % config.duration)
116
+ print(" Batch Size: %d" % config.batch_size)
117
+ print(" Operations: %s" % config.operations)
118
+ print(
119
+ " Instances per process: %d, Workers: %d, Locations: %d, Keys: %d"
120
+ % (
121
+ config.num_instances,
122
+ config.num_workers,
123
+ config.num_locations,
124
+ config.num_keys,
125
+ )
126
+ )
127
+ print(" Total Instances: %d" % (config.num_instances * num_processes))
128
+
129
+ print("\nAggregated Performance:")
130
+ print(" Total Requests: %d" % results.total_requests)
131
+ print(" Total Messages: %d" % results.total_messages)
132
+ print(" Total Time: %.2fs" % results.total_time)
133
+ print(" Overall RPS (Requests/sec): %.2f" % results.overall_rps)
134
+ print(" Overall QPS (Messages/sec): %.2f" % results.overall_qps)
135
+
136
+ print("\nPer-Operation Performance (Aggregated):")
137
+ for op_name in config.operations.keys():
138
+ if op_name in results.operations:
139
+ stats = results.operations[op_name]
140
+ print(" %s:" % op_name)
141
+ print(" RPS (Requests/sec): %.2f" % stats.rps)
142
+ print(" QPS (Messages/sec): %.2f" % stats.qps)
143
+ print(
144
+ " Latency - Avg: %.3fms, Min: %.3fms, Max: %.3fms, P95: %.3fms"
145
+ % (
146
+ stats.avg_latency * 1000,
147
+ stats.min_latency * 1000,
148
+ stats.max_latency * 1000,
149
+ stats.p95_latency * 1000,
150
+ )
151
+ )
152
+ print(" Errors: %d" % stats.errors)
153
+
154
+ print("\nSystem Metrics (All Processes):")
155
+ if results.memory_usage:
156
+ avg_memory = statistics.mean(results.memory_usage)
157
+ max_memory = max(results.memory_usage)
158
+ print(" Memory Usage - Avg: %.1f%%, Max: %.1f%%" % (avg_memory, max_memory))
159
+
160
+ print("=" * 80)
161
+
162
+
163
+ def main():
164
+ """Main function with argument parsing"""
165
+ parser = argparse.ArgumentParser(
166
+ description="LMCache Controller ZMQ Benchmark Tool",
167
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
168
+ )
169
+
170
+ parser.add_argument(
171
+ "--controller-host",
172
+ type=str,
173
+ default="127.0.0.1",
174
+ help="Controller host address",
175
+ )
176
+
177
+ parser.add_argument(
178
+ "--monitor-ports",
179
+ type=str,
180
+ default='{"pull":8100,"reply":8101}',
181
+ help='Monitor ports in JSON format, e.g. {"pull":8100,"reply":8101}',
182
+ )
183
+
184
+ parser.add_argument(
185
+ "--duration",
186
+ type=int,
187
+ default=60,
188
+ help="Benchmark duration in seconds",
189
+ )
190
+
191
+ parser.add_argument(
192
+ "--batch-size",
193
+ type=int,
194
+ default=50,
195
+ help="Number of KV operations per batch message",
196
+ )
197
+
198
+ parser.add_argument(
199
+ "--operations",
200
+ type=str,
201
+ default="admit:70,evict:25,heartbeat:5",
202
+ help="Operation distribution (name:percentage comma-separated)",
203
+ )
204
+
205
+ parser.add_argument(
206
+ "--num-instances",
207
+ type=int,
208
+ default=10,
209
+ help="Number of instances to simulate per process",
210
+ )
211
+
212
+ parser.add_argument(
213
+ "--num-workers",
214
+ type=int,
215
+ default=1,
216
+ help="Number of workers per instance",
217
+ )
218
+
219
+ parser.add_argument(
220
+ "--num-locations",
221
+ type=int,
222
+ default=1,
223
+ help="Number of storage locations",
224
+ )
225
+
226
+ parser.add_argument(
227
+ "--num-keys",
228
+ type=int,
229
+ default=10000,
230
+ help="Number of unique keys",
231
+ )
232
+
233
+ parser.add_argument(
234
+ "--num-hashes",
235
+ type=int,
236
+ default=100,
237
+ help="Number of hashes for P2P lookup operations",
238
+ )
239
+
240
+ parser.add_argument(
241
+ "--num-processes",
242
+ type=int,
243
+ default=1,
244
+ help="Number of concurrent benchmark processes",
245
+ )
246
+
247
+ parser.add_argument(
248
+ "--no-register-first",
249
+ action="store_true",
250
+ help="Skip pre-registering workers before benchmark",
251
+ )
252
+
253
+ args = parser.parse_args()
254
+
255
+ # Parse monitor ports from JSON
256
+ try:
257
+ monitor_ports = json.loads(args.monitor_ports)
258
+ pull_port = monitor_ports.get("pull", 8100)
259
+ reply_port = monitor_ports.get("reply")
260
+ heartbeat_port = monitor_ports.get("heartbeat")
261
+ except json.JSONDecodeError as e:
262
+ logger.error("Failed to parse monitor-ports JSON: %s", e)
263
+ raise ValueError("Invalid monitor-ports format") from e
264
+
265
+ # Convert 0.0.0.0 to 127.0.0.1 for client connections
266
+ client_host = (
267
+ "127.0.0.1" if args.controller_host == "0.0.0.0" else args.controller_host
268
+ )
269
+ controller_pull_url = f"{client_host}:{pull_port}"
270
+ controller_reply_url = f"{client_host}:{reply_port}" if reply_port else None
271
+ controller_heartbeat_url = (
272
+ f"{client_host}:{heartbeat_port}" if heartbeat_port else None
273
+ )
274
+
275
+ # Parse operations
276
+ operations = {}
277
+ for op_str in args.operations.split(","):
278
+ if ":" in op_str:
279
+ name, percentage = op_str.split(":", 1)
280
+ operations[name.strip()] = float(percentage.strip())
281
+
282
+ num_processes = args.num_processes
283
+
284
+ # Create a base config dict
285
+ base_config_kwargs = {
286
+ "controller_pull_url": controller_pull_url,
287
+ "controller_reply_url": controller_reply_url,
288
+ "controller_heartbeat_url": controller_heartbeat_url,
289
+ "duration": args.duration,
290
+ "batch_size": args.batch_size,
291
+ "operations": operations,
292
+ "num_instances": args.num_instances,
293
+ "num_workers": args.num_workers,
294
+ "num_locations": args.num_locations,
295
+ "num_keys": args.num_keys,
296
+ "num_hashes": args.num_hashes,
297
+ "register_first": not args.no_register_first,
298
+ "num_processes": num_processes,
299
+ }
300
+
301
+ try:
302
+ if num_processes == 1:
303
+ # Single process mode
304
+ config = ZMQBenchmarkConfig(**base_config_kwargs, process_id=0)
305
+ run_single_process(config)
306
+ else:
307
+ # Multi-process mode
308
+ logger.info(
309
+ "Starting multi-process benchmark with %d processes", num_processes
310
+ )
311
+ configs = [
312
+ ZMQBenchmarkConfig(**base_config_kwargs, process_id=i)
313
+ for i in range(num_processes)
314
+ ]
315
+ # Use multiprocessing pool to run benchmarks in parallel
316
+ with multiprocessing.Pool(processes=num_processes) as pool:
317
+ results_list = pool.map(run_single_process, configs)
318
+
319
+ # Aggregate and print combined results
320
+ aggregated = aggregate_results(results_list, operations)
321
+ print_aggregated_results(aggregated, configs[0], num_processes)
322
+
323
+ except KeyboardInterrupt:
324
+ print("\nBenchmark interrupted by user")
325
+ except Exception as e:
326
+ logger.error("Benchmark failed: %s", e)
327
+ raise e
328
+
329
+
330
+ if __name__ == "__main__":
331
+ main()