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,194 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
from typing import Generic, Optional, TypeVar
|
|
4
|
+
import threading
|
|
5
|
+
|
|
6
|
+
# Third Party
|
|
7
|
+
import torch
|
|
8
|
+
|
|
9
|
+
T = TypeVar("T")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MessagingFuture(Generic[T]):
|
|
13
|
+
def __init__(self):
|
|
14
|
+
self.is_done_ = threading.Event()
|
|
15
|
+
self.result_ = None
|
|
16
|
+
|
|
17
|
+
def query(self) -> bool:
|
|
18
|
+
"""
|
|
19
|
+
Check if the future is done.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
bool: True if the future is done, False otherwise.
|
|
23
|
+
"""
|
|
24
|
+
return self.is_done_.is_set()
|
|
25
|
+
|
|
26
|
+
def wait(self, timeout: Optional[float] = None) -> bool:
|
|
27
|
+
"""
|
|
28
|
+
Wait for the future to be done.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
timeout (Optional[float]): Maximum time to wait in seconds.
|
|
32
|
+
If None, wait indefinitely.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
bool: True if the future is done, False if the timeout was reached.
|
|
36
|
+
"""
|
|
37
|
+
return self.is_done_.wait(timeout)
|
|
38
|
+
|
|
39
|
+
def result(self, timeout: Optional[float] = None) -> T:
|
|
40
|
+
"""
|
|
41
|
+
Get the result of the future.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
timeout (Optional[float]): Maximum time to wait in seconds.
|
|
45
|
+
If None, wait indefinitely.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
T: The result of the future.
|
|
49
|
+
|
|
50
|
+
Raises:
|
|
51
|
+
TimeoutError: If the future is not done within the timeout.
|
|
52
|
+
"""
|
|
53
|
+
flag = self.wait(timeout)
|
|
54
|
+
if not flag:
|
|
55
|
+
raise TimeoutError("Future result not available within timeout")
|
|
56
|
+
return self.result_
|
|
57
|
+
|
|
58
|
+
def set_result(self, result: T) -> None:
|
|
59
|
+
"""
|
|
60
|
+
Set the result of the future and mark it as done. This function is NOT
|
|
61
|
+
SUPPOSED TO BE CALLED by users directly. It should be only called by
|
|
62
|
+
the messaging system when the result is available.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
result (T): The result to set.
|
|
66
|
+
"""
|
|
67
|
+
self.result_ = result
|
|
68
|
+
self.is_done_.set()
|
|
69
|
+
|
|
70
|
+
def to_cuda_future(
|
|
71
|
+
self,
|
|
72
|
+
device: torch.cuda.device | None = None,
|
|
73
|
+
) -> "CUDAMessagingFuture":
|
|
74
|
+
# TODO: need extra type checking for the future type
|
|
75
|
+
return CUDAMessagingFuture.FromMessagingFuture(self, device) # type: ignore
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class CUDAMessagingFuture(MessagingFuture[T]):
|
|
79
|
+
"""
|
|
80
|
+
The future class that wraps both result and a CUDA IPC event.
|
|
81
|
+
The `query`, `wait`, and `result` methods will pend on both the
|
|
82
|
+
original future and the CUDA event.
|
|
83
|
+
The original future should return tuple[bytes, T], where the first
|
|
84
|
+
element is the serialized CUDA event.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
def __init__(
|
|
88
|
+
self,
|
|
89
|
+
raw_future: MessagingFuture[tuple[bytes, T]],
|
|
90
|
+
device: torch.cuda.device | None = None,
|
|
91
|
+
) -> None:
|
|
92
|
+
super().__init__()
|
|
93
|
+
self.raw_future_ = raw_future
|
|
94
|
+
self.event_: torch.cuda.Event | None = None
|
|
95
|
+
self.result_: T | None = None
|
|
96
|
+
self.device_ = device if device is not None else torch.cuda.current_device()
|
|
97
|
+
|
|
98
|
+
def _on_raw_future_complete(self):
|
|
99
|
+
"""
|
|
100
|
+
Update the CUDA event and result when the raw future is complete.
|
|
101
|
+
"""
|
|
102
|
+
event_bytes, result = self.raw_future_.result()
|
|
103
|
+
self.result_ = result
|
|
104
|
+
|
|
105
|
+
# Deserialize the CUDA event
|
|
106
|
+
self.event_ = torch.cuda.Event.from_ipc_handle(self.device_, event_bytes)
|
|
107
|
+
|
|
108
|
+
def wait(self, timeout: Optional[float] = None) -> bool:
|
|
109
|
+
"""
|
|
110
|
+
Wait for the future to be done, with the CUDA stream.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
timeout (Optional[float]): Maximum time to wait for the UNDERLYING
|
|
114
|
+
RAW FUTURE in seconds. The exact timeout is not guaranteed
|
|
115
|
+
when waiting on the CUDA event. (NOTE: this could be improved
|
|
116
|
+
with careful threading management)
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
bool: True if the future is done, False if the timeout was reached.
|
|
120
|
+
|
|
121
|
+
Raises:
|
|
122
|
+
ValueError: if the timeout is not None.
|
|
123
|
+
|
|
124
|
+
Notes:
|
|
125
|
+
This function does not support waiting for a specific time.
|
|
126
|
+
"""
|
|
127
|
+
if self.event_:
|
|
128
|
+
self.event_.synchronize()
|
|
129
|
+
return True
|
|
130
|
+
|
|
131
|
+
flag = self.raw_future_.wait(timeout)
|
|
132
|
+
if not flag:
|
|
133
|
+
return False
|
|
134
|
+
|
|
135
|
+
self._on_raw_future_complete()
|
|
136
|
+
|
|
137
|
+
assert self.event_ is not None
|
|
138
|
+
self.event_.synchronize()
|
|
139
|
+
|
|
140
|
+
return True
|
|
141
|
+
|
|
142
|
+
def result(self, timeout: Optional[float] = None) -> T:
|
|
143
|
+
"""
|
|
144
|
+
Get the result of the future.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
timeout (Optional[float]): Maximum time to wait for the UNDERLYING
|
|
148
|
+
RAW FUTURE in seconds. The exact timeout is not guaranteed
|
|
149
|
+
when waiting on the CUDA event. (NOTE: this could be improved
|
|
150
|
+
with careful threading management)
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
T: The result of the future.
|
|
154
|
+
|
|
155
|
+
Raises:
|
|
156
|
+
TimeoutError: If the future is not done within the timeout.
|
|
157
|
+
"""
|
|
158
|
+
flag = self.wait(timeout)
|
|
159
|
+
if not flag:
|
|
160
|
+
raise TimeoutError(
|
|
161
|
+
"CUDAMessagingFuture result not available within timeout"
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
assert self.result_ is not None
|
|
165
|
+
return self.result_
|
|
166
|
+
|
|
167
|
+
def query(self) -> bool:
|
|
168
|
+
"""
|
|
169
|
+
Check if the future is done.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
bool: True if the future is done, False otherwise.
|
|
173
|
+
"""
|
|
174
|
+
if self.event_:
|
|
175
|
+
return self.event_.query()
|
|
176
|
+
|
|
177
|
+
if self.raw_future_.query():
|
|
178
|
+
self._on_raw_future_complete()
|
|
179
|
+
assert self.event_ is not None
|
|
180
|
+
return self.event_.query()
|
|
181
|
+
|
|
182
|
+
return False
|
|
183
|
+
|
|
184
|
+
def set_result(self, result: T) -> None:
|
|
185
|
+
raise NotImplementedError(
|
|
186
|
+
"CUDAMessagingFuture does not support set_result directly"
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
@staticmethod
|
|
190
|
+
def FromMessagingFuture(
|
|
191
|
+
raw_future: MessagingFuture[tuple[bytes, T]],
|
|
192
|
+
device: torch.cuda.device | None = None,
|
|
193
|
+
) -> "CUDAMessagingFuture[T]":
|
|
194
|
+
return CUDAMessagingFuture(raw_future, device)
|
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""
|
|
3
|
+
GPU Cache Context management for LMCache multiprocessing.
|
|
4
|
+
|
|
5
|
+
This module provides GPU-side KV cache management functionality, including:
|
|
6
|
+
- GPUCacheContext: Manages shape and pointers to vLLM GPU KV cache tensors
|
|
7
|
+
- Helper functions for tensor operations and key resolution
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# Standard
|
|
11
|
+
import array
|
|
12
|
+
|
|
13
|
+
# Third Party
|
|
14
|
+
import cupy
|
|
15
|
+
import torch
|
|
16
|
+
|
|
17
|
+
# First Party
|
|
18
|
+
from lmcache.logging import init_logger
|
|
19
|
+
from lmcache.utils import EngineType
|
|
20
|
+
from lmcache.v1.gpu_connector.utils import (
|
|
21
|
+
LayoutHints,
|
|
22
|
+
discover_gpu_kv_format,
|
|
23
|
+
get_attention_backend,
|
|
24
|
+
get_block_size,
|
|
25
|
+
get_concrete_gpu_kv_shape,
|
|
26
|
+
get_dtype,
|
|
27
|
+
get_gpu_kv_shape_description,
|
|
28
|
+
get_head_size,
|
|
29
|
+
get_hidden_dim_size,
|
|
30
|
+
get_num_blocks,
|
|
31
|
+
get_num_heads,
|
|
32
|
+
get_num_layers,
|
|
33
|
+
is_mla,
|
|
34
|
+
)
|
|
35
|
+
from lmcache.v1.kv_layer_groups import KVLayerGroupsManager
|
|
36
|
+
|
|
37
|
+
if torch.cuda.is_available():
|
|
38
|
+
import lmcache.c_ops as lmc_ops
|
|
39
|
+
|
|
40
|
+
# First Party
|
|
41
|
+
from lmcache.v1.multiprocess.custom_types import (
|
|
42
|
+
KVCache,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
logger = init_logger(__name__)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def unwrap_kv_cache_tensors(kv_caches: KVCache) -> list[torch.Tensor]:
|
|
49
|
+
unwrapped_tensors = []
|
|
50
|
+
for ipc_wrapper in kv_caches:
|
|
51
|
+
tensor = ipc_wrapper.to_tensor()
|
|
52
|
+
unwrapped_tensors.append(tensor)
|
|
53
|
+
return unwrapped_tensors
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def list_to_gpu_tensor(lis: list[int], device: torch.device) -> torch.Tensor:
|
|
57
|
+
return torch.frombuffer(array.array("l", lis), dtype=torch.long).to(
|
|
58
|
+
device, non_blocking=True
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class GPUCacheContext:
|
|
63
|
+
"""
|
|
64
|
+
Manages the shape and pointers to vLLM GPU KV cache tensors.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
def __init__(
|
|
68
|
+
self,
|
|
69
|
+
kv_caches: KVCache,
|
|
70
|
+
lmcache_chunk_size: int = 256,
|
|
71
|
+
layout_hints: LayoutHints | None = None,
|
|
72
|
+
):
|
|
73
|
+
self.kv_caches_ = unwrap_kv_cache_tensors(kv_caches)
|
|
74
|
+
self.device_ = self.kv_caches_[0].device
|
|
75
|
+
|
|
76
|
+
# Pointers
|
|
77
|
+
pointers_list = [t.data_ptr() for t in self.kv_caches_]
|
|
78
|
+
self.kv_cache_pointers_ = list_to_gpu_tensor(pointers_list, self.device_)
|
|
79
|
+
|
|
80
|
+
# TODO support creating GPUCacheContext for SGLang
|
|
81
|
+
self.gpu_kv_format_ = discover_gpu_kv_format(
|
|
82
|
+
self.kv_caches_,
|
|
83
|
+
EngineType.VLLM,
|
|
84
|
+
layout_hints=layout_hints,
|
|
85
|
+
)
|
|
86
|
+
self.is_mla_ = is_mla(self.gpu_kv_format_)
|
|
87
|
+
self.num_layers_ = get_num_layers(self.kv_caches_, self.gpu_kv_format_)
|
|
88
|
+
self.num_blocks_ = get_num_blocks(self.kv_caches_, self.gpu_kv_format_)
|
|
89
|
+
self.block_size_ = get_block_size(self.kv_caches_, self.gpu_kv_format_)
|
|
90
|
+
|
|
91
|
+
# Build per-layer KV groups (grouped by shape and dtype)
|
|
92
|
+
self.kv_layer_groups_manager_ = KVLayerGroupsManager()
|
|
93
|
+
self.kv_layer_groups_manager_.build_kv_layer_groups_from_list(self.kv_caches_)
|
|
94
|
+
|
|
95
|
+
# Per-group attributes: hidden_dim_size, num_heads, head_size,
|
|
96
|
+
# shape_desc, and kv_pointers — all derived from the representative
|
|
97
|
+
# first layer of each group. MLA formats have no independent num_heads
|
|
98
|
+
# dimension; use nh=1 so the kernel thread block has a single row.
|
|
99
|
+
kv_size = 1 if self.is_mla_ else 2
|
|
100
|
+
self.hidden_dim_sizes_: list[int] = []
|
|
101
|
+
self.group_num_heads_: list[int] = []
|
|
102
|
+
self.group_head_sizes_: list[int] = []
|
|
103
|
+
self.shape_descs_: list[lmc_ops.PageBufferShapeDesc] = []
|
|
104
|
+
self.group_kv_pointers_: list[torch.Tensor] = []
|
|
105
|
+
for group in self.kv_layer_groups_manager_.kv_layer_groups:
|
|
106
|
+
rep = [self.kv_caches_[group.layer_indices[0]]]
|
|
107
|
+
hidden_dim = get_hidden_dim_size(rep, self.gpu_kv_format_)
|
|
108
|
+
nh = 1 if self.is_mla_ else get_num_heads(rep, self.gpu_kv_format_)
|
|
109
|
+
hs = get_head_size(rep, self.gpu_kv_format_)
|
|
110
|
+
|
|
111
|
+
self.hidden_dim_sizes_.append(hidden_dim)
|
|
112
|
+
self.group_num_heads_.append(nh)
|
|
113
|
+
self.group_head_sizes_.append(hs)
|
|
114
|
+
|
|
115
|
+
sd = lmc_ops.PageBufferShapeDesc()
|
|
116
|
+
sd.kv_size = kv_size
|
|
117
|
+
sd.nl = group.num_layers
|
|
118
|
+
sd.nb = self.num_blocks_
|
|
119
|
+
sd.bs = self.block_size_
|
|
120
|
+
sd.nh = nh
|
|
121
|
+
sd.hs = hs
|
|
122
|
+
sd.element_size = rep[0].element_size()
|
|
123
|
+
self.shape_descs_.append(sd)
|
|
124
|
+
|
|
125
|
+
self.group_kv_pointers_.append(
|
|
126
|
+
list_to_gpu_tensor(
|
|
127
|
+
[self.kv_caches_[i].data_ptr() for i in group.layer_indices],
|
|
128
|
+
self.device_,
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Pre-allocated GPU buffer for block IDs (up to 1M elements).
|
|
133
|
+
# The caller copies block_ids into this buffer before launching the
|
|
134
|
+
# block-level kernel. Single-thread assumption: no lock needed.
|
|
135
|
+
_MAX_BLOCK_IDS = 1_000_000
|
|
136
|
+
self.block_ids_buffer_ = torch.empty(
|
|
137
|
+
_MAX_BLOCK_IDS, dtype=torch.long, device=self.device_
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Temporary GPU buffer for transfers — a single flat uint8 buffer
|
|
141
|
+
# laid out in chunk-major order so that each chunk's data matches
|
|
142
|
+
# the layout of a MemoryObj.raw_data (all groups concatenated):
|
|
143
|
+
#
|
|
144
|
+
# [ chunk_0: group_0_bytes | group_1_bytes | ... ]
|
|
145
|
+
# [ chunk_1: group_0_bytes | group_1_bytes | ... ]
|
|
146
|
+
# ...
|
|
147
|
+
#
|
|
148
|
+
# This lets callers copy an entire chunk to/from a MemoryObj with a
|
|
149
|
+
# single memcpy, without needing to know the per-group layout.
|
|
150
|
+
# max_batch_size is the max number of chunks processed concurrently.
|
|
151
|
+
self.max_batch_size = 4
|
|
152
|
+
self.lmcache_chunk_size = lmcache_chunk_size
|
|
153
|
+
# Byte size of one chunk entry (= one chunk across all groups).
|
|
154
|
+
# tmp_chunk_group_offsets_[g] is the byte offset of group g within
|
|
155
|
+
# a single chunk; tmp_chunk_group_offsets_[num_groups] ==
|
|
156
|
+
# tmp_chunk_bytes_.
|
|
157
|
+
self.tmp_chunk_group_offsets_: list[int] = [0]
|
|
158
|
+
for group_idx, group in enumerate(
|
|
159
|
+
self.kv_layer_groups_manager_.kv_layer_groups
|
|
160
|
+
):
|
|
161
|
+
shape = self.get_kv_buffer_shape(lmcache_chunk_size, group_idx)
|
|
162
|
+
byte_size = shape.numel() * group.dtype.itemsize
|
|
163
|
+
self.tmp_chunk_group_offsets_.append(
|
|
164
|
+
self.tmp_chunk_group_offsets_[-1] + byte_size
|
|
165
|
+
)
|
|
166
|
+
self.tmp_chunk_bytes_ = self.tmp_chunk_group_offsets_[-1]
|
|
167
|
+
self.tmp_gpu_buffer_ = torch.empty(
|
|
168
|
+
self.tmp_chunk_bytes_ * self.max_batch_size,
|
|
169
|
+
dtype=torch.uint8,
|
|
170
|
+
device=self.device_,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# Cuda streams
|
|
174
|
+
self.cuda_stream_ = torch.cuda.Stream(device=self.device_)
|
|
175
|
+
self.cupy_stream_ = cupy.cuda.ExternalStream(
|
|
176
|
+
self.cuda_stream_.cuda_stream, self.device_.index
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
_, high_priority = torch.cuda.Stream.priority_range()
|
|
180
|
+
self.high_priority_cuda_stream_ = torch.cuda.Stream(
|
|
181
|
+
device=self.device_, priority=high_priority
|
|
182
|
+
)
|
|
183
|
+
self.high_priority_cupy_stream_ = cupy.cuda.ExternalStream(
|
|
184
|
+
self.high_priority_cuda_stream_.cuda_stream, self.device_.index
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Extra initialization
|
|
188
|
+
self.cupy_stream_.launch_host_func(
|
|
189
|
+
lambda logger: logger.info(
|
|
190
|
+
"Initialized cuda stream on device %s", str(self.device_)
|
|
191
|
+
),
|
|
192
|
+
logger,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def dtype(self) -> torch.dtype:
|
|
197
|
+
return get_dtype(self.kv_caches_, self.gpu_kv_format_)
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
def device(self) -> torch.device:
|
|
201
|
+
return self.device_
|
|
202
|
+
|
|
203
|
+
@property
|
|
204
|
+
def kv_tensors(self) -> list[torch.Tensor]:
|
|
205
|
+
return self.kv_caches_
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def kv_pointers(self) -> torch.Tensor:
|
|
209
|
+
"""
|
|
210
|
+
Returns a GPU tensor of the KV cache pointers
|
|
211
|
+
"""
|
|
212
|
+
return self.kv_cache_pointers_
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def stream(self) -> torch.cuda.Stream:
|
|
216
|
+
"""
|
|
217
|
+
Returns the CUDA stream for KV cache operations
|
|
218
|
+
"""
|
|
219
|
+
return self.cuda_stream_
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def cupy_stream(self) -> cupy.cuda.Stream:
|
|
223
|
+
return self.cupy_stream_
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def high_priority_stream(self) -> torch.cuda.Stream:
|
|
227
|
+
return self.high_priority_cuda_stream_
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
def high_priority_cupy_stream(self) -> cupy.cuda.Stream:
|
|
231
|
+
return self.high_priority_cupy_stream_
|
|
232
|
+
|
|
233
|
+
@property
|
|
234
|
+
def block_size(self) -> int:
|
|
235
|
+
"""
|
|
236
|
+
Returns the block size (number of tokens per block)
|
|
237
|
+
"""
|
|
238
|
+
return self.block_size_
|
|
239
|
+
|
|
240
|
+
@property
|
|
241
|
+
def num_layers(self) -> int:
|
|
242
|
+
"""
|
|
243
|
+
Returns the number of layers in the model
|
|
244
|
+
"""
|
|
245
|
+
return self.num_layers_
|
|
246
|
+
|
|
247
|
+
@property
|
|
248
|
+
def num_blocks(self) -> int:
|
|
249
|
+
"""
|
|
250
|
+
Returns the number of blocks in the KV cache
|
|
251
|
+
"""
|
|
252
|
+
return self.num_blocks_
|
|
253
|
+
|
|
254
|
+
@property
|
|
255
|
+
def is_mla(self) -> bool:
|
|
256
|
+
"""
|
|
257
|
+
Returns whether the model uses MLA
|
|
258
|
+
"""
|
|
259
|
+
return self.is_mla_
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def hidden_dim_sizes(self) -> list[int]:
|
|
263
|
+
"""Returns the hidden dimension sizes for each KV layer group."""
|
|
264
|
+
return self.hidden_dim_sizes_
|
|
265
|
+
|
|
266
|
+
def get_shape_desc(self, group_idx: int) -> "lmc_ops.PageBufferShapeDesc":
|
|
267
|
+
"""Returns the PageBufferShapeDesc for the given KV layer group."""
|
|
268
|
+
return self.shape_descs_[group_idx]
|
|
269
|
+
|
|
270
|
+
@property
|
|
271
|
+
def kv_layer_groups_manager(self) -> KVLayerGroupsManager:
|
|
272
|
+
"""Returns the KV layer groups manager."""
|
|
273
|
+
return self.kv_layer_groups_manager_
|
|
274
|
+
|
|
275
|
+
def gpu_kv_format_name(self) -> str:
|
|
276
|
+
"""Returns the GPU KV format enum name (e.g. ``'NL_X_TWO_NB_BS_NH_HS'``)."""
|
|
277
|
+
return self.gpu_kv_format_.name
|
|
278
|
+
|
|
279
|
+
@property
|
|
280
|
+
def gpu_kv_shape(self) -> str:
|
|
281
|
+
"""Returns a human-readable shape description of the GPU KV cache layout."""
|
|
282
|
+
return get_gpu_kv_shape_description(self.gpu_kv_format_)
|
|
283
|
+
|
|
284
|
+
@property
|
|
285
|
+
def attention_backend(self) -> str:
|
|
286
|
+
"""Returns the attention backend name."""
|
|
287
|
+
return get_attention_backend(self.gpu_kv_format_)
|
|
288
|
+
|
|
289
|
+
@property
|
|
290
|
+
def concrete_gpu_kv_shape(self) -> str:
|
|
291
|
+
"""Returns the GPU KV shape with actual numeric values substituted."""
|
|
292
|
+
return get_concrete_gpu_kv_shape(self.kv_caches_, self.gpu_kv_format_)
|
|
293
|
+
|
|
294
|
+
def get_group_kv_pointers(self, group_idx: int) -> torch.Tensor:
|
|
295
|
+
"""Returns the pre-computed GPU tensor of KV cache pointers for the
|
|
296
|
+
given group."""
|
|
297
|
+
return self.group_kv_pointers_[group_idx]
|
|
298
|
+
|
|
299
|
+
def get_tmp_gpu_buffer_flat(self, chunk_idx: int) -> torch.Tensor:
|
|
300
|
+
"""Returns the flat uint8 view of the temporary GPU buffer for the
|
|
301
|
+
given chunk index, covering all KV layer groups.
|
|
302
|
+
|
|
303
|
+
The returned tensor will fit a memory full object corresponding
|
|
304
|
+
``self.chunk_size`` tokens, so it can be copied to/from a MemoryObj
|
|
305
|
+
with a single memcpy.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
chunk_idx: Chunk index (0 <= chunk_idx < max_batch_size).
|
|
309
|
+
"""
|
|
310
|
+
if chunk_idx >= self.max_batch_size:
|
|
311
|
+
raise ValueError(
|
|
312
|
+
f"chunk_idx {chunk_idx} exceeds max_batch_size {self.max_batch_size}"
|
|
313
|
+
)
|
|
314
|
+
start = chunk_idx * self.tmp_chunk_bytes_
|
|
315
|
+
return self.tmp_gpu_buffer_[start : start + self.tmp_chunk_bytes_]
|
|
316
|
+
|
|
317
|
+
def get_tmp_chunk_gpu_buffer(self, group_idx: int = 0) -> torch.Tensor:
|
|
318
|
+
"""
|
|
319
|
+
Returns a view of the temporary GPU buffer for the given group,
|
|
320
|
+
sized for a single chunk of ``lmcache_chunk_size`` tokens.
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
group_idx: Index of the KV layer group (default 0).
|
|
324
|
+
"""
|
|
325
|
+
group = self.kv_layer_groups_manager_.kv_layer_groups[group_idx]
|
|
326
|
+
shape = self.get_kv_buffer_shape(self.lmcache_chunk_size, group_idx)
|
|
327
|
+
start = self.tmp_chunk_group_offsets_[group_idx]
|
|
328
|
+
end = self.tmp_chunk_group_offsets_[group_idx + 1]
|
|
329
|
+
return self.tmp_gpu_buffer_[start:end].view(group.dtype).view(shape)
|
|
330
|
+
|
|
331
|
+
def get_tmp_chunk_gpu_buffer_batched(
|
|
332
|
+
self, batch_size: int, group_idx: int = 0
|
|
333
|
+
) -> list[torch.Tensor]:
|
|
334
|
+
"""
|
|
335
|
+
Returns a list of ``batch_size`` non-overlapping views into the
|
|
336
|
+
pre-allocated temporary GPU buffer for the given group, each
|
|
337
|
+
sized for ``lmcache_chunk_size`` tokens.
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
batch_size: Number of concurrent requests (must be <= max_batch_size).
|
|
341
|
+
group_idx: Index of the KV layer group (default 0).
|
|
342
|
+
"""
|
|
343
|
+
if batch_size > self.max_batch_size:
|
|
344
|
+
raise ValueError(
|
|
345
|
+
f"batch_size {batch_size} exceeds max_batch_size {self.max_batch_size}"
|
|
346
|
+
)
|
|
347
|
+
group = self.kv_layer_groups_manager_.kv_layer_groups[group_idx]
|
|
348
|
+
shape = self.get_kv_buffer_shape(self.lmcache_chunk_size, group_idx)
|
|
349
|
+
g_start = self.tmp_chunk_group_offsets_[group_idx]
|
|
350
|
+
g_end = self.tmp_chunk_group_offsets_[group_idx + 1]
|
|
351
|
+
chunk = self.tmp_chunk_bytes_
|
|
352
|
+
return [
|
|
353
|
+
self.tmp_gpu_buffer_[i * chunk + g_start : i * chunk + g_end]
|
|
354
|
+
.view(group.dtype)
|
|
355
|
+
.view(shape)
|
|
356
|
+
for i in range(batch_size)
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
def stage_block_ids(self, block_ids: list[int]) -> torch.Tensor:
|
|
360
|
+
"""Copy block_ids into the pre-allocated GPU buffer and return a
|
|
361
|
+
view of the occupied region. Uses non-blocking copy via a pinned
|
|
362
|
+
CPU tensor created from the list's underlying buffer.
|
|
363
|
+
|
|
364
|
+
Args:
|
|
365
|
+
block_ids: Block indices as a Python list of ints.
|
|
366
|
+
|
|
367
|
+
Returns:
|
|
368
|
+
A GPU int64 tensor view into the pre-allocated buffer.
|
|
369
|
+
"""
|
|
370
|
+
n = len(block_ids)
|
|
371
|
+
cpu_tensor = torch.frombuffer(array.array("l", block_ids), dtype=torch.long)
|
|
372
|
+
buf = self.block_ids_buffer_[:n]
|
|
373
|
+
buf.copy_(cpu_tensor, non_blocking=True)
|
|
374
|
+
return buf
|
|
375
|
+
|
|
376
|
+
def get_kv_buffer_shape(self, num_tokens: int, group_idx: int = 0) -> torch.Size:
|
|
377
|
+
"""
|
|
378
|
+
Returns the shape of the KV buffer for the given number of tokens.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
num_tokens: Number of tokens.
|
|
382
|
+
group_idx: Index of the KV layer group (default 0).
|
|
383
|
+
"""
|
|
384
|
+
group = self.kv_layer_groups_manager_.kv_layer_groups[group_idx]
|
|
385
|
+
num_layers_in_group = group.num_layers
|
|
386
|
+
hidden_dim = self.hidden_dim_sizes[group_idx]
|
|
387
|
+
if self.is_mla_:
|
|
388
|
+
return torch.Size((1, num_layers_in_group, num_tokens, hidden_dim))
|
|
389
|
+
else:
|
|
390
|
+
return torch.Size((2, num_layers_in_group, num_tokens, hidden_dim))
|
|
391
|
+
|
|
392
|
+
def cache_size_per_token(self) -> int:
|
|
393
|
+
"""
|
|
394
|
+
Returns the cache size per token (in bytes), summed across all groups.
|
|
395
|
+
"""
|
|
396
|
+
total = 0
|
|
397
|
+
for group_idx, group in enumerate(
|
|
398
|
+
self.kv_layer_groups_manager_.kv_layer_groups
|
|
399
|
+
):
|
|
400
|
+
numels = self.get_kv_buffer_shape(1, group_idx).numel()
|
|
401
|
+
total += numels * group.dtype.itemsize
|
|
402
|
+
return total
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
class PlainGPUCacheContext:
|
|
406
|
+
"""
|
|
407
|
+
A plain GPU cache context that have a single contiguous 2LTD buffer
|
|
408
|
+
"""
|
|
409
|
+
|
|
410
|
+
def __init__(self, kv_caches: KVCache, lmcache_chunk_size: int = 256):
|
|
411
|
+
assert len(kv_caches) == 1, (
|
|
412
|
+
"PlainGPUCacheContext only supports a single KV cache tensor"
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
# KV cache basics
|
|
416
|
+
self._kv_cache = unwrap_kv_cache_tensors(kv_caches)[0]
|
|
417
|
+
self._device = self._kv_cache.device
|
|
418
|
+
|
|
419
|
+
# Shape related
|
|
420
|
+
shape = self._kv_cache.shape
|
|
421
|
+
assert len(shape) == 4, "Expected [2, L, T, D] for plain GPU cache"
|
|
422
|
+
|
|
423
|
+
self._num_layers = shape[1]
|
|
424
|
+
self._num_tokens = shape[2]
|
|
425
|
+
self._hidden_dim_size = shape[3]
|
|
426
|
+
|
|
427
|
+
# Temporary buffer
|
|
428
|
+
tmp_buffer_shape = self.get_kv_buffer_shape(lmcache_chunk_size)
|
|
429
|
+
self._tmp_gpu_buffer = torch.empty(
|
|
430
|
+
tmp_buffer_shape, dtype=self.dtype, device=self.device
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
# Cuda streams
|
|
434
|
+
self._cuda_stream = torch.cuda.Stream(device=self._device)
|
|
435
|
+
self._cupy_stream = cupy.cuda.ExternalStream(
|
|
436
|
+
self._cuda_stream.cuda_stream, self._device.index
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
_, high_priority = torch.cuda.Stream.priority_range()
|
|
440
|
+
self._high_priority_cuda_stream = torch.cuda.Stream(
|
|
441
|
+
device=self._device, priority=high_priority
|
|
442
|
+
)
|
|
443
|
+
self._high_priority_cupy_stream = cupy.cuda.ExternalStream(
|
|
444
|
+
self._high_priority_cuda_stream.cuda_stream, self._device.index
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
# Extra initialization
|
|
448
|
+
self._cupy_stream.launch_host_func(
|
|
449
|
+
lambda logger: logger.info(
|
|
450
|
+
"Initialized cuda stream on device %s", str(self._device)
|
|
451
|
+
),
|
|
452
|
+
logger,
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
def get_kv_buffer_shape(self, num_tokens: int) -> torch.Size:
|
|
456
|
+
"""
|
|
457
|
+
Returns the shape of the KV buffer for the given number of tokens
|
|
458
|
+
"""
|
|
459
|
+
return torch.Size((2, self._num_layers, num_tokens, self._hidden_dim_size))
|
|
460
|
+
|
|
461
|
+
def get_tmp_gpu_buffer(self, num_tokens: int) -> torch.Tensor:
|
|
462
|
+
"""
|
|
463
|
+
Returns the temporary GPU buffer for transfers
|
|
464
|
+
"""
|
|
465
|
+
return self._tmp_gpu_buffer[:, :, :num_tokens, :]
|
|
466
|
+
|
|
467
|
+
def slice_kv_cache_on_tokens(self, start: int, end: int) -> torch.Tensor:
|
|
468
|
+
"""
|
|
469
|
+
Slices the KV cache tensor on the token dimension
|
|
470
|
+
"""
|
|
471
|
+
return self._kv_cache[:, :, start:end, :]
|
|
472
|
+
|
|
473
|
+
@property
|
|
474
|
+
def dtype(self) -> torch.dtype:
|
|
475
|
+
return self._kv_cache.dtype
|
|
476
|
+
|
|
477
|
+
@property
|
|
478
|
+
def device(self) -> torch.device:
|
|
479
|
+
return self._device
|
|
480
|
+
|
|
481
|
+
@property
|
|
482
|
+
def stream(self) -> torch.cuda.Stream:
|
|
483
|
+
return self._cuda_stream
|
|
484
|
+
|
|
485
|
+
@property
|
|
486
|
+
def cupy_stream(self) -> cupy.cuda.Stream:
|
|
487
|
+
return self._cupy_stream
|
|
488
|
+
|
|
489
|
+
@property
|
|
490
|
+
def high_priority_stream(self) -> torch.cuda.Stream:
|
|
491
|
+
return self._high_priority_cuda_stream
|
|
492
|
+
|
|
493
|
+
@property
|
|
494
|
+
def high_priority_cupy_stream(self) -> cupy.cuda.Stream:
|
|
495
|
+
return self._high_priority_cupy_stream
|
|
496
|
+
|
|
497
|
+
@property
|
|
498
|
+
def num_layers(self) -> int:
|
|
499
|
+
return self._num_layers
|
|
500
|
+
|
|
501
|
+
@property
|
|
502
|
+
def num_tokens(self) -> int:
|
|
503
|
+
return self._num_tokens
|
|
504
|
+
|
|
505
|
+
@property
|
|
506
|
+
def hidden_dim_size(self) -> int:
|
|
507
|
+
return self._hidden_dim_size
|
|
508
|
+
|
|
509
|
+
@property
|
|
510
|
+
def kv_cache_tensor(self) -> torch.Tensor:
|
|
511
|
+
return self._kv_cache
|