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.
- lmcache/__init__.py +84 -0
- lmcache/_version.py +24 -0
- lmcache/cli/__init__.py +1 -0
- lmcache/cli/commands/__init__.py +34 -0
- lmcache/cli/commands/base.py +157 -0
- lmcache/cli/commands/bench/__init__.py +557 -0
- lmcache/cli/commands/bench/engine_bench/__init__.py +1 -0
- lmcache/cli/commands/bench/engine_bench/config.py +245 -0
- lmcache/cli/commands/bench/engine_bench/interactive/__init__.py +274 -0
- lmcache/cli/commands/bench/engine_bench/interactive/config.json +10 -0
- lmcache/cli/commands/bench/engine_bench/interactive/schema.py +352 -0
- lmcache/cli/commands/bench/engine_bench/interactive/state.py +327 -0
- lmcache/cli/commands/bench/engine_bench/interactive/terminal.py +291 -0
- lmcache/cli/commands/bench/engine_bench/progress.py +145 -0
- lmcache/cli/commands/bench/engine_bench/request_sender.py +232 -0
- lmcache/cli/commands/bench/engine_bench/stats.py +275 -0
- lmcache/cli/commands/bench/engine_bench/workloads/__init__.py +153 -0
- lmcache/cli/commands/bench/engine_bench/workloads/base.py +122 -0
- lmcache/cli/commands/bench/engine_bench/workloads/long_doc_permutator.py +435 -0
- lmcache/cli/commands/bench/engine_bench/workloads/long_doc_qa.py +281 -0
- lmcache/cli/commands/bench/engine_bench/workloads/multi_round_chat.py +337 -0
- lmcache/cli/commands/bench/engine_bench/workloads/random_prefill.py +178 -0
- lmcache/cli/commands/describe.py +310 -0
- lmcache/cli/commands/kvcache.py +133 -0
- lmcache/cli/commands/mock.py +75 -0
- lmcache/cli/commands/ping.py +113 -0
- lmcache/cli/commands/query/__init__.py +155 -0
- lmcache/cli/commands/query/prompt.py +134 -0
- lmcache/cli/commands/query/request.py +357 -0
- lmcache/cli/commands/server.py +99 -0
- lmcache/cli/commands/tool/__init__.py +63 -0
- lmcache/cli/commands/tool/cache_simulator.py +113 -0
- lmcache/cli/commands/trace/__init__.py +505 -0
- lmcache/cli/commands/trace/dispatch.py +249 -0
- lmcache/cli/commands/trace/driver.py +372 -0
- lmcache/cli/commands/trace/stats.py +289 -0
- lmcache/cli/documents/lmcache.txt +11 -0
- lmcache/cli/main.py +42 -0
- lmcache/cli/metrics/__init__.py +29 -0
- lmcache/cli/metrics/formatter.py +171 -0
- lmcache/cli/metrics/handler.py +94 -0
- lmcache/cli/metrics/metrics.py +161 -0
- lmcache/cli/metrics/section.py +77 -0
- lmcache/connections.py +173 -0
- lmcache/integration/__init__.py +2 -0
- lmcache/integration/base_service_factory.py +165 -0
- lmcache/integration/request_telemetry/__init__.py +1 -0
- lmcache/integration/request_telemetry/base.py +51 -0
- lmcache/integration/request_telemetry/factory.py +113 -0
- lmcache/integration/request_telemetry/fastapi.py +109 -0
- lmcache/integration/request_telemetry/noop.py +35 -0
- lmcache/integration/sglang/__init__.py +2 -0
- lmcache/integration/sglang/sglang_adapter.py +326 -0
- lmcache/integration/sglang/utils.py +39 -0
- lmcache/integration/vllm/__init__.py +1 -0
- lmcache/integration/vllm/lmcache_connector_v1.py +213 -0
- lmcache/integration/vllm/lmcache_connector_v1_085.py +150 -0
- lmcache/integration/vllm/lmcache_mp_connector_0180.py +1072 -0
- lmcache/integration/vllm/tests/test_mm_hash_utils.py +112 -0
- lmcache/integration/vllm/utils.py +433 -0
- lmcache/integration/vllm/vllm_multi_process_adapter.py +1090 -0
- lmcache/integration/vllm/vllm_service_factory.py +339 -0
- lmcache/integration/vllm/vllm_v1_adapter.py +1713 -0
- lmcache/logging.py +107 -0
- lmcache/native_storage_ops.pyi +230 -0
- lmcache/non_cuda_equivalents.py +1424 -0
- lmcache/observability.py +1958 -0
- lmcache/storage_backend/serde/__init__.py +1 -0
- lmcache/storage_backend/serde/cachegen_basics.py +210 -0
- lmcache/storage_backend/serde/cachegen_decoder.py +207 -0
- lmcache/storage_backend/serde/cachegen_encoder.py +394 -0
- lmcache/storage_backend/serde/serde.py +75 -0
- lmcache/tools/__init__.py +1 -0
- lmcache/tools/cache_simulator/README.md +392 -0
- lmcache/tools/cache_simulator/__init__.py +1 -0
- lmcache/tools/cache_simulator/docs/simulate_example.png +0 -0
- lmcache/tools/cache_simulator/docs/sweep_example.png +0 -0
- lmcache/tools/cache_simulator/gen_bench_dataset.py +360 -0
- lmcache/tools/cache_simulator/lru_cache.py +124 -0
- lmcache/tools/cache_simulator/plot_hit_rate.py +231 -0
- lmcache/tools/cache_simulator/simulator.py +795 -0
- lmcache/tools/controller_benchmark/README.md +161 -0
- lmcache/tools/controller_benchmark/__init__.py +1 -0
- lmcache/tools/controller_benchmark/__main__.py +331 -0
- lmcache/tools/controller_benchmark/benchmark.py +660 -0
- lmcache/tools/controller_benchmark/config.py +44 -0
- lmcache/tools/controller_benchmark/constants.py +10 -0
- lmcache/tools/controller_benchmark/handlers/__init__.py +46 -0
- lmcache/tools/controller_benchmark/handlers/admit.py +52 -0
- lmcache/tools/controller_benchmark/handlers/base.py +47 -0
- lmcache/tools/controller_benchmark/handlers/deregister.py +49 -0
- lmcache/tools/controller_benchmark/handlers/evict.py +52 -0
- lmcache/tools/controller_benchmark/handlers/heartbeat.py +56 -0
- lmcache/tools/controller_benchmark/handlers/p2p_lookup.py +47 -0
- lmcache/tools/controller_benchmark/handlers/register.py +56 -0
- lmcache/tools/mp_status_viewer/__init__.py +1 -0
- lmcache/tools/mp_status_viewer/__main__.py +95 -0
- lmcache/usage_context.py +417 -0
- lmcache/utils.py +665 -0
- lmcache/v1/__init__.py +2 -0
- lmcache/v1/api_server/__init__.py +2 -0
- lmcache/v1/api_server/__main__.py +537 -0
- lmcache/v1/basic_check.py +112 -0
- lmcache/v1/cache_controller/__init__.py +9 -0
- lmcache/v1/cache_controller/commands/__init__.py +15 -0
- lmcache/v1/cache_controller/commands/base.py +35 -0
- lmcache/v1/cache_controller/commands/full_sync.py +49 -0
- lmcache/v1/cache_controller/config.py +176 -0
- lmcache/v1/cache_controller/controller_manager.py +535 -0
- lmcache/v1/cache_controller/controllers/__init__.py +11 -0
- lmcache/v1/cache_controller/controllers/full_sync_tracker.py +473 -0
- lmcache/v1/cache_controller/controllers/kv_controller.py +439 -0
- lmcache/v1/cache_controller/controllers/registration_controller.py +282 -0
- lmcache/v1/cache_controller/executor.py +463 -0
- lmcache/v1/cache_controller/frontend/static/css/style.css +201 -0
- lmcache/v1/cache_controller/frontend/static/img/logo.png +0 -0
- lmcache/v1/cache_controller/frontend/static/index.html +234 -0
- lmcache/v1/cache_controller/frontend/static/js/controller_app.js +660 -0
- lmcache/v1/cache_controller/full_sync_sender.py +475 -0
- lmcache/v1/cache_controller/locks.py +149 -0
- lmcache/v1/cache_controller/message.py +828 -0
- lmcache/v1/cache_controller/observability.py +208 -0
- lmcache/v1/cache_controller/utils.py +679 -0
- lmcache/v1/cache_controller/worker.py +665 -0
- lmcache/v1/cache_engine.py +2058 -0
- lmcache/v1/cache_interface.py +19 -0
- lmcache/v1/check/__init__.py +74 -0
- lmcache/v1/check/check_mode_gen.py +86 -0
- lmcache/v1/check/check_mode_test_l2_adapter.py +284 -0
- lmcache/v1/check/check_mode_test_remote.py +155 -0
- lmcache/v1/check/check_mode_test_storage_manager.py +142 -0
- lmcache/v1/check/utils.py +571 -0
- lmcache/v1/compute/__init__.py +2 -0
- lmcache/v1/compute/attention/__init__.py +0 -0
- lmcache/v1/compute/attention/abstract.py +39 -0
- lmcache/v1/compute/attention/flash_attn.py +129 -0
- lmcache/v1/compute/attention/flash_infer_sparse.py +284 -0
- lmcache/v1/compute/attention/metadata.py +85 -0
- lmcache/v1/compute/attention/utils.py +14 -0
- lmcache/v1/compute/blend/__init__.py +7 -0
- lmcache/v1/compute/blend/blender.py +168 -0
- lmcache/v1/compute/blend/metadata.py +34 -0
- lmcache/v1/compute/blend/utils.py +63 -0
- lmcache/v1/compute/models/__init__.py +0 -0
- lmcache/v1/compute/models/base.py +141 -0
- lmcache/v1/compute/models/llama.py +9 -0
- lmcache/v1/compute/models/qwen3.py +24 -0
- lmcache/v1/compute/models/utils.py +68 -0
- lmcache/v1/compute/positional_encoding.py +199 -0
- lmcache/v1/config.py +848 -0
- lmcache/v1/config_base.py +848 -0
- lmcache/v1/distributed/api.py +248 -0
- lmcache/v1/distributed/config.py +321 -0
- lmcache/v1/distributed/error.py +64 -0
- lmcache/v1/distributed/eviction.py +192 -0
- lmcache/v1/distributed/eviction_policy/__init__.py +21 -0
- lmcache/v1/distributed/eviction_policy/factory.py +27 -0
- lmcache/v1/distributed/eviction_policy/lru.py +244 -0
- lmcache/v1/distributed/eviction_policy/noop.py +50 -0
- lmcache/v1/distributed/internal_api.py +170 -0
- lmcache/v1/distributed/l1_manager.py +835 -0
- lmcache/v1/distributed/l2_adapters/__init__.py +67 -0
- lmcache/v1/distributed/l2_adapters/base.py +360 -0
- lmcache/v1/distributed/l2_adapters/config.py +385 -0
- lmcache/v1/distributed/l2_adapters/factory.py +205 -0
- lmcache/v1/distributed/l2_adapters/fs_l2_adapter.py +747 -0
- lmcache/v1/distributed/l2_adapters/fs_native_l2_adapter.py +167 -0
- lmcache/v1/distributed/l2_adapters/mock_l2_adapter.py +516 -0
- lmcache/v1/distributed/l2_adapters/mooncake_store_l2_adapter.py +135 -0
- lmcache/v1/distributed/l2_adapters/native_connector_l2_adapter.py +468 -0
- lmcache/v1/distributed/l2_adapters/native_plugin_l2_adapter.py +199 -0
- lmcache/v1/distributed/l2_adapters/nixl_store_dynamic_l2_adapter.py +831 -0
- lmcache/v1/distributed/l2_adapters/nixl_store_l2_adapter.py +983 -0
- lmcache/v1/distributed/l2_adapters/plugin_l2_adapter.py +210 -0
- lmcache/v1/distributed/l2_adapters/resp_l2_adapter.py +176 -0
- lmcache/v1/distributed/memory_manager.py +179 -0
- lmcache/v1/distributed/storage_controller.py +39 -0
- lmcache/v1/distributed/storage_controllers/__init__.py +43 -0
- lmcache/v1/distributed/storage_controllers/eviction_controller.py +242 -0
- lmcache/v1/distributed/storage_controllers/prefetch_controller.py +830 -0
- lmcache/v1/distributed/storage_controllers/prefetch_policy.py +193 -0
- lmcache/v1/distributed/storage_controllers/store_controller.py +452 -0
- lmcache/v1/distributed/storage_controllers/store_policy.py +213 -0
- lmcache/v1/distributed/storage_manager.py +532 -0
- lmcache/v1/event_manager.py +145 -0
- lmcache/v1/exceptions/__init__.py +16 -0
- lmcache/v1/gpu_connector/__init__.py +126 -0
- lmcache/v1/gpu_connector/gpu_connectors.py +1906 -0
- lmcache/v1/gpu_connector/gpu_ops.py +85 -0
- lmcache/v1/gpu_connector/hpu_connector.py +326 -0
- lmcache/v1/gpu_connector/mock_gpu_connector.py +67 -0
- lmcache/v1/gpu_connector/utils.py +890 -0
- lmcache/v1/gpu_connector/xpu_connectors.py +916 -0
- lmcache/v1/health_monitor/__init__.py +1 -0
- lmcache/v1/health_monitor/base.py +587 -0
- lmcache/v1/health_monitor/checks/__init__.py +1 -0
- lmcache/v1/health_monitor/checks/remote_backend_check.py +304 -0
- lmcache/v1/health_monitor/constants.py +36 -0
- lmcache/v1/internal_api_server/__init__.py +0 -0
- lmcache/v1/internal_api_server/api_registry.py +59 -0
- lmcache/v1/internal_api_server/api_server.py +120 -0
- lmcache/v1/internal_api_server/common/__init__.py +1 -0
- lmcache/v1/internal_api_server/common/env_api.py +22 -0
- lmcache/v1/internal_api_server/common/loglevel_api.py +57 -0
- lmcache/v1/internal_api_server/common/metrics_api.py +29 -0
- lmcache/v1/internal_api_server/common/periodic_thread_api.py +138 -0
- lmcache/v1/internal_api_server/common/run_script_api.py +73 -0
- lmcache/v1/internal_api_server/common/thread_api.py +63 -0
- lmcache/v1/internal_api_server/controller/__init__.py +1 -0
- lmcache/v1/internal_api_server/controller/key_stats_api.py +81 -0
- lmcache/v1/internal_api_server/controller/worker_info_api.py +136 -0
- lmcache/v1/internal_api_server/utils.py +43 -0
- lmcache/v1/internal_api_server/vllm/__init__.py +1 -0
- lmcache/v1/internal_api_server/vllm/backend_api.py +221 -0
- lmcache/v1/internal_api_server/vllm/bypass_api.py +204 -0
- lmcache/v1/internal_api_server/vllm/cache_api.py +895 -0
- lmcache/v1/internal_api_server/vllm/chunk_statistics_api.py +141 -0
- lmcache/v1/internal_api_server/vllm/conf_api.py +147 -0
- lmcache/v1/internal_api_server/vllm/freeze_api.py +172 -0
- lmcache/v1/internal_api_server/vllm/hot_cache_api.py +184 -0
- lmcache/v1/internal_api_server/vllm/inference_api.py +65 -0
- lmcache/v1/internal_api_server/vllm/load_fs_chunks_api.py +320 -0
- lmcache/v1/internal_api_server/vllm/lookup_api.py +145 -0
- lmcache/v1/internal_api_server/vllm/version_api.py +25 -0
- lmcache/v1/kv_layer_groups.py +267 -0
- lmcache/v1/lazy_memory_allocator.py +284 -0
- lmcache/v1/lookup_client/__init__.py +25 -0
- lmcache/v1/lookup_client/abstract_client.py +77 -0
- lmcache/v1/lookup_client/async_lookup_message.py +50 -0
- lmcache/v1/lookup_client/chunk_statistics_lookup_client.py +200 -0
- lmcache/v1/lookup_client/factory.py +251 -0
- lmcache/v1/lookup_client/hit_limit_lookup_client.py +86 -0
- lmcache/v1/lookup_client/lmcache_async_lookup_client.py +407 -0
- lmcache/v1/lookup_client/lmcache_lookup_client.py +285 -0
- lmcache/v1/lookup_client/lmcache_lookup_client_bypass.py +99 -0
- lmcache/v1/lookup_client/mooncake_lookup_client.py +87 -0
- lmcache/v1/lookup_client/record_strategies/__init__.py +77 -0
- lmcache/v1/lookup_client/record_strategies/base.py +327 -0
- lmcache/v1/lookup_client/record_strategies/file_hash.py +130 -0
- lmcache/v1/lookup_client/record_strategies/memory_bloom_filter.py +81 -0
- lmcache/v1/manager.py +539 -0
- lmcache/v1/memory_management.py +2619 -0
- lmcache/v1/metadata.py +114 -0
- lmcache/v1/mp_observability/AGENTS.override.md +21 -0
- lmcache/v1/mp_observability/README.md +204 -0
- lmcache/v1/mp_observability/config.py +340 -0
- lmcache/v1/mp_observability/event.py +100 -0
- lmcache/v1/mp_observability/event_bus.py +313 -0
- lmcache/v1/mp_observability/otel_init.py +145 -0
- lmcache/v1/mp_observability/subscribers/__init__.py +28 -0
- lmcache/v1/mp_observability/subscribers/logging/__init__.py +19 -0
- lmcache/v1/mp_observability/subscribers/logging/l1.py +56 -0
- lmcache/v1/mp_observability/subscribers/logging/l2.py +73 -0
- lmcache/v1/mp_observability/subscribers/logging/lookup_hash.py +209 -0
- lmcache/v1/mp_observability/subscribers/logging/mp_server.py +90 -0
- lmcache/v1/mp_observability/subscribers/logging/sm.py +59 -0
- lmcache/v1/mp_observability/subscribers/metrics/__init__.py +20 -0
- lmcache/v1/mp_observability/subscribers/metrics/l0_lifecycle.py +290 -0
- lmcache/v1/mp_observability/subscribers/metrics/l1.py +55 -0
- lmcache/v1/mp_observability/subscribers/metrics/l1_lifecycle.py +166 -0
- lmcache/v1/mp_observability/subscribers/metrics/l2.py +121 -0
- lmcache/v1/mp_observability/subscribers/metrics/sm.py +69 -0
- lmcache/v1/mp_observability/subscribers/tracing/__init__.py +12 -0
- lmcache/v1/mp_observability/subscribers/tracing/mp_server.py +333 -0
- lmcache/v1/mp_observability/subscribers/tracing/span_registry.py +148 -0
- lmcache/v1/mp_observability/trace/__init__.py +50 -0
- lmcache/v1/mp_observability/trace/codecs.py +255 -0
- lmcache/v1/mp_observability/trace/decorator.py +147 -0
- lmcache/v1/mp_observability/trace/format.py +132 -0
- lmcache/v1/mp_observability/trace/lifecycle.py +83 -0
- lmcache/v1/mp_observability/trace/reader.py +167 -0
- lmcache/v1/mp_observability/trace/recorder.py +300 -0
- lmcache/v1/multiprocess/__init__.py +0 -0
- lmcache/v1/multiprocess/affinity_pool.py +102 -0
- lmcache/v1/multiprocess/blend_server_v2.py +891 -0
- lmcache/v1/multiprocess/config.py +253 -0
- lmcache/v1/multiprocess/custom_types.py +281 -0
- lmcache/v1/multiprocess/futures.py +194 -0
- lmcache/v1/multiprocess/gpu_context.py +511 -0
- lmcache/v1/multiprocess/http_server.py +235 -0
- lmcache/v1/multiprocess/mp_runtime_plugin_launcher.py +130 -0
- lmcache/v1/multiprocess/mq.py +732 -0
- lmcache/v1/multiprocess/protocol.py +86 -0
- lmcache/v1/multiprocess/protocols/README.md +213 -0
- lmcache/v1/multiprocess/protocols/__init__.py +127 -0
- lmcache/v1/multiprocess/protocols/base.py +89 -0
- lmcache/v1/multiprocess/protocols/blend.py +109 -0
- lmcache/v1/multiprocess/protocols/blend_v2.py +57 -0
- lmcache/v1/multiprocess/protocols/controller.py +53 -0
- lmcache/v1/multiprocess/protocols/debug.py +34 -0
- lmcache/v1/multiprocess/protocols/engine.py +146 -0
- lmcache/v1/multiprocess/protocols/observability.py +39 -0
- lmcache/v1/multiprocess/server.py +1134 -0
- lmcache/v1/multiprocess/session.py +190 -0
- lmcache/v1/multiprocess/token_hasher.py +441 -0
- lmcache/v1/offload_server/__init__.py +17 -0
- lmcache/v1/offload_server/abstract_server.py +37 -0
- lmcache/v1/offload_server/message.py +30 -0
- lmcache/v1/offload_server/zmq_server.py +122 -0
- lmcache/v1/periodic_thread.py +579 -0
- lmcache/v1/pin_monitor.py +246 -0
- lmcache/v1/plugin/__init__.py +0 -0
- lmcache/v1/plugin/runtime_plugin_launcher.py +211 -0
- lmcache/v1/protocol.py +317 -0
- lmcache/v1/rpc/__init__.py +17 -0
- lmcache/v1/rpc/transport.py +105 -0
- lmcache/v1/rpc/zmq_transport.py +213 -0
- lmcache/v1/rpc_utils.py +165 -0
- lmcache/v1/server/__init__.py +2 -0
- lmcache/v1/server/__main__.py +170 -0
- lmcache/v1/server/storage_backend/__init__.py +21 -0
- lmcache/v1/server/storage_backend/abstract_backend.py +80 -0
- lmcache/v1/server/storage_backend/local_backend.py +75 -0
- lmcache/v1/server/utils.py +21 -0
- lmcache/v1/standalone/__init__.py +1 -0
- lmcache/v1/standalone/__main__.py +583 -0
- lmcache/v1/standalone/manager.py +80 -0
- lmcache/v1/standalone/standalone_service_factory.py +86 -0
- lmcache/v1/storage_backend/__init__.py +313 -0
- lmcache/v1/storage_backend/abstract_backend.py +445 -0
- lmcache/v1/storage_backend/audit_backend.py +233 -0
- lmcache/v1/storage_backend/batched_message_sender.py +222 -0
- lmcache/v1/storage_backend/cache_policy/__init__.py +45 -0
- lmcache/v1/storage_backend/cache_policy/base_policy.py +87 -0
- lmcache/v1/storage_backend/cache_policy/fifo.py +58 -0
- lmcache/v1/storage_backend/cache_policy/lfu.py +105 -0
- lmcache/v1/storage_backend/cache_policy/lru.py +81 -0
- lmcache/v1/storage_backend/cache_policy/mru.py +61 -0
- lmcache/v1/storage_backend/connector/__init__.py +443 -0
- lmcache/v1/storage_backend/connector/audit_adapter.py +77 -0
- lmcache/v1/storage_backend/connector/audit_connector.py +320 -0
- lmcache/v1/storage_backend/connector/base_connector.py +379 -0
- lmcache/v1/storage_backend/connector/blackhole_adapter.py +21 -0
- lmcache/v1/storage_backend/connector/blackhole_connector.py +37 -0
- lmcache/v1/storage_backend/connector/eic_adapter.py +31 -0
- lmcache/v1/storage_backend/connector/eic_connector.py +757 -0
- lmcache/v1/storage_backend/connector/external_adapter.py +79 -0
- lmcache/v1/storage_backend/connector/fs_adapter.py +51 -0
- lmcache/v1/storage_backend/connector/fs_connector.py +403 -0
- lmcache/v1/storage_backend/connector/infinistore_adapter.py +56 -0
- lmcache/v1/storage_backend/connector/infinistore_connector.py +177 -0
- lmcache/v1/storage_backend/connector/instrumented_connector.py +219 -0
- lmcache/v1/storage_backend/connector/lm_adapter.py +31 -0
- lmcache/v1/storage_backend/connector/lm_connector.py +176 -0
- lmcache/v1/storage_backend/connector/mock_adapter.py +57 -0
- lmcache/v1/storage_backend/connector/mock_connector.py +349 -0
- lmcache/v1/storage_backend/connector/mooncakestore_adapter.py +43 -0
- lmcache/v1/storage_backend/connector/mooncakestore_connector.py +614 -0
- lmcache/v1/storage_backend/connector/redis_adapter.py +181 -0
- lmcache/v1/storage_backend/connector/redis_connector.py +828 -0
- lmcache/v1/storage_backend/connector/s3_adapter.py +59 -0
- lmcache/v1/storage_backend/connector/s3_connector.py +699 -0
- lmcache/v1/storage_backend/connector/sagemaker_hyperpod_adapter.py +233 -0
- lmcache/v1/storage_backend/connector/sagemaker_hyperpod_connector.py +987 -0
- lmcache/v1/storage_backend/connector/valkey_adapter.py +114 -0
- lmcache/v1/storage_backend/connector/valkey_connector.py +627 -0
- lmcache/v1/storage_backend/gds_backend.py +1199 -0
- lmcache/v1/storage_backend/job_executor/__init__.py +0 -0
- lmcache/v1/storage_backend/job_executor/base_executor.py +34 -0
- lmcache/v1/storage_backend/job_executor/pq_executor.py +235 -0
- lmcache/v1/storage_backend/local_cpu_backend.py +810 -0
- lmcache/v1/storage_backend/local_disk_backend.py +656 -0
- lmcache/v1/storage_backend/maru_backend.py +734 -0
- lmcache/v1/storage_backend/naive_serde/__init__.py +50 -0
- lmcache/v1/storage_backend/naive_serde/cachegen_basics.py +133 -0
- lmcache/v1/storage_backend/naive_serde/cachegen_decoder.py +135 -0
- lmcache/v1/storage_backend/naive_serde/cachegen_encoder.py +83 -0
- lmcache/v1/storage_backend/naive_serde/kivi_serde.py +22 -0
- lmcache/v1/storage_backend/naive_serde/naive_serde.py +18 -0
- lmcache/v1/storage_backend/naive_serde/serde.py +37 -0
- lmcache/v1/storage_backend/native_clients/connector_client_base.py +165 -0
- lmcache/v1/storage_backend/native_clients/resp_client.py +35 -0
- lmcache/v1/storage_backend/nixl_storage_backend.py +1400 -0
- lmcache/v1/storage_backend/p2p_backend.py +788 -0
- lmcache/v1/storage_backend/path_sharder.py +117 -0
- lmcache/v1/storage_backend/pd_backend.py +646 -0
- lmcache/v1/storage_backend/plugins/dax_backend.py +1443 -0
- lmcache/v1/storage_backend/plugins/rust_raw_block_backend.py +1361 -0
- lmcache/v1/storage_backend/remote_backend.py +624 -0
- lmcache/v1/storage_backend/resp_client.py +227 -0
- lmcache/v1/storage_backend/storage_backend_listener.py +19 -0
- lmcache/v1/storage_backend/storage_manager.py +1352 -0
- lmcache/v1/system_detection.py +110 -0
- lmcache/v1/token_database.py +551 -0
- lmcache/v1/transfer_channel/__init__.py +83 -0
- lmcache/v1/transfer_channel/abstract.py +285 -0
- lmcache/v1/transfer_channel/mock_memory_channel.py +156 -0
- lmcache/v1/transfer_channel/nixl_channel.py +639 -0
- lmcache/v1/transfer_channel/py_socket_channel.py +260 -0
- lmcache/v1/transfer_channel/transfer_utils.py +63 -0
- lmcache/v1/utils/__init__.py +1 -0
- lmcache/v1/utils/bloom_filter.py +109 -0
- lmcache/v1/utils/cache_utils.py +125 -0
- lmcache_cli-0.4.5.dev0.dist-info/METADATA +185 -0
- lmcache_cli-0.4.5.dev0.dist-info/RECORD +399 -0
- lmcache_cli-0.4.5.dev0.dist-info/WHEEL +5 -0
- lmcache_cli-0.4.5.dev0.dist-info/entry_points.txt +2 -0
- lmcache_cli-0.4.5.dev0.dist-info/licenses/LICENSE +201 -0
- lmcache_cli-0.4.5.dev0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
from enum import IntEnum, auto
|
|
4
|
+
from typing import List, Optional, Union, no_type_check
|
|
5
|
+
import asyncio
|
|
6
|
+
import ctypes
|
|
7
|
+
import os
|
|
8
|
+
import random
|
|
9
|
+
import string
|
|
10
|
+
import time
|
|
11
|
+
|
|
12
|
+
# Third Party
|
|
13
|
+
import eic
|
|
14
|
+
import yaml
|
|
15
|
+
|
|
16
|
+
# First Party
|
|
17
|
+
from lmcache.logging import init_logger
|
|
18
|
+
from lmcache.utils import CacheEngineKey, _lmcache_nvtx_annotate
|
|
19
|
+
from lmcache.v1.memory_management import MemoryObj, MixedMemoryAllocator
|
|
20
|
+
from lmcache.v1.protocol import RemoteMetadata
|
|
21
|
+
from lmcache.v1.storage_backend.connector.base_connector import RemoteConnector
|
|
22
|
+
from lmcache.v1.storage_backend.job_executor.pq_executor import AsyncPQExecutor
|
|
23
|
+
from lmcache.v1.storage_backend.local_cpu_backend import LocalCPUBackend
|
|
24
|
+
|
|
25
|
+
logger = init_logger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Priorities(IntEnum):
|
|
29
|
+
PEEK = auto()
|
|
30
|
+
PREFETCH = auto()
|
|
31
|
+
GET = auto()
|
|
32
|
+
PUT = auto()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class PerformanceTimer:
|
|
36
|
+
def __init__(self, key, op):
|
|
37
|
+
self.key = key
|
|
38
|
+
self.size = 0
|
|
39
|
+
self.op = op
|
|
40
|
+
self.start_times = {}
|
|
41
|
+
self.elapsed_times = {}
|
|
42
|
+
|
|
43
|
+
def set_size(self, size):
|
|
44
|
+
self.size = size
|
|
45
|
+
|
|
46
|
+
def start(self, operation_name):
|
|
47
|
+
self.start_times[operation_name] = time.perf_counter()
|
|
48
|
+
|
|
49
|
+
# unit: us
|
|
50
|
+
def stop(self, operation_name):
|
|
51
|
+
if operation_name not in self.start_times:
|
|
52
|
+
raise ValueError(f"operation {operation_name} not found")
|
|
53
|
+
|
|
54
|
+
end_time = time.perf_counter()
|
|
55
|
+
start_time = self.start_times[operation_name]
|
|
56
|
+
elapsed_time = end_time - start_time
|
|
57
|
+
self.elapsed_times[operation_name] = elapsed_time * 1000000
|
|
58
|
+
del self.start_times[operation_name]
|
|
59
|
+
return elapsed_time
|
|
60
|
+
|
|
61
|
+
def get_elapsed_time(self, operation_name):
|
|
62
|
+
return self.elapsed_times.get(operation_name)
|
|
63
|
+
|
|
64
|
+
def get_all_elapsed_times(self):
|
|
65
|
+
return self.elapsed_times
|
|
66
|
+
|
|
67
|
+
def debug_all_elapsed_times(self):
|
|
68
|
+
logger.debug(f"== Perf key:{self.key} =========")
|
|
69
|
+
logger.debug(f"== Perf op {self.op} size {self.size} =========")
|
|
70
|
+
for op, item in self.elapsed_times.items():
|
|
71
|
+
logger.debug(f"Step: {op} cost {item:.2f} us")
|
|
72
|
+
logger.debug(f"== Perf op {self.op} size {self.size} =========")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class FlexibleDRAMMemoryPool:
|
|
76
|
+
def __init__(self, conn):
|
|
77
|
+
self._init = False
|
|
78
|
+
self.connection = conn
|
|
79
|
+
self.used_mem = {}
|
|
80
|
+
|
|
81
|
+
def allocate(self, size):
|
|
82
|
+
ptr = self.connection.allocate_managed_buffer(size)
|
|
83
|
+
if ptr == 0:
|
|
84
|
+
logger.error(f"fail to allocate dram pool, ptr {ptr}, size {size}")
|
|
85
|
+
return ptr
|
|
86
|
+
logger.debug(f"allocate dram pool: ptr {ptr}, size {size}")
|
|
87
|
+
self.used_mem[ptr] = size
|
|
88
|
+
return ptr
|
|
89
|
+
|
|
90
|
+
def deallocate(self, ptr):
|
|
91
|
+
size = self.used_mem.get(ptr)
|
|
92
|
+
if size is not None:
|
|
93
|
+
logger.debug(f"deallocate dram pool: ptr {ptr}, size {size}")
|
|
94
|
+
self.connection.free_managed_buffer(ptr, size)
|
|
95
|
+
del self.used_mem[ptr]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _make_dir(path: str):
|
|
99
|
+
try:
|
|
100
|
+
if not os.path.exists(path):
|
|
101
|
+
os.makedirs(path)
|
|
102
|
+
logger.info(f"create dir '{path}' success")
|
|
103
|
+
except OSError as e:
|
|
104
|
+
logger.error(f"create dir '{path}' error {e}")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class EICConnector(RemoteConnector):
|
|
108
|
+
"""
|
|
109
|
+
The remote url should start with "eic://" and only have one host-port pair
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
def __init__(
|
|
113
|
+
self,
|
|
114
|
+
endpoint: str,
|
|
115
|
+
loop: asyncio.AbstractEventLoop,
|
|
116
|
+
memory_allocator: LocalCPUBackend,
|
|
117
|
+
):
|
|
118
|
+
# initialize base class, which includes some common attributes
|
|
119
|
+
super().__init__(memory_allocator.config, memory_allocator.metadata)
|
|
120
|
+
|
|
121
|
+
logger.info("init EICConnector")
|
|
122
|
+
logger.info(f"try connect to eic: {endpoint}")
|
|
123
|
+
|
|
124
|
+
self.loop = loop
|
|
125
|
+
self.memory_allocator = memory_allocator
|
|
126
|
+
|
|
127
|
+
# Initialize pq_executor early to avoid AttributeError
|
|
128
|
+
try:
|
|
129
|
+
self.pq_executor = AsyncPQExecutor(loop)
|
|
130
|
+
logger.info("AsyncPQExecutor initialized successfully")
|
|
131
|
+
except Exception as e:
|
|
132
|
+
logger.error(f"Failed to initialize AsyncPQExecutor: {e}")
|
|
133
|
+
raise
|
|
134
|
+
|
|
135
|
+
self.cudaError_t = ctypes.c_int
|
|
136
|
+
self.cudaMemcpyDeviceToHost = 2
|
|
137
|
+
self.cudaMemcpyHostToDevice = 1
|
|
138
|
+
self.cuda_lib = ctypes.CDLL("libcudart.so")
|
|
139
|
+
self.cuda_lib.cudaMemcpy.argtypes = [
|
|
140
|
+
ctypes.c_void_p,
|
|
141
|
+
ctypes.c_void_p,
|
|
142
|
+
ctypes.c_size_t,
|
|
143
|
+
ctypes.c_int,
|
|
144
|
+
]
|
|
145
|
+
self.cuda_lib.cudaMemcpy.restype = self.cudaError_t
|
|
146
|
+
|
|
147
|
+
self.enable_compare = False
|
|
148
|
+
|
|
149
|
+
config_file = os.getenv("LMCACHE_CONFIG_FILE")
|
|
150
|
+
if config_file is None:
|
|
151
|
+
raise ValueError("LMCACHE_CONFIG_FILE environment variable is not set")
|
|
152
|
+
with open(config_file, "r") as fin:
|
|
153
|
+
config = yaml.safe_load(fin)
|
|
154
|
+
|
|
155
|
+
remote_url = config.get("remote_url", None)
|
|
156
|
+
logger.info(f"eic remote_url: {remote_url}")
|
|
157
|
+
|
|
158
|
+
eic_instance_id = config.get("eic_instance_id", None)
|
|
159
|
+
logger.info(f"eic instance_id: {eic_instance_id}")
|
|
160
|
+
|
|
161
|
+
eic_thread_num = config.get("eic_thread_num", 6)
|
|
162
|
+
logger.info(f"eic thread_num: {eic_thread_num}")
|
|
163
|
+
|
|
164
|
+
eic_log_dir = config.get("eic_log_dir", None)
|
|
165
|
+
logger.info(f"eic log_dir: {eic_log_dir}")
|
|
166
|
+
|
|
167
|
+
eic_log_level = config.get("eic_log_level", 1)
|
|
168
|
+
logger.info(f"eic log_level: {eic_log_level}")
|
|
169
|
+
|
|
170
|
+
eic_trans_type = config.get("eic_trans_type", 3)
|
|
171
|
+
logger.info(f"eic trans_type: {eic_trans_type}")
|
|
172
|
+
|
|
173
|
+
self.eic_kv_ttl = config.get("eic_kv_ttl", -1)
|
|
174
|
+
logger.info(f"eic eic_kv_ttl: {self.eic_kv_ttl}")
|
|
175
|
+
|
|
176
|
+
self.eic_kv_ns = config.get("eic_kv_ns", "")
|
|
177
|
+
logger.info(f"eic eic_kv_ns: {self.eic_kv_ns}")
|
|
178
|
+
|
|
179
|
+
eic_flag_file = config.get("eic_flag_file", None)
|
|
180
|
+
logger.info(f"eic flag_file: {eic_flag_file}")
|
|
181
|
+
|
|
182
|
+
_make_dir(eic_log_dir)
|
|
183
|
+
|
|
184
|
+
self.connection = eic.Client()
|
|
185
|
+
init_option = eic.InitOption()
|
|
186
|
+
init_option.log_dir = eic_log_dir
|
|
187
|
+
init_option.log_level = eic.LogLevel(eic_log_level)
|
|
188
|
+
init_option.transport_type = eic.TransportType(eic_trans_type)
|
|
189
|
+
init_option.flag_file = eic_flag_file
|
|
190
|
+
endpoint = endpoint.removeprefix("eic://").removesuffix("/")
|
|
191
|
+
ret = self.connection.init(eic_instance_id, endpoint, init_option)
|
|
192
|
+
if ret != 0:
|
|
193
|
+
logger.error(f"fail to init eic client, ret: {ret}")
|
|
194
|
+
raise RuntimeError(
|
|
195
|
+
f"Failed to initialize eic client with error code: {ret}"
|
|
196
|
+
)
|
|
197
|
+
else:
|
|
198
|
+
logger.info(f"init eic client success, ret: {ret}")
|
|
199
|
+
|
|
200
|
+
self.trans_type = eic.TransportType(eic_trans_type)
|
|
201
|
+
|
|
202
|
+
# Register memory in rdma and gdr scenarios
|
|
203
|
+
if self.trans_type == eic.TransportType.TRANSPORT_GDR:
|
|
204
|
+
if not isinstance(self.memory_allocator, LocalCPUBackend):
|
|
205
|
+
raise RuntimeError("memory_allocator must be LocalCPUBackend")
|
|
206
|
+
allocator = self.memory_allocator.memory_allocator
|
|
207
|
+
if not isinstance(allocator, MixedMemoryAllocator):
|
|
208
|
+
raise RuntimeError(
|
|
209
|
+
"memory_allocator.memory_allocator must be MixedMemoryAllocator"
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
if hasattr(allocator, "pin_allocator") and hasattr(
|
|
213
|
+
allocator.pin_allocator, "buffer"
|
|
214
|
+
):
|
|
215
|
+
mem_pool = allocator.pin_allocator.buffer
|
|
216
|
+
meminfo = eic.MemoryInfo()
|
|
217
|
+
meminfo.type = eic.MemoryType.MEMORY_CUDA
|
|
218
|
+
meminfo.cuda_id = 0
|
|
219
|
+
|
|
220
|
+
vals = eic.IOBuffers()
|
|
221
|
+
vals.append(
|
|
222
|
+
mem_pool.data_ptr(),
|
|
223
|
+
mem_pool.numel() * mem_pool.element_size(),
|
|
224
|
+
True,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
if self.connection.register_memory(vals, meminfo):
|
|
228
|
+
logger.info("register mixed memory pin buffer success")
|
|
229
|
+
else:
|
|
230
|
+
logger.error("fail to register mixed memory pin buffer")
|
|
231
|
+
exit(1)
|
|
232
|
+
else:
|
|
233
|
+
logger.error("mixed memory pin buffer is None")
|
|
234
|
+
exit(1)
|
|
235
|
+
self.prebuilt_connection()
|
|
236
|
+
|
|
237
|
+
def prebuilt_connection(self) -> None:
|
|
238
|
+
def random_string(N):
|
|
239
|
+
return self.eic_kv_ns.join(
|
|
240
|
+
random.choices(string.ascii_uppercase + string.digits, k=N)
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
try:
|
|
244
|
+
for i in range(2048):
|
|
245
|
+
key = random_string(30)
|
|
246
|
+
self._exists_sync(key)
|
|
247
|
+
logger.info("eic prebuilt connection finish")
|
|
248
|
+
except Exception as e:
|
|
249
|
+
logger.error(f"Error in prebuilt connection thread: {e}")
|
|
250
|
+
|
|
251
|
+
def delete_sync(self, key: str) -> bool:
|
|
252
|
+
keys = eic.StringVector()
|
|
253
|
+
keys.append(key)
|
|
254
|
+
status_code, _ = self.connection.mdel(keys)
|
|
255
|
+
if status_code != eic.StatusCode.SUCCESS:
|
|
256
|
+
logger.debug(f"eic delete {key} failed, status_code {status_code}")
|
|
257
|
+
return False
|
|
258
|
+
return True
|
|
259
|
+
|
|
260
|
+
def _exists_sync(self, key_str: str) -> bool:
|
|
261
|
+
keys = eic.StringVector()
|
|
262
|
+
keys.append(key_str)
|
|
263
|
+
exist_option = eic.ExistOption()
|
|
264
|
+
status_code, exist_outcome = self.connection.mexist(keys, exist_option)
|
|
265
|
+
if status_code != eic.StatusCode.SUCCESS:
|
|
266
|
+
logger.debug(f"eic exists {key_str} failed, status_code {status_code}")
|
|
267
|
+
return False
|
|
268
|
+
|
|
269
|
+
err_code = exist_outcome.status_codes[0]
|
|
270
|
+
success = err_code == eic.StatusCode.SUCCESS
|
|
271
|
+
if success:
|
|
272
|
+
logger.debug(f"eic exists {key_str} success")
|
|
273
|
+
else:
|
|
274
|
+
logger.debug(
|
|
275
|
+
f"eic exists {key_str} failed, status_code {status_code} "
|
|
276
|
+
"err_code {err_code}"
|
|
277
|
+
)
|
|
278
|
+
return success
|
|
279
|
+
|
|
280
|
+
async def _exists(self, key: CacheEngineKey) -> bool:
|
|
281
|
+
return self._exists_sync(key.to_string())
|
|
282
|
+
|
|
283
|
+
async def exists(self, key: CacheEngineKey) -> bool:
|
|
284
|
+
if not hasattr(self, "pq_executor") or self.pq_executor is None:
|
|
285
|
+
logger.error("pq_executor is not initialized in EICConnector")
|
|
286
|
+
raise AttributeError("pq_executor is not initialized")
|
|
287
|
+
|
|
288
|
+
return await self.pq_executor.submit_job(
|
|
289
|
+
self._exists, key=key, priority=Priorities.PEEK
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
def exists_sync(self, key: CacheEngineKey) -> bool:
|
|
293
|
+
return self._exists_sync(key.to_string())
|
|
294
|
+
|
|
295
|
+
async def get_meta(self, key_str: str) -> Optional[RemoteMetadata]:
|
|
296
|
+
perf_timer = PerformanceTimer(key_str, "get_meta")
|
|
297
|
+
perf_timer.start("total_cost")
|
|
298
|
+
|
|
299
|
+
# Get Meta: generate meta keys and vals
|
|
300
|
+
meta_keys = eic.StringVector()
|
|
301
|
+
meta_vals = eic.IOBuffers()
|
|
302
|
+
|
|
303
|
+
# Get Meta: generate meta buffer tensor
|
|
304
|
+
perf_timer.start("alloc_mem")
|
|
305
|
+
meta_key = key_str + "_meta"
|
|
306
|
+
meta_size = self.remote_metadata_bytes
|
|
307
|
+
meta_bytes = bytearray(meta_size)
|
|
308
|
+
meta_bytes_ptr = self.bytes_get_ptr(meta_bytes)
|
|
309
|
+
|
|
310
|
+
meta_keys.append(meta_key)
|
|
311
|
+
meta_vals.append(meta_bytes_ptr, meta_size, False)
|
|
312
|
+
|
|
313
|
+
perf_timer.set_size(meta_size)
|
|
314
|
+
perf_timer.stop("alloc_mem")
|
|
315
|
+
|
|
316
|
+
# Get Meta: recv meta buffer tensor
|
|
317
|
+
perf_timer.start("eic_mget")
|
|
318
|
+
get_option = eic.GetOption()
|
|
319
|
+
get_option.ns = self.eic_kv_ns
|
|
320
|
+
status_code, meta_vals, get_outcome = self.connection.mget(
|
|
321
|
+
meta_keys, get_option, meta_vals
|
|
322
|
+
)
|
|
323
|
+
err_code = get_outcome.status_codes[0]
|
|
324
|
+
if status_code != eic.StatusCode.SUCCESS or err_code != eic.StatusCode.SUCCESS:
|
|
325
|
+
if err_code == eic.StatusCode.KEY_NOT_EXIST:
|
|
326
|
+
logger.debug(
|
|
327
|
+
f"eic mget meta {key_str} failed, status_code {status_code}"
|
|
328
|
+
" err_code {err_code}"
|
|
329
|
+
)
|
|
330
|
+
else:
|
|
331
|
+
logger.error(
|
|
332
|
+
f"eic mget meta {key_str} failed, status_code {status_code}"
|
|
333
|
+
" err_code {err_code}"
|
|
334
|
+
)
|
|
335
|
+
return None
|
|
336
|
+
else:
|
|
337
|
+
logger.debug(f"eic mget meta {key_str} success")
|
|
338
|
+
|
|
339
|
+
perf_timer.stop("eic_mget")
|
|
340
|
+
|
|
341
|
+
perf_timer.start("serialize")
|
|
342
|
+
meta = RemoteMetadata.deserialize(meta_bytes[:meta_size])
|
|
343
|
+
perf_timer.stop("serialize")
|
|
344
|
+
|
|
345
|
+
perf_timer.stop("total_cost")
|
|
346
|
+
perf_timer.debug_all_elapsed_times()
|
|
347
|
+
|
|
348
|
+
return meta
|
|
349
|
+
|
|
350
|
+
async def get_data(self, key_str: str, meta: RemoteMetadata) -> Optional[MemoryObj]:
|
|
351
|
+
perf_timer = PerformanceTimer(key_str, "get_data")
|
|
352
|
+
perf_timer.start("total_cost")
|
|
353
|
+
perf_timer.start("alloc_obj")
|
|
354
|
+
memory_obj = self.memory_allocator.allocate(
|
|
355
|
+
meta.shapes,
|
|
356
|
+
meta.dtypes,
|
|
357
|
+
meta.fmt,
|
|
358
|
+
)
|
|
359
|
+
if memory_obj is None:
|
|
360
|
+
logger.error(
|
|
361
|
+
f"fail to allocate memory during remote receive key {key_str} length"
|
|
362
|
+
" {meta.length}"
|
|
363
|
+
)
|
|
364
|
+
return None
|
|
365
|
+
perf_timer.stop("alloc_obj")
|
|
366
|
+
|
|
367
|
+
perf_timer.start("alloc_mem")
|
|
368
|
+
obj_size = memory_obj.get_size()
|
|
369
|
+
data_ptr = memory_obj.tensor.data_ptr()
|
|
370
|
+
data_keys = eic.StringVector()
|
|
371
|
+
data_vals = eic.IOBuffers()
|
|
372
|
+
data_keys.append(key_str)
|
|
373
|
+
|
|
374
|
+
perf_timer.set_size(obj_size)
|
|
375
|
+
perf_timer.stop("alloc_mem")
|
|
376
|
+
|
|
377
|
+
try:
|
|
378
|
+
if self.trans_type == eic.TransportType.TRANSPORT_GDR:
|
|
379
|
+
data_vals.append(data_ptr, obj_size, True)
|
|
380
|
+
else:
|
|
381
|
+
data_vals.append(data_ptr, obj_size, False)
|
|
382
|
+
|
|
383
|
+
perf_timer.start("eic_mget")
|
|
384
|
+
get_option = eic.GetOption()
|
|
385
|
+
get_option.ns = self.eic_kv_ns
|
|
386
|
+
status_code, data_vals, get_outcome = self.connection.mget(
|
|
387
|
+
data_keys, get_option, data_vals
|
|
388
|
+
)
|
|
389
|
+
err_code = get_outcome.status_codes[0]
|
|
390
|
+
if (
|
|
391
|
+
status_code != eic.StatusCode.SUCCESS
|
|
392
|
+
or err_code != eic.StatusCode.SUCCESS
|
|
393
|
+
):
|
|
394
|
+
logger.error(
|
|
395
|
+
f"eic mget data {key_str} failed, status_code {status_code} "
|
|
396
|
+
f"err_code {err_code}"
|
|
397
|
+
)
|
|
398
|
+
memory_obj.ref_count_down()
|
|
399
|
+
return None
|
|
400
|
+
else:
|
|
401
|
+
logger.debug(f"eic mget data {key_str} success")
|
|
402
|
+
except Exception as e:
|
|
403
|
+
logger.error(
|
|
404
|
+
f"eic mget data {key_str} raised exception: {e}", exc_info=True
|
|
405
|
+
)
|
|
406
|
+
memory_obj.ref_count_down()
|
|
407
|
+
return None
|
|
408
|
+
|
|
409
|
+
perf_timer.stop("eic_mget")
|
|
410
|
+
|
|
411
|
+
perf_timer.stop("total_cost")
|
|
412
|
+
perf_timer.debug_all_elapsed_times()
|
|
413
|
+
|
|
414
|
+
return memory_obj
|
|
415
|
+
|
|
416
|
+
async def _get(self, key: CacheEngineKey) -> Optional[MemoryObj]:
|
|
417
|
+
key_str = key.to_string()
|
|
418
|
+
meta = await self.get_meta(key_str)
|
|
419
|
+
if meta is None:
|
|
420
|
+
return None
|
|
421
|
+
data = await self.get_data(key_str, meta)
|
|
422
|
+
return data
|
|
423
|
+
|
|
424
|
+
@_lmcache_nvtx_annotate
|
|
425
|
+
async def get(self, key: CacheEngineKey) -> Optional[MemoryObj]:
|
|
426
|
+
if not hasattr(self, "pq_executor") or self.pq_executor is None:
|
|
427
|
+
logger.error("pq_executor is not initialized in EICConnector")
|
|
428
|
+
raise AttributeError("pq_executor is not initialized")
|
|
429
|
+
|
|
430
|
+
return await self.pq_executor.submit_job(
|
|
431
|
+
self._get, key=key, priority=Priorities.GET
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
def bytes_get_ptr(self, mv: Union[bytearray, memoryview, bytes]) -> int:
|
|
435
|
+
if isinstance(mv, bytes):
|
|
436
|
+
pointer = ctypes.cast(ctypes.c_char_p(mv), ctypes.POINTER(ctypes.c_char))
|
|
437
|
+
ptr = ctypes.addressof(pointer.contents)
|
|
438
|
+
return ptr
|
|
439
|
+
return ctypes.addressof(ctypes.c_char.from_buffer(mv))
|
|
440
|
+
|
|
441
|
+
async def _put(self, key: CacheEngineKey, memory_obj: MemoryObj):
|
|
442
|
+
return self._put_sync(key, memory_obj)
|
|
443
|
+
|
|
444
|
+
def _put_sync(self, key: CacheEngineKey, memory_obj: MemoryObj):
|
|
445
|
+
key_str = key.to_string()
|
|
446
|
+
logger.debug(f"eic put {key_str}")
|
|
447
|
+
|
|
448
|
+
perf_timer = PerformanceTimer(key_str, "put_data")
|
|
449
|
+
perf_timer.start("total_cost")
|
|
450
|
+
kv_bytes = memory_obj.byte_array
|
|
451
|
+
kv_tensor = memory_obj.tensor
|
|
452
|
+
kv_shapes = memory_obj.get_shapes()
|
|
453
|
+
kv_dtypes = memory_obj.get_dtypes()
|
|
454
|
+
memory_format = memory_obj.get_memory_format()
|
|
455
|
+
value_size = memory_obj.get_physical_size()
|
|
456
|
+
|
|
457
|
+
logger.debug(
|
|
458
|
+
f"eic put {key_str} data len {len(kv_bytes)} value_size {value_size}"
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
if kv_tensor is None:
|
|
462
|
+
logger.error(f"Memory object tensor is None for key {key_str}")
|
|
463
|
+
return
|
|
464
|
+
|
|
465
|
+
perf_timer.start("serialize")
|
|
466
|
+
|
|
467
|
+
# generate meta bytes
|
|
468
|
+
remote_meta = RemoteMetadata(
|
|
469
|
+
self.remote_metadata_bytes, kv_shapes, kv_dtypes, memory_format
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
logger.debug(f"eic meta {key_str} remote_meta{remote_meta}")
|
|
473
|
+
|
|
474
|
+
meta_bytes = remote_meta.serialize()
|
|
475
|
+
|
|
476
|
+
perf_timer.stop("serialize")
|
|
477
|
+
|
|
478
|
+
perf_timer.start("trans_address")
|
|
479
|
+
# generate meta & data ptr
|
|
480
|
+
meta_ptr = self.bytes_get_ptr(meta_bytes)
|
|
481
|
+
meta_size = len(meta_bytes)
|
|
482
|
+
data_ptr = kv_tensor.data_ptr()
|
|
483
|
+
data_size = len(kv_bytes)
|
|
484
|
+
perf_timer.set_size(data_size)
|
|
485
|
+
perf_timer.stop("trans_address")
|
|
486
|
+
|
|
487
|
+
logger.debug(
|
|
488
|
+
f"eic put {key_str} meta ptr {meta_ptr} len {meta_size} data ptr {data_ptr}"
|
|
489
|
+
" len {data_size}"
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
perf_timer.start("eic_mset")
|
|
493
|
+
keys = eic.StringVector()
|
|
494
|
+
vals = eic.IOBuffers()
|
|
495
|
+
|
|
496
|
+
# set meta key & value
|
|
497
|
+
meta_key = key_str + "_meta"
|
|
498
|
+
keys.append(meta_key)
|
|
499
|
+
vals.append(meta_ptr, meta_size, False)
|
|
500
|
+
|
|
501
|
+
# set data key & value
|
|
502
|
+
keys.append(key_str)
|
|
503
|
+
if self.trans_type == eic.TransportType.TRANSPORT_GDR:
|
|
504
|
+
vals.append(data_ptr, data_size, True)
|
|
505
|
+
else:
|
|
506
|
+
vals.append(data_ptr, data_size, False)
|
|
507
|
+
|
|
508
|
+
# set options
|
|
509
|
+
set_option = eic.SetOption()
|
|
510
|
+
set_option.ns = self.eic_kv_ns
|
|
511
|
+
set_option.ttl_second = self.eic_kv_ttl
|
|
512
|
+
|
|
513
|
+
status_code, set_outcome = self.connection.mset(keys, vals, set_option)
|
|
514
|
+
if status_code != eic.StatusCode.SUCCESS:
|
|
515
|
+
logger.error(f"eic mset {key_str} failed, status_code {status_code}")
|
|
516
|
+
|
|
517
|
+
err_code = set_outcome.status_codes[0]
|
|
518
|
+
if err_code == eic.StatusCode.SUCCESS:
|
|
519
|
+
logger.debug(f"eic put meta key {meta_key} success")
|
|
520
|
+
else:
|
|
521
|
+
logger.error(f"eic put meta key {meta_key} failed, err_code {err_code}")
|
|
522
|
+
|
|
523
|
+
err_code = set_outcome.status_codes[1]
|
|
524
|
+
if err_code == eic.StatusCode.SUCCESS:
|
|
525
|
+
logger.debug(f"eic put data key {key_str} success")
|
|
526
|
+
else:
|
|
527
|
+
logger.error(f"eic put data key {key_str} failed, err_code {err_code}")
|
|
528
|
+
|
|
529
|
+
perf_timer.stop("eic_mset")
|
|
530
|
+
perf_timer.stop("total_cost")
|
|
531
|
+
perf_timer.debug_all_elapsed_times()
|
|
532
|
+
|
|
533
|
+
async def _batched_put(
|
|
534
|
+
self, keys: List[CacheEngineKey], memory_objs: List[MemoryObj]
|
|
535
|
+
):
|
|
536
|
+
if not keys or not memory_objs:
|
|
537
|
+
return
|
|
538
|
+
|
|
539
|
+
# Prepare all keys and values for batch mset
|
|
540
|
+
eic_keys = eic.StringVector()
|
|
541
|
+
eic_vals = eic.IOBuffers()
|
|
542
|
+
# Keep references to meta_bytes to prevent dangling pointers
|
|
543
|
+
meta_list = []
|
|
544
|
+
for key, memory_obj in zip(keys, memory_objs, strict=False):
|
|
545
|
+
key_str = key.to_string()
|
|
546
|
+
logger.debug(f"eic batched_put processing {key_str}")
|
|
547
|
+
|
|
548
|
+
# Get memory object data
|
|
549
|
+
kv_bytes = memory_obj.byte_array
|
|
550
|
+
kv_tensor = memory_obj.tensor
|
|
551
|
+
kv_shapes = memory_obj.get_shapes()
|
|
552
|
+
kv_dtypes = memory_obj.get_dtypes()
|
|
553
|
+
memory_format = memory_obj.get_memory_format()
|
|
554
|
+
if kv_tensor is None:
|
|
555
|
+
logger.error(f"Memory object tensor is None for key {key_str}")
|
|
556
|
+
return
|
|
557
|
+
|
|
558
|
+
remote_meta = RemoteMetadata(
|
|
559
|
+
self.remote_metadata_bytes, kv_shapes, kv_dtypes, memory_format
|
|
560
|
+
)
|
|
561
|
+
meta_bytes = remote_meta.serialize()
|
|
562
|
+
meta_list.append(meta_bytes)
|
|
563
|
+
meta_ptr = self.bytes_get_ptr(meta_bytes)
|
|
564
|
+
meta_size = len(meta_bytes)
|
|
565
|
+
data_ptr = kv_tensor.data_ptr()
|
|
566
|
+
data_size = len(kv_bytes)
|
|
567
|
+
|
|
568
|
+
logger.info(
|
|
569
|
+
"eic batched_put %s, shapes: %s, dtypes: %s, fmt: %s",
|
|
570
|
+
key_str,
|
|
571
|
+
kv_shapes,
|
|
572
|
+
kv_dtypes,
|
|
573
|
+
memory_format,
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
# Add meta key & value
|
|
577
|
+
meta_key = key_str + "_meta"
|
|
578
|
+
eic_keys.append(meta_key)
|
|
579
|
+
eic_vals.append(meta_ptr, meta_size, False)
|
|
580
|
+
# Add data key & value
|
|
581
|
+
eic_keys.append(key_str)
|
|
582
|
+
if self.trans_type == eic.TransportType.TRANSPORT_GDR:
|
|
583
|
+
eic_vals.append(data_ptr, data_size, True)
|
|
584
|
+
else:
|
|
585
|
+
eic_vals.append(data_ptr, data_size, False)
|
|
586
|
+
|
|
587
|
+
set_option = eic.SetOption()
|
|
588
|
+
set_option.ns = self.eic_kv_ns
|
|
589
|
+
set_option.ttl_second = self.eic_kv_ttl
|
|
590
|
+
|
|
591
|
+
set_status_code, set_outcome = self.connection.mset(
|
|
592
|
+
eic_keys, eic_vals, set_option
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
if set_status_code != eic.StatusCode.SUCCESS:
|
|
596
|
+
logger.error(
|
|
597
|
+
f"eic batched_put mset data failed, status_code {set_status_code}"
|
|
598
|
+
)
|
|
599
|
+
return
|
|
600
|
+
for i, key_str in enumerate(eic_keys):
|
|
601
|
+
meta_key = key_str + "_meta"
|
|
602
|
+
|
|
603
|
+
outcome_err_code = set_outcome.status_codes[i]
|
|
604
|
+
log_key = meta_key if i % 2 == 0 else key_str
|
|
605
|
+
if outcome_err_code == eic.StatusCode.SUCCESS:
|
|
606
|
+
logger.debug(f"eic batched_put {log_key} success")
|
|
607
|
+
else:
|
|
608
|
+
logger.error(
|
|
609
|
+
f"eic batched_put {log_key} failed, err_code {outcome_err_code}"
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
async def put(self, key: CacheEngineKey, memory_obj: MemoryObj):
|
|
613
|
+
if not hasattr(self, "pq_executor") or self.pq_executor is None:
|
|
614
|
+
logger.error("pq_executor is not initialized in EICConnector")
|
|
615
|
+
raise AttributeError("pq_executor is not initialized")
|
|
616
|
+
|
|
617
|
+
return await self.pq_executor.submit_job(
|
|
618
|
+
self._put, key=key, memory_obj=memory_obj, priority=Priorities.PUT
|
|
619
|
+
)
|
|
620
|
+
|
|
621
|
+
def support_batched_put(self) -> bool:
|
|
622
|
+
return False
|
|
623
|
+
|
|
624
|
+
async def batched_put(
|
|
625
|
+
self, keys: List[CacheEngineKey], memory_objs: List[MemoryObj]
|
|
626
|
+
):
|
|
627
|
+
if not hasattr(self, "pq_executor") or self.pq_executor is None:
|
|
628
|
+
logger.error("pq_executor is not initialized in EICConnector")
|
|
629
|
+
raise AttributeError("pq_executor is not initialized")
|
|
630
|
+
|
|
631
|
+
await self.pq_executor.submit_job(
|
|
632
|
+
self._batched_put,
|
|
633
|
+
keys=keys,
|
|
634
|
+
memory_objs=memory_objs,
|
|
635
|
+
priority=Priorities.PUT,
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
def support_batched_async_contains(self) -> bool:
|
|
639
|
+
return True
|
|
640
|
+
|
|
641
|
+
async def _batched_async_contains(
|
|
642
|
+
self,
|
|
643
|
+
lookup_id: str,
|
|
644
|
+
keys: List[CacheEngineKey],
|
|
645
|
+
pin: bool = False,
|
|
646
|
+
) -> int:
|
|
647
|
+
if not keys:
|
|
648
|
+
return 0
|
|
649
|
+
|
|
650
|
+
# Convert all keys to strings at once
|
|
651
|
+
key_strings = eic.StringVector()
|
|
652
|
+
for key in keys:
|
|
653
|
+
key_strings.append(key.to_string())
|
|
654
|
+
|
|
655
|
+
# Use mexist to check all keys at once
|
|
656
|
+
exist_option = eic.ExistOption()
|
|
657
|
+
status_code, exist_outcome = self.connection.mexist(key_strings, exist_option)
|
|
658
|
+
|
|
659
|
+
if status_code != eic.StatusCode.SUCCESS:
|
|
660
|
+
logger.error(
|
|
661
|
+
f"eic batched_async_contains mexist failed, status_code {status_code}"
|
|
662
|
+
)
|
|
663
|
+
return 0
|
|
664
|
+
|
|
665
|
+
# Count consecutive hits from the beginning
|
|
666
|
+
num_hit_counts = 0
|
|
667
|
+
for i, key in enumerate(keys):
|
|
668
|
+
status_code = exist_outcome.status_codes[i]
|
|
669
|
+
if status_code != eic.StatusCode.SUCCESS:
|
|
670
|
+
logger.debug(
|
|
671
|
+
f"eic batched_async_contains {key.to_string()} miss,"
|
|
672
|
+
" err_code {status_code}"
|
|
673
|
+
)
|
|
674
|
+
break
|
|
675
|
+
num_hit_counts += 1
|
|
676
|
+
return num_hit_counts
|
|
677
|
+
|
|
678
|
+
async def batched_async_contains(
|
|
679
|
+
self,
|
|
680
|
+
lookup_id: str,
|
|
681
|
+
keys: List[CacheEngineKey],
|
|
682
|
+
pin: bool = False,
|
|
683
|
+
) -> int:
|
|
684
|
+
if not hasattr(self, "pq_executor") or self.pq_executor is None:
|
|
685
|
+
logger.error("pq_executor is not initialized in EICConnector")
|
|
686
|
+
raise AttributeError("pq_executor is not initialized")
|
|
687
|
+
|
|
688
|
+
return await self.pq_executor.submit_job(
|
|
689
|
+
self._batched_async_contains,
|
|
690
|
+
lookup_id=lookup_id,
|
|
691
|
+
keys=keys,
|
|
692
|
+
pin=pin,
|
|
693
|
+
priority=Priorities.PEEK,
|
|
694
|
+
)
|
|
695
|
+
|
|
696
|
+
def support_batched_get(self) -> bool:
|
|
697
|
+
return True
|
|
698
|
+
|
|
699
|
+
async def _batched_get(
|
|
700
|
+
self, keys: List[CacheEngineKey]
|
|
701
|
+
) -> List[Optional[MemoryObj]]:
|
|
702
|
+
# calling self.get will create a circular dependency
|
|
703
|
+
results = await asyncio.gather(*(self._get(key) for key in keys))
|
|
704
|
+
return results
|
|
705
|
+
|
|
706
|
+
async def batched_get(
|
|
707
|
+
self, keys: List[CacheEngineKey]
|
|
708
|
+
) -> List[Optional[MemoryObj]]:
|
|
709
|
+
if not hasattr(self, "pq_executor") or self.pq_executor is None:
|
|
710
|
+
logger.error("pq_executor is not initialized in EICConnector")
|
|
711
|
+
raise AttributeError("pq_executor is not initialized")
|
|
712
|
+
|
|
713
|
+
return await self.pq_executor.submit_job(
|
|
714
|
+
self._batched_get,
|
|
715
|
+
keys=keys,
|
|
716
|
+
priority=Priorities.GET,
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
def support_batched_get_non_blocking(self) -> bool:
|
|
720
|
+
return True
|
|
721
|
+
|
|
722
|
+
async def _batched_get_non_blocking(
|
|
723
|
+
self,
|
|
724
|
+
lookup_id: str,
|
|
725
|
+
keys: List[CacheEngineKey],
|
|
726
|
+
) -> List[MemoryObj]:
|
|
727
|
+
# calling self.get will create a circular dependency
|
|
728
|
+
results = await asyncio.gather(*(self._get(key) for key in keys))
|
|
729
|
+
return [r for r in results if r is not None]
|
|
730
|
+
|
|
731
|
+
async def batched_get_non_blocking(
|
|
732
|
+
self,
|
|
733
|
+
lookup_id: str,
|
|
734
|
+
keys: List[CacheEngineKey],
|
|
735
|
+
) -> List[MemoryObj]:
|
|
736
|
+
if not hasattr(self, "pq_executor") or self.pq_executor is None:
|
|
737
|
+
logger.error("pq_executor is not initialized in EICConnector")
|
|
738
|
+
raise AttributeError("pq_executor is not initialized")
|
|
739
|
+
|
|
740
|
+
return await self.pq_executor.submit_job(
|
|
741
|
+
self._batched_get_non_blocking,
|
|
742
|
+
lookup_id=lookup_id,
|
|
743
|
+
keys=keys,
|
|
744
|
+
priority=Priorities.PREFETCH,
|
|
745
|
+
)
|
|
746
|
+
|
|
747
|
+
async def close(self):
|
|
748
|
+
if hasattr(self, "pq_executor") and self.pq_executor is not None:
|
|
749
|
+
await self.pq_executor.shutdown(wait=True)
|
|
750
|
+
if self.connection:
|
|
751
|
+
self.connection = None
|
|
752
|
+
logger.info("closed the eic connection")
|
|
753
|
+
|
|
754
|
+
# TODO
|
|
755
|
+
@no_type_check
|
|
756
|
+
async def list(self) -> List[str]:
|
|
757
|
+
pass
|