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
lmcache/utils.py
ADDED
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Future
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
# Standard
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import TYPE_CHECKING, Any, List, Optional, Tuple, Union
|
|
9
|
+
import asyncio
|
|
10
|
+
import hashlib
|
|
11
|
+
import re
|
|
12
|
+
import threading
|
|
13
|
+
import traceback
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
# Third Party
|
|
17
|
+
from nvtx import annotate # type: ignore
|
|
18
|
+
except ImportError:
|
|
19
|
+
|
|
20
|
+
def annotate(*args, **kwargs):
|
|
21
|
+
"""Dummy decorator when nvtx is not available."""
|
|
22
|
+
|
|
23
|
+
def decorator(func):
|
|
24
|
+
return func
|
|
25
|
+
|
|
26
|
+
return decorator
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Third Party
|
|
30
|
+
import torch
|
|
31
|
+
|
|
32
|
+
# First Party
|
|
33
|
+
from lmcache.logging import init_logger
|
|
34
|
+
|
|
35
|
+
if TYPE_CHECKING:
|
|
36
|
+
# First Party
|
|
37
|
+
from lmcache.v1.memory_management import MemoryFormat
|
|
38
|
+
|
|
39
|
+
logger = init_logger(__name__)
|
|
40
|
+
|
|
41
|
+
# Type definition
|
|
42
|
+
KVCache = Tuple[Tuple[torch.Tensor, torch.Tensor], ...]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# Math utility functions
|
|
46
|
+
def cdiv(a: int, b: int) -> int:
|
|
47
|
+
"""Ceiling division."""
|
|
48
|
+
return -(a // -b)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def round_down(x: int, y: int) -> int:
|
|
52
|
+
"""Round down x to the nearest multiple of y."""
|
|
53
|
+
return (x // y) * y
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def compress_slot_mapping(slots: list[int]) -> list[Union[int, list[int]]]:
|
|
57
|
+
"""Compress a list of slot indices into ranges while preserving order.
|
|
58
|
+
|
|
59
|
+
Consecutive slots (3 or more) are represented as [start, end] ranges.
|
|
60
|
+
Single elements or pairs are kept as individual integers.
|
|
61
|
+
For example: [1, 2, 3, 4, 5, 9, 10, 11, 12] -> [[1, 5], [9, 12]]
|
|
62
|
+
Order-preserving: [5, 3, 1, 2, 4] -> [5, 3, 1, 2, 4] (no compression)
|
|
63
|
+
Mixed: [1, 2, 3, 4, 5, 7, 8] -> [[1, 5], 7, 8]
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
slots: List of slot indices (order is preserved).
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
List of integers or [start, end] ranges. Ranges are only used
|
|
70
|
+
when there are 3 or more consecutive elements.
|
|
71
|
+
"""
|
|
72
|
+
if not slots:
|
|
73
|
+
return []
|
|
74
|
+
|
|
75
|
+
result: list[Union[int, list[int]]] = []
|
|
76
|
+
range_start = slots[0]
|
|
77
|
+
range_end = slots[0]
|
|
78
|
+
|
|
79
|
+
for slot in slots[1:]:
|
|
80
|
+
if slot == range_end + 1:
|
|
81
|
+
# Extend current range
|
|
82
|
+
range_end = slot
|
|
83
|
+
else:
|
|
84
|
+
# Close current range and start a new one
|
|
85
|
+
_append_range_or_elements(result, range_start, range_end)
|
|
86
|
+
range_start = slot
|
|
87
|
+
range_end = slot
|
|
88
|
+
|
|
89
|
+
# Append the last range
|
|
90
|
+
_append_range_or_elements(result, range_start, range_end)
|
|
91
|
+
return result
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _append_range_or_elements(
|
|
95
|
+
result: list[Union[int, list[int]]], start: int, end: int
|
|
96
|
+
) -> None:
|
|
97
|
+
"""Helper to append range or individual elements based on length.
|
|
98
|
+
|
|
99
|
+
Only compresses to [start, end] if there are 3 or more consecutive elements.
|
|
100
|
+
"""
|
|
101
|
+
length = end - start + 1
|
|
102
|
+
if length >= 3:
|
|
103
|
+
# Compress: 3 or more consecutive elements
|
|
104
|
+
result.append([start, end])
|
|
105
|
+
else:
|
|
106
|
+
# Don't compress: 1 or 2 elements
|
|
107
|
+
for i in range(start, end + 1):
|
|
108
|
+
result.append(i)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def decompress_slot_mapping(compressed: list[Union[int, list[int]]]) -> list[int]:
|
|
112
|
+
"""Decompress slot ranges back to a list of slot indices.
|
|
113
|
+
|
|
114
|
+
Inverse operation of compress_slot_mapping.
|
|
115
|
+
For example: [[1, 5], [9, 12]] -> [1, 2, 3, 4, 5, 9, 10, 11, 12]
|
|
116
|
+
Mixed: [[1, 5], 7, 8] -> [1, 2, 3, 4, 5, 7, 8]
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
compressed: List of integers or [start, end] ranges from
|
|
120
|
+
compress_slot_mapping.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
List of slot indices.
|
|
124
|
+
"""
|
|
125
|
+
slots: list[int] = []
|
|
126
|
+
for item in compressed:
|
|
127
|
+
if isinstance(item, list):
|
|
128
|
+
start, end = item
|
|
129
|
+
slots.extend(range(start, end + 1))
|
|
130
|
+
else:
|
|
131
|
+
slots.append(item)
|
|
132
|
+
return slots
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def parse_mixed_slot_mapping(
|
|
136
|
+
slot_mapping_str: str,
|
|
137
|
+
) -> Tuple[Optional[list[int]], Optional[dict]]:
|
|
138
|
+
"""Parse mixed format slot_mapping string.
|
|
139
|
+
|
|
140
|
+
Supports two formats:
|
|
141
|
+
1. Single numbers: "1,2,3,17,19"
|
|
142
|
+
2. Range format: "[9,12]" (represents 9,10,11,12)
|
|
143
|
+
3. Mixed format: "1,2,3,[9,12],17,19" (represents 1,2,3,9,10,11,12,17,19)
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
slot_mapping_str: String containing slot mapping information.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
Tuple of (slot_indices list, error dict).
|
|
150
|
+
If error dict is not None, slot_indices will be None.
|
|
151
|
+
"""
|
|
152
|
+
try:
|
|
153
|
+
# Remove all whitespace
|
|
154
|
+
clean_str = "".join(slot_mapping_str.split())
|
|
155
|
+
|
|
156
|
+
# Split by comma but preserve range expressions
|
|
157
|
+
parts = []
|
|
158
|
+
buffer = ""
|
|
159
|
+
in_brackets = False
|
|
160
|
+
|
|
161
|
+
for char in clean_str:
|
|
162
|
+
if char == "[":
|
|
163
|
+
if in_brackets:
|
|
164
|
+
raise ValueError("Nested brackets not allowed")
|
|
165
|
+
in_brackets = True
|
|
166
|
+
buffer += char
|
|
167
|
+
elif char == "]":
|
|
168
|
+
if not in_brackets:
|
|
169
|
+
raise ValueError("Unmatched closing bracket")
|
|
170
|
+
in_brackets = False
|
|
171
|
+
buffer += char
|
|
172
|
+
parts.append(buffer)
|
|
173
|
+
buffer = ""
|
|
174
|
+
elif char == "," and not in_brackets:
|
|
175
|
+
if buffer:
|
|
176
|
+
parts.append(buffer)
|
|
177
|
+
buffer = ""
|
|
178
|
+
else:
|
|
179
|
+
buffer += char
|
|
180
|
+
|
|
181
|
+
# Add the last part if any
|
|
182
|
+
if buffer:
|
|
183
|
+
parts.append(buffer)
|
|
184
|
+
|
|
185
|
+
if in_brackets:
|
|
186
|
+
raise ValueError("Unclosed bracket")
|
|
187
|
+
|
|
188
|
+
# Parse each part
|
|
189
|
+
compressed: list[Union[int, list[int]]] = []
|
|
190
|
+
|
|
191
|
+
for part in parts:
|
|
192
|
+
part = part.strip()
|
|
193
|
+
if not part:
|
|
194
|
+
continue
|
|
195
|
+
|
|
196
|
+
# Check if it's a range format [start,end]
|
|
197
|
+
range_match = re.match(r"^\[(\d+),(\d+)\]$", part)
|
|
198
|
+
if range_match:
|
|
199
|
+
start = int(range_match.group(1))
|
|
200
|
+
end = int(range_match.group(2))
|
|
201
|
+
if start > end:
|
|
202
|
+
raise ValueError(f"Range start {start} must be <= end {end}")
|
|
203
|
+
compressed.append([start, end])
|
|
204
|
+
else:
|
|
205
|
+
# Single number
|
|
206
|
+
try:
|
|
207
|
+
num = int(part)
|
|
208
|
+
compressed.append(num)
|
|
209
|
+
except ValueError as ve:
|
|
210
|
+
raise ValueError(f"Invalid slot format: '{part}'") from ve
|
|
211
|
+
|
|
212
|
+
# Decompress to individual slot indices
|
|
213
|
+
slot_indices = decompress_slot_mapping(compressed)
|
|
214
|
+
return slot_indices, None
|
|
215
|
+
|
|
216
|
+
except Exception as e:
|
|
217
|
+
return None, {
|
|
218
|
+
"error": "Invalid slot_mapping format",
|
|
219
|
+
"message": (
|
|
220
|
+
f"slot_mapping must be comma-separated integers "
|
|
221
|
+
f"or ranges like [start,end]: {str(e)}"
|
|
222
|
+
),
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
try:
|
|
227
|
+
# First Party
|
|
228
|
+
from lmcache import _version # type: ignore[attr-defined]
|
|
229
|
+
|
|
230
|
+
VERSION = getattr(_version, "__version__", "")
|
|
231
|
+
COMMIT_ID = getattr(_version, "__commit_id__", "")
|
|
232
|
+
except ImportError:
|
|
233
|
+
VERSION = ""
|
|
234
|
+
COMMIT_ID = ""
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def get_version():
|
|
238
|
+
version_display = VERSION if VERSION else "NA"
|
|
239
|
+
commit_id_display = COMMIT_ID if COMMIT_ID else "NA"
|
|
240
|
+
return f"{version_display}-{commit_id_display}"
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def convert_tokens_to_list(
|
|
244
|
+
tokens: Optional[Union[torch.Tensor, list[int]]], token_start: int, token_end: int
|
|
245
|
+
) -> List[int]:
|
|
246
|
+
"""Convert tokens to a list.
|
|
247
|
+
token_start and token_end delineate tokens to convert"""
|
|
248
|
+
if tokens is None:
|
|
249
|
+
return []
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
tokens.tolist()[token_start : token_end + 1]
|
|
253
|
+
if isinstance(tokens, torch.Tensor)
|
|
254
|
+
else tokens[token_start : token_end + 1]
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
@dataclass
|
|
259
|
+
class DiskCacheMetadata:
|
|
260
|
+
path: str
|
|
261
|
+
size: int # in bytes
|
|
262
|
+
shape: Optional[torch.Size] = None
|
|
263
|
+
dtype: Optional[torch.dtype] = None
|
|
264
|
+
cached_positions: Optional[torch.Tensor] = None
|
|
265
|
+
fmt: Optional[MemoryFormat] = None
|
|
266
|
+
pin_count: int = 0
|
|
267
|
+
|
|
268
|
+
def pin(self) -> bool:
|
|
269
|
+
self.pin_count += 1
|
|
270
|
+
return True
|
|
271
|
+
|
|
272
|
+
def unpin(self) -> bool:
|
|
273
|
+
self.pin_count -= 1
|
|
274
|
+
return True
|
|
275
|
+
|
|
276
|
+
@property
|
|
277
|
+
def is_pinned(self) -> bool:
|
|
278
|
+
return self.pin_count > 0
|
|
279
|
+
|
|
280
|
+
@property
|
|
281
|
+
def can_evict(self) -> bool:
|
|
282
|
+
"""
|
|
283
|
+
Check if the disk cache can be evicted.
|
|
284
|
+
"""
|
|
285
|
+
return not self.is_pinned
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
TORCH_DTYPE_TO_STR_DTYPE = {
|
|
289
|
+
torch.half: "half",
|
|
290
|
+
torch.float16: "half",
|
|
291
|
+
torch.bfloat16: "bfloat16",
|
|
292
|
+
torch.float: "float",
|
|
293
|
+
torch.float32: "float",
|
|
294
|
+
torch.double: "double",
|
|
295
|
+
torch.float64: "double",
|
|
296
|
+
torch.int8: "int8",
|
|
297
|
+
torch.uint8: "uint8",
|
|
298
|
+
torch.int16: "int16",
|
|
299
|
+
torch.int32: "int32",
|
|
300
|
+
torch.int64: "int64",
|
|
301
|
+
torch.bool: "bool",
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
# FP8 variants (PyTorch ≥2.1)
|
|
305
|
+
if hasattr(torch, "float8_e4m3fn"):
|
|
306
|
+
TORCH_DTYPE_TO_STR_DTYPE[torch.float8_e4m3fn] = "fp8_e4m3fn"
|
|
307
|
+
if hasattr(torch, "float8_e4m3fnuz"):
|
|
308
|
+
TORCH_DTYPE_TO_STR_DTYPE[torch.float8_e4m3fnuz] = "fp8_e4m3fnuz"
|
|
309
|
+
if hasattr(torch, "float8_e5m2"):
|
|
310
|
+
TORCH_DTYPE_TO_STR_DTYPE[torch.float8_e5m2] = "fp8_e5m2"
|
|
311
|
+
if hasattr(torch, "float8_e5m2fnuz"):
|
|
312
|
+
TORCH_DTYPE_TO_STR_DTYPE[torch.float8_e5m2fnuz] = "fp8_e5m2fnuz"
|
|
313
|
+
|
|
314
|
+
STR_DTYPE_TO_TORCH_DTYPE = {v: k for k, v in TORCH_DTYPE_TO_STR_DTYPE.items()}
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def parse_cache_key(key_str: str) -> Union[CacheEngineKey, LayerCacheEngineKey]:
|
|
318
|
+
"""Parse a key string into either a CacheEngineKey or LayerCacheEngineKey.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
key_str: String in format:
|
|
322
|
+
CacheEngineKey:
|
|
323
|
+
model_name@world_size@worker_id@chunk_hash@dtype[@tag%value...]
|
|
324
|
+
LayerCacheEngineKey:
|
|
325
|
+
model_name@world_size@worker_id@chunk_hash@dtype@layer_id[@tag%value...]
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
CacheEngineKey if no layer_id, LayerCacheEngineKey if valid layer_id
|
|
329
|
+
"""
|
|
330
|
+
parts = key_str.strip().split("@")
|
|
331
|
+
# parts[0]=model, [1]=world_size, [2]=worker_id, [3]=chunk_hash, [4]=dtype
|
|
332
|
+
# parts[5]=layer_id OR tag%value
|
|
333
|
+
# If parts[5] exists and is a digit (not containing '%'), it's a LayerCacheEngineKey
|
|
334
|
+
if len(parts) >= 6 and parts[5].isdigit():
|
|
335
|
+
return LayerCacheEngineKey.from_string(key_str)
|
|
336
|
+
return CacheEngineKey.from_string(key_str)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
@dataclass(slots=True)
|
|
340
|
+
class CacheEngineKey:
|
|
341
|
+
model_name: str
|
|
342
|
+
world_size: int
|
|
343
|
+
worker_id: int
|
|
344
|
+
chunk_hash: int
|
|
345
|
+
dtype: torch.dtype
|
|
346
|
+
request_configs: Optional[dict] = field(default_factory=dict)
|
|
347
|
+
tags: Optional[tuple] = field(init=False, default=None)
|
|
348
|
+
_dtype_str: str = field(init=False, default="")
|
|
349
|
+
|
|
350
|
+
def __post_init__(self):
|
|
351
|
+
tag_list = None
|
|
352
|
+
if self.request_configs is not None:
|
|
353
|
+
for k, v in self.request_configs.items():
|
|
354
|
+
if k.startswith("lmcache.tag."):
|
|
355
|
+
if tag_list is None:
|
|
356
|
+
tag_list = []
|
|
357
|
+
tag_list.append((k[len("lmcache.tag.") :], v))
|
|
358
|
+
if self.dtype not in TORCH_DTYPE_TO_STR_DTYPE:
|
|
359
|
+
raise ValueError(f"Unsupported dtype in CacheEngineKey: {self.dtype}")
|
|
360
|
+
self._dtype_str = TORCH_DTYPE_TO_STR_DTYPE[self.dtype]
|
|
361
|
+
# use tuple to save tags
|
|
362
|
+
self.tags = None if tag_list is None else tuple(tag_list)
|
|
363
|
+
|
|
364
|
+
def __hash__(self):
|
|
365
|
+
return hash(
|
|
366
|
+
(
|
|
367
|
+
self.model_name,
|
|
368
|
+
self.world_size,
|
|
369
|
+
self.worker_id,
|
|
370
|
+
self.chunk_hash,
|
|
371
|
+
self._dtype_str,
|
|
372
|
+
self.tags,
|
|
373
|
+
)
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
def __eq__(self, other):
|
|
377
|
+
if type(self) is type(other):
|
|
378
|
+
return (
|
|
379
|
+
self.model_name == other.model_name
|
|
380
|
+
and self.world_size == other.world_size
|
|
381
|
+
and self.worker_id == other.worker_id
|
|
382
|
+
and self.chunk_hash == other.chunk_hash
|
|
383
|
+
and self.dtype == other.dtype
|
|
384
|
+
and self.tags == other.tags
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
return False
|
|
388
|
+
|
|
389
|
+
def to_string(self):
|
|
390
|
+
s = (
|
|
391
|
+
f"{self.model_name}@{self.world_size}"
|
|
392
|
+
f"@{self.worker_id}@{self.chunk_hash_hex}@{self._dtype_str}"
|
|
393
|
+
)
|
|
394
|
+
if self.tags is not None and len(self.tags) != 0:
|
|
395
|
+
tags = [f"{k}%{v}" for k, v in self.tags]
|
|
396
|
+
s += "@" + "@".join(tags)
|
|
397
|
+
return s
|
|
398
|
+
|
|
399
|
+
def split_layers(self, num_layers: int) -> List["LayerCacheEngineKey"]:
|
|
400
|
+
"""Split the key into multiple keys for each layer"""
|
|
401
|
+
keys = []
|
|
402
|
+
for layer_id in range(num_layers):
|
|
403
|
+
keys.append(
|
|
404
|
+
LayerCacheEngineKey(
|
|
405
|
+
model_name=self.model_name,
|
|
406
|
+
world_size=self.world_size,
|
|
407
|
+
worker_id=self.worker_id,
|
|
408
|
+
chunk_hash=self.chunk_hash,
|
|
409
|
+
dtype=self.dtype,
|
|
410
|
+
request_configs=self.request_configs,
|
|
411
|
+
layer_id=layer_id,
|
|
412
|
+
)
|
|
413
|
+
)
|
|
414
|
+
return keys
|
|
415
|
+
|
|
416
|
+
def get_first_layer(self) -> "LayerCacheEngineKey":
|
|
417
|
+
"""Return the key for the first layer"""
|
|
418
|
+
key = LayerCacheEngineKey(
|
|
419
|
+
model_name=self.model_name,
|
|
420
|
+
world_size=self.world_size,
|
|
421
|
+
worker_id=self.worker_id,
|
|
422
|
+
chunk_hash=self.chunk_hash,
|
|
423
|
+
dtype=self.dtype,
|
|
424
|
+
request_configs=self.request_configs,
|
|
425
|
+
layer_id=0,
|
|
426
|
+
)
|
|
427
|
+
return key
|
|
428
|
+
|
|
429
|
+
@staticmethod
|
|
430
|
+
def from_string(s):
|
|
431
|
+
parts = s.split("@")
|
|
432
|
+
if len(parts) < 5:
|
|
433
|
+
raise ValueError(f"Invalid key string: {s}")
|
|
434
|
+
request_configs = None
|
|
435
|
+
if len(parts) >= 6:
|
|
436
|
+
request_configs = {}
|
|
437
|
+
for kv in parts[5:]:
|
|
438
|
+
kvs = kv.split("%", 1)
|
|
439
|
+
if len(kvs) != 2:
|
|
440
|
+
raise ValueError(f"Invalid key string: {s}")
|
|
441
|
+
request_configs["lmcache.tag." + kvs[0]] = kvs[1]
|
|
442
|
+
return CacheEngineKey(
|
|
443
|
+
model_name=parts[0],
|
|
444
|
+
world_size=int(parts[1]),
|
|
445
|
+
worker_id=int(parts[2]),
|
|
446
|
+
chunk_hash=int(parts[3], 16),
|
|
447
|
+
dtype=STR_DTYPE_TO_TORCH_DTYPE[parts[4]],
|
|
448
|
+
request_configs=request_configs,
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
def to_dict(self):
|
|
452
|
+
# Note(Kuntai): this is used for serializing CacheEngineKey via msgpack.
|
|
453
|
+
msg = {
|
|
454
|
+
"__type__": "CacheEngineKey",
|
|
455
|
+
"model_name": self.model_name,
|
|
456
|
+
"world_size": self.world_size,
|
|
457
|
+
"worker_id": self.worker_id,
|
|
458
|
+
"chunk_hash": self.chunk_hash,
|
|
459
|
+
"dtype": self._dtype_str,
|
|
460
|
+
}
|
|
461
|
+
if self.request_configs is not None and len(self.request_configs) != 0:
|
|
462
|
+
msg["request_configs"] = [
|
|
463
|
+
f"{k}%{v}" for k, v in self.request_configs.items()
|
|
464
|
+
]
|
|
465
|
+
return msg
|
|
466
|
+
|
|
467
|
+
@staticmethod
|
|
468
|
+
def from_dict(d):
|
|
469
|
+
request_configs = None
|
|
470
|
+
if request_configs_list := d.get("request_configs"):
|
|
471
|
+
request_configs = {}
|
|
472
|
+
for kv in request_configs_list:
|
|
473
|
+
kvs = kv.split("%", 1)
|
|
474
|
+
if len(kvs) != 2:
|
|
475
|
+
raise ValueError(f"Invalid key dict: {d}")
|
|
476
|
+
request_configs[kvs[0]] = kvs[1]
|
|
477
|
+
return CacheEngineKey(
|
|
478
|
+
model_name=d["model_name"],
|
|
479
|
+
world_size=d["world_size"],
|
|
480
|
+
worker_id=d["worker_id"],
|
|
481
|
+
chunk_hash=d["chunk_hash"],
|
|
482
|
+
dtype=STR_DTYPE_TO_TORCH_DTYPE[d["dtype"]],
|
|
483
|
+
request_configs=request_configs,
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
def with_new_worker_id(self, new_worker_id: int) -> "CacheEngineKey":
|
|
487
|
+
# Reconstruct the cache engine key with new worker id
|
|
488
|
+
return CacheEngineKey(
|
|
489
|
+
self.model_name,
|
|
490
|
+
world_size=self.world_size,
|
|
491
|
+
worker_id=new_worker_id,
|
|
492
|
+
chunk_hash=self.chunk_hash,
|
|
493
|
+
dtype=self.dtype,
|
|
494
|
+
request_configs=self.request_configs,
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
@property
|
|
498
|
+
def chunk_hash_hex(self) -> str:
|
|
499
|
+
if isinstance(self.chunk_hash, bytes):
|
|
500
|
+
return self.chunk_hash.hex()
|
|
501
|
+
return f"{self.chunk_hash:x}"
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
@dataclass(slots=True)
|
|
505
|
+
class LayerCacheEngineKey(CacheEngineKey):
|
|
506
|
+
"""A key for the layer cache engine"""
|
|
507
|
+
|
|
508
|
+
layer_id: int = 0
|
|
509
|
+
|
|
510
|
+
def __hash__(self):
|
|
511
|
+
return hash(
|
|
512
|
+
(
|
|
513
|
+
self.model_name,
|
|
514
|
+
self.world_size,
|
|
515
|
+
self.worker_id,
|
|
516
|
+
self.chunk_hash,
|
|
517
|
+
self._dtype_str,
|
|
518
|
+
self.tags,
|
|
519
|
+
self.layer_id,
|
|
520
|
+
)
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
def __eq__(self, other):
|
|
524
|
+
if super(LayerCacheEngineKey, self).__eq__(other):
|
|
525
|
+
return self.layer_id == other.layer_id
|
|
526
|
+
|
|
527
|
+
return False
|
|
528
|
+
|
|
529
|
+
def to_string(self):
|
|
530
|
+
s = (
|
|
531
|
+
f"{self.model_name}@{self.world_size}"
|
|
532
|
+
f"@{self.worker_id}@{self.chunk_hash_hex}@{self._dtype_str}@{self.layer_id}"
|
|
533
|
+
)
|
|
534
|
+
if self.tags is not None and len(self.tags) != 0:
|
|
535
|
+
tags = [f"{k}%{v}" for k, v in self.tags]
|
|
536
|
+
s += "@" + "@".join(tags)
|
|
537
|
+
return s
|
|
538
|
+
|
|
539
|
+
def split_layers(self, num_layers: int) -> List["LayerCacheEngineKey"]:
|
|
540
|
+
"""Split the key into multiple keys for each layer"""
|
|
541
|
+
keys = []
|
|
542
|
+
for layer_id in range(num_layers):
|
|
543
|
+
keys.append(
|
|
544
|
+
LayerCacheEngineKey(
|
|
545
|
+
model_name=self.model_name,
|
|
546
|
+
world_size=self.world_size,
|
|
547
|
+
worker_id=self.worker_id,
|
|
548
|
+
chunk_hash=self.chunk_hash,
|
|
549
|
+
dtype=self.dtype,
|
|
550
|
+
request_configs=self.request_configs,
|
|
551
|
+
layer_id=layer_id,
|
|
552
|
+
)
|
|
553
|
+
)
|
|
554
|
+
return keys
|
|
555
|
+
|
|
556
|
+
@staticmethod
|
|
557
|
+
def from_string(s):
|
|
558
|
+
parts = s.split("@")
|
|
559
|
+
if len(parts) < 6:
|
|
560
|
+
raise ValueError(f"Invalid key string: {s}")
|
|
561
|
+
request_configs = None
|
|
562
|
+
if len(parts) >= 7:
|
|
563
|
+
request_configs = {}
|
|
564
|
+
for kv in parts[6:]:
|
|
565
|
+
kvs = kv.split("%", 1)
|
|
566
|
+
if len(kvs) != 2:
|
|
567
|
+
raise ValueError(f"Invalid key string: {s}")
|
|
568
|
+
request_configs["lmcache.tag." + kvs[0]] = kvs[1]
|
|
569
|
+
return LayerCacheEngineKey(
|
|
570
|
+
model_name=parts[0],
|
|
571
|
+
world_size=int(parts[1]),
|
|
572
|
+
worker_id=int(parts[2]),
|
|
573
|
+
chunk_hash=int(parts[3], 16),
|
|
574
|
+
dtype=STR_DTYPE_TO_TORCH_DTYPE[parts[4]],
|
|
575
|
+
request_configs=request_configs,
|
|
576
|
+
layer_id=int(parts[5]),
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
@dataclass
|
|
581
|
+
class CacheStoreEvent:
|
|
582
|
+
block_hashes: list[int]
|
|
583
|
+
parent_block_hash: int | None
|
|
584
|
+
token_ids: list[int]
|
|
585
|
+
block_size: int
|
|
586
|
+
|
|
587
|
+
# Deprecated, use lora_name instead
|
|
588
|
+
# Retained for backwards compatibility
|
|
589
|
+
# Remove when vLLM removes it from BlockStored
|
|
590
|
+
lora_id: int | None
|
|
591
|
+
|
|
592
|
+
medium: str | None
|
|
593
|
+
lora_name: str | None
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
class EngineType(Enum):
|
|
597
|
+
VLLM = "vllm"
|
|
598
|
+
SGLANG = "sglang"
|
|
599
|
+
MOCK = "mock"
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
##### NVTX annotation #####
|
|
603
|
+
_NVTX_COLORS = ["green", "blue", "purple", "rapids"]
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
def _get_color_for_nvtx(name):
|
|
607
|
+
m = hashlib.sha256()
|
|
608
|
+
m.update(name.encode())
|
|
609
|
+
hash_value = int(m.hexdigest(), 16)
|
|
610
|
+
idx = hash_value % len(_NVTX_COLORS)
|
|
611
|
+
return _NVTX_COLORS[idx]
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
def _lmcache_nvtx_annotate(func, domain="lmcache"):
|
|
615
|
+
"""Decorator for applying nvtx annotations to methods in lmcache."""
|
|
616
|
+
return annotate(
|
|
617
|
+
message=func.__qualname__,
|
|
618
|
+
color=_get_color_for_nvtx(func.__qualname__),
|
|
619
|
+
domain=domain,
|
|
620
|
+
)(func)
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
##### Observability Threading related #####
|
|
624
|
+
_shared_observability_lock = threading.Lock()
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
def thread_safe(func):
|
|
628
|
+
def wrapper(*args, **kwargs):
|
|
629
|
+
with _shared_observability_lock:
|
|
630
|
+
result = func(*args, **kwargs)
|
|
631
|
+
return result
|
|
632
|
+
|
|
633
|
+
return wrapper
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
#### Thread/asyncio-related utilities ####
|
|
637
|
+
def handle_thread_exception(args):
|
|
638
|
+
logger.error(
|
|
639
|
+
f"Thread {args.thread.name} crashed: {args.exc_type.__name__}: {args.exc_value}"
|
|
640
|
+
)
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
def start_loop_in_thread_with_exceptions(loop: asyncio.AbstractEventLoop):
|
|
644
|
+
# The loop must be set in the *same* thread where it runs.
|
|
645
|
+
asyncio.set_event_loop(loop)
|
|
646
|
+
|
|
647
|
+
# Catch unhandled exceptions from callbacks/tasks in this loop:
|
|
648
|
+
def loop_excepthook(loop, context):
|
|
649
|
+
msg = context.get("message", "Unhandled exception in event loop")
|
|
650
|
+
exc = context.get("exception")
|
|
651
|
+
logger.error(f"[asyncio] {msg}")
|
|
652
|
+
if exc:
|
|
653
|
+
traceback.print_exception(type(exc), exc, exc.__traceback__)
|
|
654
|
+
|
|
655
|
+
loop.set_exception_handler(loop_excepthook)
|
|
656
|
+
loop.run_forever()
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
#### Placeholder for dpsk broadcast functionality ####
|
|
660
|
+
def mock_up_broadcast_fn(t: torch.Tensor, i: int) -> None:
|
|
661
|
+
raise NotImplementedError("Calling invalid broadcast function")
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
def mock_up_broadcast_object_fn(a: Any, i: int) -> None:
|
|
665
|
+
raise NotImplementedError("Calling invalid broadcast object function")
|
lmcache/v1/__init__.py
ADDED