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,916 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright 2024-2025 LMCache Authors.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
# Standard
|
|
16
|
+
from typing import List, Optional, Union, cast
|
|
17
|
+
import os
|
|
18
|
+
|
|
19
|
+
# Third Party
|
|
20
|
+
import torch
|
|
21
|
+
|
|
22
|
+
# First Party
|
|
23
|
+
from lmcache.logging import init_logger
|
|
24
|
+
from lmcache.utils import EngineType
|
|
25
|
+
from lmcache.v1.gpu_connector.gpu_connectors import (
|
|
26
|
+
GPUConnectorInterface,
|
|
27
|
+
VLLMPagedMemGPUConnectorV2,
|
|
28
|
+
)
|
|
29
|
+
from lmcache.v1.gpu_connector.utils import (
|
|
30
|
+
LayoutHints,
|
|
31
|
+
_get_head_size_view,
|
|
32
|
+
_split_token2d_kv,
|
|
33
|
+
discover_gpu_kv_format,
|
|
34
|
+
get_block_size,
|
|
35
|
+
get_dtype,
|
|
36
|
+
get_head_size,
|
|
37
|
+
get_hidden_dim_size,
|
|
38
|
+
get_num_blocks,
|
|
39
|
+
get_num_heads,
|
|
40
|
+
get_num_layers,
|
|
41
|
+
get_page_buffer_size,
|
|
42
|
+
is_mla,
|
|
43
|
+
)
|
|
44
|
+
from lmcache.v1.memory_management import (
|
|
45
|
+
MemoryAllocatorInterface,
|
|
46
|
+
MemoryFormat,
|
|
47
|
+
MemoryObj,
|
|
48
|
+
)
|
|
49
|
+
from lmcache.v1.metadata import LMCacheMetadata
|
|
50
|
+
|
|
51
|
+
logger = init_logger(__name__)
|
|
52
|
+
|
|
53
|
+
ALLOWED_FORMAT_TRANSITIONS = {
|
|
54
|
+
(None, MemoryFormat.KV_MLA_FMT),
|
|
55
|
+
(MemoryFormat.KV_MLA_FMT, MemoryFormat.KV_MLA_FMT),
|
|
56
|
+
(MemoryFormat.KV_T2D, MemoryFormat.KV_MLA_FMT),
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class VLLMPagedMemXPUConnectorV2(VLLMPagedMemGPUConnectorV2):
|
|
61
|
+
"""
|
|
62
|
+
The GPU KV cache should be a nested tuple of K and V tensors.
|
|
63
|
+
More specifically, we have:
|
|
64
|
+
- GPUTensor = Tuple[KVLayer, ...]
|
|
65
|
+
- KVLayer = Tuple[Tensor, Tensor]
|
|
66
|
+
- Tensor: [num_blocks, block_size, num_heads, head_size]
|
|
67
|
+
|
|
68
|
+
It will produce / consume memory object with KV_2LTD format
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
def __init__(
|
|
72
|
+
self,
|
|
73
|
+
use_gpu: bool = False,
|
|
74
|
+
**kwargs,
|
|
75
|
+
):
|
|
76
|
+
self._attributes_initialized = False
|
|
77
|
+
self.kvcaches: Optional[List[torch.Tensor]] = None
|
|
78
|
+
self.use_gpu = use_gpu
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def from_metadata(
|
|
82
|
+
cls,
|
|
83
|
+
metadata: LMCacheMetadata,
|
|
84
|
+
use_gpu: bool = False,
|
|
85
|
+
device: Optional[torch.device] = None,
|
|
86
|
+
layout_hints: Optional[LayoutHints] = None,
|
|
87
|
+
) -> "VLLMPagedMemXPUConnectorV2":
|
|
88
|
+
"""Create a connector from LMCacheMetadata.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
metadata: The LMCache engine metadata containing model configuration.
|
|
92
|
+
use_gpu: Whether to use GPU intermediate buffer.
|
|
93
|
+
device: The device to use for the connector.
|
|
94
|
+
layout_hints: Optional hints about KV cache layout from the
|
|
95
|
+
serving engine.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
A new instance of VLLMPagedMemXPUConnectorV2.
|
|
99
|
+
"""
|
|
100
|
+
return cls(
|
|
101
|
+
use_gpu=use_gpu,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def to_gpu(self, memory_obj: MemoryObj, start: int, end: int, **kwargs):
|
|
105
|
+
"""Expect a kwarg 'kvcaches' which is a nested tuple of K and V tensors.
|
|
106
|
+
The kvcaches should correspond to the "WHOLE token sequence".
|
|
107
|
+
|
|
108
|
+
Note:
|
|
109
|
+
1. This function expects the 'slot_mapping' is a "full slot mapping"
|
|
110
|
+
where it's length is the same as the whole token sequence.
|
|
111
|
+
2. In the case that there is prefix caching, slot_mapping will starts
|
|
112
|
+
with -1s until the end of the matched prefix. The start and end
|
|
113
|
+
should NEVER overlap with the prefix caching (which means the
|
|
114
|
+
underlying CUDA kernel will never see -1 in slot_mapping)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
:raises ValueError: If 'kvcaches' is not provided in kwargs.
|
|
118
|
+
:raises AssertionError: If the memory object does not have a tensor.
|
|
119
|
+
:raises ValueError: If 'slot_mapping' is not provided in kwargs.
|
|
120
|
+
"""
|
|
121
|
+
assert memory_obj.tensor is not None
|
|
122
|
+
|
|
123
|
+
self.initialize_kvcaches_ptr(**kwargs)
|
|
124
|
+
|
|
125
|
+
assert self.kvcaches is not None, (
|
|
126
|
+
"kvcaches should be provided in kwargs or initialized beforehand."
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
if "slot_mapping" not in kwargs:
|
|
130
|
+
raise ValueError("'slot_mapping' should be provided in kwargs.")
|
|
131
|
+
|
|
132
|
+
slot_mapping: torch.Tensor = kwargs["slot_mapping"]
|
|
133
|
+
slices = slot_mapping[start:end]
|
|
134
|
+
self._initialize_attributes(self.kvcaches)
|
|
135
|
+
self._validate_memory_format(memory_obj)
|
|
136
|
+
|
|
137
|
+
if self.use_mla:
|
|
138
|
+
tmp = memory_obj.tensor[0].to(slot_mapping.device)
|
|
139
|
+
total_blocks = self.num_blocks * self.block_size
|
|
140
|
+
for i, kvcache in enumerate(self.kvcaches):
|
|
141
|
+
kvcache.view(total_blocks, self.head_size).index_copy_(
|
|
142
|
+
0, slices, tmp[i]
|
|
143
|
+
)
|
|
144
|
+
else:
|
|
145
|
+
tmp_k = memory_obj.tensor[0].to(slot_mapping.device)
|
|
146
|
+
tmp_v = memory_obj.tensor[1].to(slot_mapping.device)
|
|
147
|
+
total_blocks = self.num_blocks * self.block_size
|
|
148
|
+
d = self.num_heads * self.head_size
|
|
149
|
+
for i, (kcache, vcache) in enumerate(self.kvcaches):
|
|
150
|
+
kcache.view(total_blocks, d).index_copy_(0, slices, tmp_k[i])
|
|
151
|
+
vcache.view(total_blocks, d).index_copy_(0, slices, tmp_v[i])
|
|
152
|
+
|
|
153
|
+
def from_gpu(self, memory_obj: MemoryObj, start: int, end: int, **kwargs):
|
|
154
|
+
"""Expect a kwarg 'kvcaches' which is a nested tuple of K and V tensors.
|
|
155
|
+
The kvcaches should correspond to the "WHOLE token sequence".
|
|
156
|
+
|
|
157
|
+
Will set the memory_obj.metadata.fmt to MemoryFormat.KV_MLA_FMT
|
|
158
|
+
if use_mla is True.
|
|
159
|
+
|
|
160
|
+
Note:
|
|
161
|
+
1. This function expects the 'slot_mapping' is a "full slot mapping"
|
|
162
|
+
where it's length is the same as the whole token sequence.
|
|
163
|
+
2. In the case that there is prefix caching, slot_mapping will starts
|
|
164
|
+
with -1s until the end of the matched prefix. The start and end
|
|
165
|
+
should NEVER overlap with the prefix caching (which means the
|
|
166
|
+
underlying CUDA kernel will never see -1 in slot_mapping)
|
|
167
|
+
|
|
168
|
+
:raises ValueError: If 'kvcaches' is not provided in kwargs,
|
|
169
|
+
:raises AssertionError: If the memory object does not have a tensor.
|
|
170
|
+
:raises ValueError: If 'slot_mapping' is not provided in kwargs.
|
|
171
|
+
"""
|
|
172
|
+
assert memory_obj.tensor is not None
|
|
173
|
+
|
|
174
|
+
self.initialize_kvcaches_ptr(**kwargs)
|
|
175
|
+
assert self.kvcaches is not None, (
|
|
176
|
+
"kvcaches should be provided in kwargs or initialized beforehand."
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
if "slot_mapping" not in kwargs:
|
|
180
|
+
raise ValueError("'slot_mapping' should be provided in kwargs.")
|
|
181
|
+
|
|
182
|
+
slot_mapping: torch.Tensor = kwargs["slot_mapping"]
|
|
183
|
+
slices = slot_mapping[start:end]
|
|
184
|
+
self._initialize_attributes(self.kvcaches)
|
|
185
|
+
self._validate_memory_format(memory_obj)
|
|
186
|
+
|
|
187
|
+
if self.use_mla:
|
|
188
|
+
total_blocks = self.num_blocks * self.block_size
|
|
189
|
+
tmp = torch.stack(
|
|
190
|
+
[
|
|
191
|
+
kvcache.view(total_blocks, self.head_size).index_select(0, slices)
|
|
192
|
+
for kvcache in self.kvcaches
|
|
193
|
+
]
|
|
194
|
+
)
|
|
195
|
+
else:
|
|
196
|
+
total_blocks = self.num_blocks * self.block_size
|
|
197
|
+
d = self.num_heads * self.head_size
|
|
198
|
+
tmp_k = torch.stack(
|
|
199
|
+
[
|
|
200
|
+
kvcache[0].view(total_blocks, d).index_select(0, slices)
|
|
201
|
+
for kvcache in self.kvcaches
|
|
202
|
+
]
|
|
203
|
+
)
|
|
204
|
+
tmp_v = torch.stack(
|
|
205
|
+
[
|
|
206
|
+
kvcache[1].view(total_blocks, d).index_select(0, slices)
|
|
207
|
+
for kvcache in self.kvcaches
|
|
208
|
+
]
|
|
209
|
+
)
|
|
210
|
+
tmp = torch.stack([tmp_k, tmp_v])
|
|
211
|
+
memory_obj.tensor.copy_(tmp, non_blocking=True)
|
|
212
|
+
|
|
213
|
+
if not memory_obj.tensor.is_xpu:
|
|
214
|
+
# Force a synchronize if the target buffer is NOT XPU device
|
|
215
|
+
# NOTE: for better performance, we may not want to sync for every
|
|
216
|
+
# memory object
|
|
217
|
+
torch.xpu.synchronize()
|
|
218
|
+
|
|
219
|
+
if self.use_mla:
|
|
220
|
+
memory_obj.metadata.fmt = MemoryFormat.KV_MLA_FMT
|
|
221
|
+
|
|
222
|
+
# TODO(Jiayi): need to optimize to enable real batching
|
|
223
|
+
def batched_to_gpu(self, memory_objs, starts, ends, **kwargs):
|
|
224
|
+
for memory_obj, start, end in zip(memory_objs, starts, ends, strict=False):
|
|
225
|
+
self.to_gpu(memory_obj, start, end, **kwargs)
|
|
226
|
+
|
|
227
|
+
def get_shape(self, num_tokens: int) -> torch.Size:
|
|
228
|
+
"""Get the shape of the data given the number of tokens.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
num_tokens: The number of tokens in the data.
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
The shape of the KV cache data.
|
|
235
|
+
|
|
236
|
+
Raises:
|
|
237
|
+
RuntimeError: If attributes have not been initialized yet
|
|
238
|
+
(i.e., no kv_caches have been seen).
|
|
239
|
+
"""
|
|
240
|
+
if not self._attributes_initialized:
|
|
241
|
+
raise RuntimeError(
|
|
242
|
+
"Cannot determine shape before attributes are initialized. "
|
|
243
|
+
"Call to_gpu or from_gpu first so that _initialize_attributes "
|
|
244
|
+
"can discover the KV cache layout."
|
|
245
|
+
)
|
|
246
|
+
kv_size = 1 if self.use_mla else 2
|
|
247
|
+
return torch.Size([kv_size, self.num_layers, num_tokens, self.hidden_dim_size])
|
|
248
|
+
|
|
249
|
+
def _validate_memory_format(self, memory_obj: MemoryObj) -> None:
|
|
250
|
+
"""Validate that the memory object has the expected format.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
memory_obj: The memory object to validate.
|
|
254
|
+
|
|
255
|
+
Raises:
|
|
256
|
+
ValueError: If the memory format does not match the expected
|
|
257
|
+
format based on whether MLA is in use.
|
|
258
|
+
"""
|
|
259
|
+
if self.use_mla:
|
|
260
|
+
if memory_obj.metadata.fmt != MemoryFormat.KV_MLA_FMT:
|
|
261
|
+
raise ValueError(
|
|
262
|
+
"The memory object should be in KV_MLA_FMT format in"
|
|
263
|
+
" order to be processed by VLLMPagedMemXPUConnectorV2"
|
|
264
|
+
)
|
|
265
|
+
else:
|
|
266
|
+
if memory_obj.metadata.fmt != MemoryFormat.KV_2LTD:
|
|
267
|
+
raise ValueError(
|
|
268
|
+
"The memory object should be in KV_2LTD format in"
|
|
269
|
+
" order to be processed by VLLMPagedMemXPUConnectorV2"
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
def _initialize_attributes(self, kv_caches: List[torch.Tensor]):
|
|
273
|
+
"""Initialize attributes from the kv_caches using utils functions.
|
|
274
|
+
|
|
275
|
+
Uses format discovery and utility functions from utils.py to
|
|
276
|
+
extract all KV cache parameters lazily on first use.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
kv_caches: The KV cache tensors from which to discover
|
|
280
|
+
the cache layout and parameters.
|
|
281
|
+
"""
|
|
282
|
+
if self._attributes_initialized:
|
|
283
|
+
return
|
|
284
|
+
|
|
285
|
+
self.device = kv_caches[0].device
|
|
286
|
+
assert self.device.type == "xpu", "The device should be XPU."
|
|
287
|
+
|
|
288
|
+
self.gpu_kv_format = discover_gpu_kv_format(kv_caches, EngineType.VLLM)
|
|
289
|
+
self.num_layers = get_num_layers(kv_caches, self.gpu_kv_format)
|
|
290
|
+
self.num_blocks = get_num_blocks(kv_caches, self.gpu_kv_format)
|
|
291
|
+
self.block_size = get_block_size(kv_caches, self.gpu_kv_format)
|
|
292
|
+
self.page_buffer_size = get_page_buffer_size(kv_caches, self.gpu_kv_format)
|
|
293
|
+
self.hidden_dim_size = get_hidden_dim_size(kv_caches, self.gpu_kv_format)
|
|
294
|
+
self.head_size = get_head_size(kv_caches, self.gpu_kv_format)
|
|
295
|
+
self.use_mla = is_mla(self.gpu_kv_format)
|
|
296
|
+
self.dtype = get_dtype(kv_caches, self.gpu_kv_format)
|
|
297
|
+
self.num_heads = (
|
|
298
|
+
1 if self.use_mla else get_num_heads(kv_caches, self.gpu_kv_format)
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
self._attributes_initialized = True
|
|
302
|
+
logger.info(
|
|
303
|
+
"XPU: attributes initialized - format: %s, "
|
|
304
|
+
"num_layers: %d, num_blocks: %d, block_size: %d, "
|
|
305
|
+
"page_buffer_size: %d, hidden_dim_size: %d, head_size: %d, "
|
|
306
|
+
"use_mla: %s, dtype: %s, num_heads: %d",
|
|
307
|
+
self.gpu_kv_format,
|
|
308
|
+
self.num_layers,
|
|
309
|
+
self.num_blocks,
|
|
310
|
+
self.block_size,
|
|
311
|
+
self.page_buffer_size,
|
|
312
|
+
self.hidden_dim_size,
|
|
313
|
+
self.head_size,
|
|
314
|
+
self.use_mla,
|
|
315
|
+
self.dtype,
|
|
316
|
+
self.num_heads,
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
class VLLMPagedMemLayerwiseXPUConnector(GPUConnectorInterface):
|
|
321
|
+
"""
|
|
322
|
+
Layerwise paged KV connector for XPU.
|
|
323
|
+
|
|
324
|
+
Implements the *same generator contract* as VLLMPagedMemLayerwiseGPUConnector:
|
|
325
|
+
- batched_to_gpu(...) yields num_layers + 2 times
|
|
326
|
+
- batched_from_gpu(...) yields num_layers + 1 times
|
|
327
|
+
|
|
328
|
+
Transfer is implemented with pure torch ops (index_copy_/index_select).
|
|
329
|
+
"""
|
|
330
|
+
|
|
331
|
+
def __init__(
|
|
332
|
+
self,
|
|
333
|
+
hidden_dim_size: int,
|
|
334
|
+
num_layers: int,
|
|
335
|
+
use_xpu: bool = False,
|
|
336
|
+
**kwargs,
|
|
337
|
+
):
|
|
338
|
+
self.hidden_dim_size = hidden_dim_size
|
|
339
|
+
self.num_layers = num_layers
|
|
340
|
+
self.use_xpu = use_xpu
|
|
341
|
+
|
|
342
|
+
assert "chunk_size" in kwargs, "chunk_size should be provided."
|
|
343
|
+
assert "dtype" in kwargs, "dtype should be provided."
|
|
344
|
+
assert "device" in kwargs, "device should be provided."
|
|
345
|
+
|
|
346
|
+
self.dtype = kwargs["dtype"]
|
|
347
|
+
self.device = kwargs["device"]
|
|
348
|
+
self.use_mla = "use_mla" in kwargs and kwargs["use_mla"]
|
|
349
|
+
|
|
350
|
+
self.kvcaches: Optional[List[torch.Tensor]] = None
|
|
351
|
+
|
|
352
|
+
# XPU streams
|
|
353
|
+
self.load_stream = torch.xpu.Stream()
|
|
354
|
+
self.store_stream = torch.xpu.Stream()
|
|
355
|
+
|
|
356
|
+
# Optional device staging buffer allocator (same pattern as CUDA class)
|
|
357
|
+
self.gpu_buffer_allocator: Optional[MemoryAllocatorInterface] = None
|
|
358
|
+
|
|
359
|
+
@classmethod
|
|
360
|
+
def from_metadata(
|
|
361
|
+
cls,
|
|
362
|
+
metadata: LMCacheMetadata,
|
|
363
|
+
use_xpu: bool = False,
|
|
364
|
+
device: Optional[torch.device] = None,
|
|
365
|
+
) -> "VLLMPagedMemLayerwiseXPUConnector":
|
|
366
|
+
num_layers = metadata.kv_shape[0]
|
|
367
|
+
num_kv_head = metadata.kv_shape[3]
|
|
368
|
+
head_size = metadata.kv_shape[4]
|
|
369
|
+
hidden_dim_size = num_kv_head * head_size
|
|
370
|
+
return cls(
|
|
371
|
+
hidden_dim_size=hidden_dim_size,
|
|
372
|
+
num_layers=num_layers,
|
|
373
|
+
use_xpu=use_xpu,
|
|
374
|
+
chunk_size=metadata.kv_shape[2],
|
|
375
|
+
dtype=metadata.kv_dtype,
|
|
376
|
+
device=device,
|
|
377
|
+
use_mla=metadata.use_mla,
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
def _validate_format_transition(self, mem, target_fmt):
|
|
381
|
+
current_fmt = mem.metadata.fmt
|
|
382
|
+
|
|
383
|
+
if (current_fmt, target_fmt) not in ALLOWED_FORMAT_TRANSITIONS:
|
|
384
|
+
raise ValueError(
|
|
385
|
+
f"Invalid KV format transition: {current_fmt} -> {target_fmt}"
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
def _lazy_initialize_buffer(self, kv_caches: List[torch.Tensor]) -> None:
|
|
389
|
+
# Buffer allocator only needed when use_xpu=True (device staging)
|
|
390
|
+
if self.use_xpu and self.gpu_buffer_allocator is None:
|
|
391
|
+
# First Party
|
|
392
|
+
from lmcache.v1.memory_management import XPUMemoryAllocator
|
|
393
|
+
|
|
394
|
+
# Derive size from first layer KV tensor
|
|
395
|
+
layer0 = kv_caches[0]
|
|
396
|
+
derived_bytes = layer0.numel() * layer0.element_size()
|
|
397
|
+
|
|
398
|
+
# Allow override via env variable
|
|
399
|
+
staging_bytes = int(
|
|
400
|
+
os.getenv("LMCACHE_GPU_STAGING_BUFFER_BYTES", derived_bytes)
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
logger.info(
|
|
404
|
+
"Initializing staging buffer (derived=%d bytes, final=%d bytes)",
|
|
405
|
+
derived_bytes,
|
|
406
|
+
staging_bytes,
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
self.gpu_buffer_allocator = XPUMemoryAllocator(
|
|
410
|
+
size=staging_bytes,
|
|
411
|
+
device=self.device,
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
def to_gpu(self, memory_obj: MemoryObj, start: int, end: int, **kwargs):
|
|
415
|
+
raise NotImplementedError("Layerwise uses batched_to_gpu(generator).")
|
|
416
|
+
|
|
417
|
+
def from_gpu(self, memory_obj: MemoryObj, start: int, end: int, **kwargs):
|
|
418
|
+
raise NotImplementedError("Layerwise uses batched_from_gpu(generator).")
|
|
419
|
+
|
|
420
|
+
def _batched_to_gpu_gen(self, starts: List[int], ends: List[int], **kwargs):
|
|
421
|
+
"""
|
|
422
|
+
Generator: CPU token2d -> (optional XPU staging) -> XPU paged KV (per layer).
|
|
423
|
+
"""
|
|
424
|
+
self.initialize_kvcaches_ptr(**kwargs)
|
|
425
|
+
assert self.kvcaches is not None
|
|
426
|
+
|
|
427
|
+
if "slot_mapping" not in kwargs:
|
|
428
|
+
raise ValueError("'slot_mapping' should be provided in kwargs.")
|
|
429
|
+
if "sync" not in kwargs:
|
|
430
|
+
raise ValueError("'sync' should be provided in kwargs.")
|
|
431
|
+
|
|
432
|
+
slot_mapping: torch.Tensor = kwargs["slot_mapping"]
|
|
433
|
+
sync: bool = kwargs["sync"]
|
|
434
|
+
|
|
435
|
+
self._lazy_initialize_buffer(self.kvcaches)
|
|
436
|
+
|
|
437
|
+
def _ensure_xpu(t: torch.Tensor) -> torch.Tensor:
|
|
438
|
+
# Handle both torch.device('xpu:0') and string devices consistently.
|
|
439
|
+
if t is None:
|
|
440
|
+
return t
|
|
441
|
+
if t.device != self.device:
|
|
442
|
+
# non_blocking is fine; will be blocking
|
|
443
|
+
# if underlying memory isn't pinned
|
|
444
|
+
return t.to(self.device, non_blocking=True)
|
|
445
|
+
return t
|
|
446
|
+
|
|
447
|
+
# Build a single contiguous mapping in the SAME order we will pack chunks.
|
|
448
|
+
slot_mapping_chunks = [
|
|
449
|
+
slot_mapping[s:e] for s, e in zip(starts, ends, strict=False)
|
|
450
|
+
]
|
|
451
|
+
slot_mapping_full = torch.cat(slot_mapping_chunks, dim=0)
|
|
452
|
+
|
|
453
|
+
# Move mapping ONCE to device (fixes multiple small H2D copies).
|
|
454
|
+
slot_mapping_full = _ensure_xpu(slot_mapping_full)
|
|
455
|
+
|
|
456
|
+
num_tokens = int(slot_mapping_full.numel())
|
|
457
|
+
if num_tokens <= 0:
|
|
458
|
+
for _ in range(self.num_layers):
|
|
459
|
+
_ = yield
|
|
460
|
+
yield
|
|
461
|
+
if sync:
|
|
462
|
+
torch.xpu.current_stream().wait_stream(self.load_stream)
|
|
463
|
+
yield
|
|
464
|
+
return
|
|
465
|
+
|
|
466
|
+
tmp_gpu_buffer_obj: Optional[MemoryObj] = None
|
|
467
|
+
if self.use_xpu:
|
|
468
|
+
# First Party
|
|
469
|
+
from lmcache.v1.memory_management import MemoryFormat
|
|
470
|
+
|
|
471
|
+
buffer_shape = self.get_shape(num_tokens)
|
|
472
|
+
assert self.gpu_buffer_allocator is not None
|
|
473
|
+
requested_bytes = (
|
|
474
|
+
int(buffer_shape.numel())
|
|
475
|
+
* torch.empty((), dtype=self.dtype).element_size()
|
|
476
|
+
)
|
|
477
|
+
allocator_tensor = getattr(self.gpu_buffer_allocator, "tensor", None)
|
|
478
|
+
capacity_bytes: Optional[int] = None
|
|
479
|
+
if isinstance(allocator_tensor, torch.Tensor):
|
|
480
|
+
capacity_bytes = int(
|
|
481
|
+
allocator_tensor.numel() * allocator_tensor.element_size()
|
|
482
|
+
)
|
|
483
|
+
allocator_backend = getattr(self.gpu_buffer_allocator, "allocator", None)
|
|
484
|
+
allocated_bytes = getattr(allocator_backend, "total_allocated_size", None)
|
|
485
|
+
tmp_gpu_buffer_obj = self.gpu_buffer_allocator.allocate(
|
|
486
|
+
buffer_shape, self.dtype, MemoryFormat.KV_T2D
|
|
487
|
+
)
|
|
488
|
+
if tmp_gpu_buffer_obj is None or tmp_gpu_buffer_obj.tensor is None:
|
|
489
|
+
raise RuntimeError(
|
|
490
|
+
"Failed to allocate XPU staging buffer for batched_to_gpu: "
|
|
491
|
+
f"requested_bytes={requested_bytes}, "
|
|
492
|
+
f"capacity_bytes={capacity_bytes}, "
|
|
493
|
+
f"allocated_bytes={allocated_bytes}, "
|
|
494
|
+
f"allocator_type={type(self.gpu_buffer_allocator).__name__}, "
|
|
495
|
+
f"allocator_tensor_device="
|
|
496
|
+
f"{getattr(allocator_tensor, 'device', None)}"
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
current_stream = torch.xpu.current_stream()
|
|
500
|
+
|
|
501
|
+
try:
|
|
502
|
+
for layer_id in range(self.num_layers):
|
|
503
|
+
memory_objs_layer = yield # List[MemoryObj] for this layer
|
|
504
|
+
|
|
505
|
+
if sync:
|
|
506
|
+
current_stream.wait_stream(self.load_stream)
|
|
507
|
+
|
|
508
|
+
with torch.xpu.stream(self.load_stream):
|
|
509
|
+
dst_layer = self.kvcaches[layer_id]
|
|
510
|
+
if self.use_mla:
|
|
511
|
+
dst_flat = cast(
|
|
512
|
+
torch.Tensor,
|
|
513
|
+
_get_head_size_view(dst_layer, use_mla=True),
|
|
514
|
+
)
|
|
515
|
+
else:
|
|
516
|
+
dst_k_flat, dst_v_flat = _get_head_size_view( # type: ignore[misc]
|
|
517
|
+
dst_layer, use_mla=False
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
cursor = 0
|
|
521
|
+
|
|
522
|
+
if self.use_xpu:
|
|
523
|
+
assert tmp_gpu_buffer_obj is not None
|
|
524
|
+
staged = tmp_gpu_buffer_obj.tensor
|
|
525
|
+
assert staged is not None
|
|
526
|
+
|
|
527
|
+
for s, e, mem in zip(
|
|
528
|
+
starts, ends, memory_objs_layer, strict=False
|
|
529
|
+
):
|
|
530
|
+
assert mem.tensor is not None
|
|
531
|
+
n = int(e - s)
|
|
532
|
+
if n <= 0:
|
|
533
|
+
continue
|
|
534
|
+
|
|
535
|
+
src = _ensure_xpu(mem.tensor)
|
|
536
|
+
|
|
537
|
+
staged[cursor : cursor + n].copy_(src, non_blocking=True)
|
|
538
|
+
cursor += n
|
|
539
|
+
|
|
540
|
+
sl = slot_mapping_full # already intended to be on device
|
|
541
|
+
sl = _ensure_xpu(sl)
|
|
542
|
+
|
|
543
|
+
if self.use_mla:
|
|
544
|
+
staged_xpu = _ensure_xpu(staged)
|
|
545
|
+
if staged_xpu.dim() == 2:
|
|
546
|
+
dst_flat.index_copy_(0, sl, staged_xpu)
|
|
547
|
+
elif staged_xpu.dim() == 3 and staged_xpu.shape[0] == 1:
|
|
548
|
+
dst_flat.index_copy_(0, sl, staged_xpu[0])
|
|
549
|
+
else:
|
|
550
|
+
raise ValueError(
|
|
551
|
+
f"Unexpected MLA staged tensor: {staged_xpu.shape}"
|
|
552
|
+
)
|
|
553
|
+
else:
|
|
554
|
+
k_tok, v_tok = _split_token2d_kv(staged)
|
|
555
|
+
|
|
556
|
+
# Make sure k_tok/v_tok are on XPU before index_copy_.
|
|
557
|
+
k_tok = _ensure_xpu(k_tok)
|
|
558
|
+
v_tok = _ensure_xpu(v_tok)
|
|
559
|
+
|
|
560
|
+
# Keep your reshape logic as-is (only triggers when needed)
|
|
561
|
+
if (
|
|
562
|
+
k_tok.dim() == 2
|
|
563
|
+
and dst_k_flat.dim() == 3
|
|
564
|
+
and k_tok.shape[1]
|
|
565
|
+
== dst_k_flat.shape[1] * dst_k_flat.shape[2]
|
|
566
|
+
):
|
|
567
|
+
k_tok = k_tok.reshape(
|
|
568
|
+
k_tok.shape[0],
|
|
569
|
+
dst_k_flat.shape[1],
|
|
570
|
+
dst_k_flat.shape[2],
|
|
571
|
+
)
|
|
572
|
+
if (
|
|
573
|
+
v_tok.dim() == 2
|
|
574
|
+
and dst_v_flat.dim() == 3
|
|
575
|
+
and v_tok.shape[1]
|
|
576
|
+
== dst_v_flat.shape[1] * dst_v_flat.shape[2]
|
|
577
|
+
):
|
|
578
|
+
v_tok = v_tok.reshape(
|
|
579
|
+
v_tok.shape[0],
|
|
580
|
+
dst_v_flat.shape[1],
|
|
581
|
+
dst_v_flat.shape[2],
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
dst_k_flat.index_copy_(0, sl, k_tok)
|
|
585
|
+
dst_v_flat.index_copy_(0, sl, v_tok)
|
|
586
|
+
|
|
587
|
+
else:
|
|
588
|
+
for s, e, mem in zip(
|
|
589
|
+
starts, ends, memory_objs_layer, strict=False
|
|
590
|
+
):
|
|
591
|
+
assert mem.tensor is not None
|
|
592
|
+
n = int(e - s)
|
|
593
|
+
if n <= 0:
|
|
594
|
+
continue
|
|
595
|
+
|
|
596
|
+
src = _ensure_xpu(mem.tensor)
|
|
597
|
+
sl = slot_mapping_full[cursor : cursor + n]
|
|
598
|
+
sl = _ensure_xpu(sl)
|
|
599
|
+
cursor += n
|
|
600
|
+
|
|
601
|
+
if self.use_mla:
|
|
602
|
+
if src.dim() == 2:
|
|
603
|
+
dst_flat.index_copy_(0, sl, src)
|
|
604
|
+
elif src.dim() == 3 and src.shape[0] == 1:
|
|
605
|
+
dst_flat.index_copy_(0, sl, src[0])
|
|
606
|
+
else:
|
|
607
|
+
raise ValueError(
|
|
608
|
+
f"Unexpected MLA token tensor: {src.shape}"
|
|
609
|
+
)
|
|
610
|
+
else:
|
|
611
|
+
k_tok, v_tok = _split_token2d_kv(src)
|
|
612
|
+
k_tok = _ensure_xpu(k_tok)
|
|
613
|
+
v_tok = _ensure_xpu(v_tok)
|
|
614
|
+
|
|
615
|
+
if (
|
|
616
|
+
k_tok.dim() == 2
|
|
617
|
+
and dst_k_flat.dim() == 3
|
|
618
|
+
and k_tok.shape[1]
|
|
619
|
+
== dst_k_flat.shape[1] * dst_k_flat.shape[2]
|
|
620
|
+
):
|
|
621
|
+
k_tok = k_tok.reshape(
|
|
622
|
+
k_tok.shape[0],
|
|
623
|
+
dst_k_flat.shape[1],
|
|
624
|
+
dst_k_flat.shape[2],
|
|
625
|
+
)
|
|
626
|
+
if (
|
|
627
|
+
v_tok.dim() == 2
|
|
628
|
+
and dst_v_flat.dim() == 3
|
|
629
|
+
and v_tok.shape[1]
|
|
630
|
+
== dst_v_flat.shape[1] * dst_v_flat.shape[2]
|
|
631
|
+
):
|
|
632
|
+
v_tok = v_tok.reshape(
|
|
633
|
+
v_tok.shape[0],
|
|
634
|
+
dst_v_flat.shape[1],
|
|
635
|
+
dst_v_flat.shape[2],
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
dst_k_flat.index_copy_(0, sl, k_tok)
|
|
639
|
+
dst_v_flat.index_copy_(0, sl, v_tok)
|
|
640
|
+
|
|
641
|
+
yield
|
|
642
|
+
|
|
643
|
+
if sync:
|
|
644
|
+
current_stream.wait_stream(self.load_stream)
|
|
645
|
+
finally:
|
|
646
|
+
if tmp_gpu_buffer_obj is not None:
|
|
647
|
+
tmp_gpu_buffer_obj.ref_count_down()
|
|
648
|
+
|
|
649
|
+
yield
|
|
650
|
+
|
|
651
|
+
def batched_from_gpu( # type: ignore[override]
|
|
652
|
+
self,
|
|
653
|
+
memory_objs: List[List[MemoryObj]],
|
|
654
|
+
starts: List[int],
|
|
655
|
+
ends: List[int],
|
|
656
|
+
**kwargs,
|
|
657
|
+
):
|
|
658
|
+
"""
|
|
659
|
+
Generator: XPU paged KV -> (optional XPU staging) -> CPU token2d (per layer).
|
|
660
|
+
"""
|
|
661
|
+
self.initialize_kvcaches_ptr(**kwargs)
|
|
662
|
+
assert self.kvcaches is not None
|
|
663
|
+
|
|
664
|
+
if "slot_mapping" not in kwargs:
|
|
665
|
+
raise ValueError("'slot_mapping' should be provided in kwargs.")
|
|
666
|
+
if "sync" not in kwargs:
|
|
667
|
+
raise ValueError("'sync' should be provided in kwargs.")
|
|
668
|
+
|
|
669
|
+
slot_mapping: torch.Tensor = kwargs["slot_mapping"]
|
|
670
|
+
sync: bool = kwargs["sync"]
|
|
671
|
+
|
|
672
|
+
self._lazy_initialize_buffer(self.kvcaches)
|
|
673
|
+
|
|
674
|
+
current_stream = torch.xpu.current_stream()
|
|
675
|
+
|
|
676
|
+
# ---- helpers (keep local to minimize file-wide changes) ----
|
|
677
|
+
def _flatten_last2_if_needed(
|
|
678
|
+
src: torch.Tensor, dst: torch.Tensor
|
|
679
|
+
) -> torch.Tensor:
|
|
680
|
+
"""
|
|
681
|
+
Make src match dst for the common KV layouts:
|
|
682
|
+
- src: [..., H, HS] -> dst: [..., H*HS]
|
|
683
|
+
- or already matches
|
|
684
|
+
"""
|
|
685
|
+
if src.shape == dst.shape:
|
|
686
|
+
return src
|
|
687
|
+
|
|
688
|
+
# dst has one less trailing dim: [..., D] where D=H*HS
|
|
689
|
+
if src.dim() == dst.dim() + 1:
|
|
690
|
+
# e.g., src [..., 8, 128] -> dst [..., 1024]
|
|
691
|
+
if dst.shape == (*src.shape[:-2], src.shape[-2] * src.shape[-1]):
|
|
692
|
+
return src.reshape(*src.shape[:-2], -1)
|
|
693
|
+
|
|
694
|
+
# same ndim but dst last dim is flattened (dst ends with D)
|
|
695
|
+
if src.dim() == dst.dim():
|
|
696
|
+
if (
|
|
697
|
+
dst.shape[:-1] == src.shape[:-2]
|
|
698
|
+
and dst.shape[-1] == src.shape[-2] * src.shape[-1]
|
|
699
|
+
):
|
|
700
|
+
return src.reshape(*src.shape[:-2], -1)
|
|
701
|
+
|
|
702
|
+
return src # caller will error if still incompatible
|
|
703
|
+
|
|
704
|
+
def _copy_kv_into_mem(
|
|
705
|
+
mem_tensor: torch.Tensor, k_src: torch.Tensor, v_src: torch.Tensor
|
|
706
|
+
) -> None:
|
|
707
|
+
"""
|
|
708
|
+
Copy K/V into mem.tensor supporting:
|
|
709
|
+
- [2, ..., D] (K in 0, V in 1)
|
|
710
|
+
- [..., 2, D] (K in [:,0,:], V in [:,1,:])
|
|
711
|
+
- [2, ..., H, HS] or [..., 2, H, HS] similarly
|
|
712
|
+
"""
|
|
713
|
+
if mem_tensor.dim() < 3:
|
|
714
|
+
raise ValueError(
|
|
715
|
+
f"Unexpected output token2d layout: {mem_tensor.shape}"
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
# Case A: mem is [2, ...]
|
|
719
|
+
if mem_tensor.shape[0] == 2:
|
|
720
|
+
k_dst = mem_tensor[0]
|
|
721
|
+
v_dst = mem_tensor[1]
|
|
722
|
+
k_src2 = _flatten_last2_if_needed(k_src, k_dst)
|
|
723
|
+
v_src2 = _flatten_last2_if_needed(v_src, v_dst)
|
|
724
|
+
if k_src2.shape != k_dst.shape or v_src2.shape != v_dst.shape:
|
|
725
|
+
raise ValueError(
|
|
726
|
+
f"KV shape mismatch after reshape: "
|
|
727
|
+
f"k src {k_src.shape}->{k_src2.shape} vs dst {k_dst.shape}; "
|
|
728
|
+
f"v src {v_src.shape}->{v_src2.shape} vs dst {v_dst.shape}"
|
|
729
|
+
)
|
|
730
|
+
k_dst.copy_(k_src2.to(k_dst.device), non_blocking=True)
|
|
731
|
+
v_dst.copy_(v_src2.to(v_dst.device), non_blocking=True)
|
|
732
|
+
return
|
|
733
|
+
|
|
734
|
+
# Case B: mem is [..., 2, ...]
|
|
735
|
+
if mem_tensor.shape[1] == 2:
|
|
736
|
+
k_dst = mem_tensor[:, 0, ...]
|
|
737
|
+
v_dst = mem_tensor[:, 1, ...]
|
|
738
|
+
k_src2 = _flatten_last2_if_needed(k_src, k_dst)
|
|
739
|
+
v_src2 = _flatten_last2_if_needed(v_src, v_dst)
|
|
740
|
+
if k_src2.shape != k_dst.shape or v_src2.shape != v_dst.shape:
|
|
741
|
+
raise ValueError(
|
|
742
|
+
f"KV shape mismatch after reshape: "
|
|
743
|
+
f"k src {k_src.shape}->{k_src2.shape} vs dst {k_dst.shape}; "
|
|
744
|
+
f"v src {v_src.shape}->{v_src2.shape} vs dst {v_dst.shape}"
|
|
745
|
+
)
|
|
746
|
+
k_dst.copy_(k_src2.to(k_dst.device), non_blocking=True)
|
|
747
|
+
v_dst.copy_(v_src2.to(v_dst.device), non_blocking=True)
|
|
748
|
+
return
|
|
749
|
+
|
|
750
|
+
raise ValueError(f"Unexpected output token2d layout: {mem_tensor.shape}")
|
|
751
|
+
|
|
752
|
+
slot_mapping_on_device = slot_mapping.to(self.device)
|
|
753
|
+
|
|
754
|
+
# Precompute “full” mapping for batched gather
|
|
755
|
+
# NOTE: this assumes starts/ends partition slot_mapping contiguously.
|
|
756
|
+
# If not contiguous, concatenation is still correct.
|
|
757
|
+
slot_mapping_full = torch.cat(
|
|
758
|
+
[slot_mapping_on_device[s:e] for s, e in zip(starts, ends, strict=False)],
|
|
759
|
+
dim=0,
|
|
760
|
+
)
|
|
761
|
+
total_tokens = int(slot_mapping_full.numel())
|
|
762
|
+
|
|
763
|
+
# Optional staging buffer (will be USED when self.use_xpu=True)
|
|
764
|
+
tmp_gpu_buffer_obj: Optional[MemoryObj] = None
|
|
765
|
+
if self.use_xpu:
|
|
766
|
+
# First Party
|
|
767
|
+
from lmcache.v1.memory_management import MemoryFormat
|
|
768
|
+
|
|
769
|
+
# buffer shape uses existing helper; must match how allocator expects KV_T2D
|
|
770
|
+
buffer_shape = self.get_shape(total_tokens)
|
|
771
|
+
assert self.gpu_buffer_allocator is not None
|
|
772
|
+
requested_bytes = (
|
|
773
|
+
int(buffer_shape.numel())
|
|
774
|
+
* torch.empty((), dtype=self.dtype).element_size()
|
|
775
|
+
)
|
|
776
|
+
allocator_tensor = getattr(self.gpu_buffer_allocator, "tensor", None)
|
|
777
|
+
capacity_bytes: Optional[int] = None
|
|
778
|
+
if isinstance(allocator_tensor, torch.Tensor):
|
|
779
|
+
capacity_bytes = int(
|
|
780
|
+
allocator_tensor.numel() * allocator_tensor.element_size()
|
|
781
|
+
)
|
|
782
|
+
allocator_backend = getattr(self.gpu_buffer_allocator, "allocator", None)
|
|
783
|
+
allocated_bytes = getattr(allocator_backend, "total_allocated_size", None)
|
|
784
|
+
tmp_gpu_buffer_obj = self.gpu_buffer_allocator.allocate(
|
|
785
|
+
buffer_shape, self.dtype, MemoryFormat.KV_T2D
|
|
786
|
+
)
|
|
787
|
+
if tmp_gpu_buffer_obj is None or tmp_gpu_buffer_obj.tensor is None:
|
|
788
|
+
raise RuntimeError(
|
|
789
|
+
"Failed to allocate XPU staging buffer for batched_from_gpu: "
|
|
790
|
+
f"requested_bytes={requested_bytes}, "
|
|
791
|
+
f"capacity_bytes={capacity_bytes}, "
|
|
792
|
+
f"allocated_bytes={allocated_bytes}, "
|
|
793
|
+
f"allocator_type={type(self.gpu_buffer_allocator).__name__}, "
|
|
794
|
+
f"allocator_tensor_device="
|
|
795
|
+
f"{getattr(allocator_tensor, 'device', None)}"
|
|
796
|
+
)
|
|
797
|
+
tmp = tmp_gpu_buffer_obj.tensor # staging tensor on device
|
|
798
|
+
|
|
799
|
+
try:
|
|
800
|
+
for layer_id in range(self.num_layers):
|
|
801
|
+
mem_layer = memory_objs[layer_id]
|
|
802
|
+
|
|
803
|
+
with torch.xpu.stream(self.store_stream):
|
|
804
|
+
self.store_stream.wait_stream(current_stream)
|
|
805
|
+
|
|
806
|
+
src_layer = self.kvcaches[layer_id]
|
|
807
|
+
|
|
808
|
+
if self.use_mla:
|
|
809
|
+
src_flat = cast(
|
|
810
|
+
torch.Tensor,
|
|
811
|
+
_get_head_size_view(src_layer, use_mla=True),
|
|
812
|
+
)
|
|
813
|
+
|
|
814
|
+
if self.use_xpu:
|
|
815
|
+
gathered_full = src_flat.index_select(0, slot_mapping_full)
|
|
816
|
+
# Write into tmp if possible, else fallback to per-chunk
|
|
817
|
+
tmp_src = (
|
|
818
|
+
_flatten_last2_if_needed(gathered_full, tmp)
|
|
819
|
+
if "tmp" in locals()
|
|
820
|
+
else gathered_full
|
|
821
|
+
)
|
|
822
|
+
if "tmp" in locals() and tmp_src.shape == tmp.shape:
|
|
823
|
+
tmp.copy_(tmp_src, non_blocking=True)
|
|
824
|
+
off = 0
|
|
825
|
+
for s, e, mem in zip(
|
|
826
|
+
starts, ends, mem_layer, strict=False
|
|
827
|
+
):
|
|
828
|
+
assert mem.tensor is not None
|
|
829
|
+
n = e - s
|
|
830
|
+
chunk = tmp[off : off + n]
|
|
831
|
+
off += n
|
|
832
|
+
mem.tensor.copy_(
|
|
833
|
+
chunk.to(mem.tensor.device), non_blocking=True
|
|
834
|
+
)
|
|
835
|
+
else:
|
|
836
|
+
for s, e, mem in zip(
|
|
837
|
+
starts, ends, mem_layer, strict=False
|
|
838
|
+
):
|
|
839
|
+
assert mem.tensor is not None
|
|
840
|
+
sl = slot_mapping_on_device[s:e]
|
|
841
|
+
gathered = src_flat.index_select(0, sl)
|
|
842
|
+
mem.tensor.copy_(
|
|
843
|
+
gathered.to(mem.tensor.device),
|
|
844
|
+
non_blocking=True,
|
|
845
|
+
)
|
|
846
|
+
else:
|
|
847
|
+
for s, e, mem in zip(starts, ends, mem_layer, strict=False):
|
|
848
|
+
assert mem.tensor is not None
|
|
849
|
+
sl = slot_mapping_on_device[s:e]
|
|
850
|
+
gathered = src_flat.index_select(0, sl)
|
|
851
|
+
mem.tensor.copy_(
|
|
852
|
+
gathered.to(mem.tensor.device), non_blocking=True
|
|
853
|
+
)
|
|
854
|
+
|
|
855
|
+
# Keep memory format metadata consistent for downstream checks.
|
|
856
|
+
target_fmt = MemoryFormat.KV_MLA_FMT
|
|
857
|
+
for mem in mem_layer:
|
|
858
|
+
self._validate_format_transition(mem, target_fmt)
|
|
859
|
+
mem.metadata.fmt = target_fmt
|
|
860
|
+
|
|
861
|
+
else:
|
|
862
|
+
src_k_flat, src_v_flat = _get_head_size_view(
|
|
863
|
+
src_layer, use_mla=False
|
|
864
|
+
)
|
|
865
|
+
|
|
866
|
+
if self.use_xpu:
|
|
867
|
+
k_full = src_k_flat.index_select(0, slot_mapping_full)
|
|
868
|
+
v_full = src_v_flat.index_select(0, slot_mapping_full)
|
|
869
|
+
|
|
870
|
+
# Slice from staging. If tmp exists and can hold
|
|
871
|
+
# the layout, use it; otherwise slice k/v directly.
|
|
872
|
+
off = 0
|
|
873
|
+
for s, e, mem in zip(starts, ends, mem_layer, strict=False):
|
|
874
|
+
assert mem.tensor is not None
|
|
875
|
+
n = e - s
|
|
876
|
+
|
|
877
|
+
k_chunk = k_full[off : off + n]
|
|
878
|
+
v_chunk = v_full[off : off + n]
|
|
879
|
+
off += n
|
|
880
|
+
|
|
881
|
+
_copy_kv_into_mem(mem.tensor, k_chunk, v_chunk)
|
|
882
|
+
|
|
883
|
+
else:
|
|
884
|
+
# per-chunk gather (original behavior);
|
|
885
|
+
# avoids per-iteration H2D slot_mapping transfers
|
|
886
|
+
for s, e, mem in zip(starts, ends, mem_layer, strict=False):
|
|
887
|
+
assert mem.tensor is not None
|
|
888
|
+
sl = slot_mapping_on_device[s:e]
|
|
889
|
+
k = src_k_flat.index_select(0, sl)
|
|
890
|
+
v = src_v_flat.index_select(0, sl)
|
|
891
|
+
_copy_kv_into_mem(mem.tensor, k, v)
|
|
892
|
+
|
|
893
|
+
if sync:
|
|
894
|
+
self.store_stream.synchronize()
|
|
895
|
+
yield
|
|
896
|
+
finally:
|
|
897
|
+
if tmp_gpu_buffer_obj is not None:
|
|
898
|
+
tmp_gpu_buffer_obj.ref_count_down()
|
|
899
|
+
|
|
900
|
+
yield
|
|
901
|
+
|
|
902
|
+
def batched_to_gpu(
|
|
903
|
+
self,
|
|
904
|
+
memory_objs: Union[
|
|
905
|
+
List[List[MemoryObj]], List[MemoryObj], List[int], None
|
|
906
|
+
] = None,
|
|
907
|
+
starts: Optional[List[int]] = None,
|
|
908
|
+
ends: Optional[List[int]] = None,
|
|
909
|
+
**kwargs,
|
|
910
|
+
):
|
|
911
|
+
return self._batched_to_gpu_gen(starts=starts or [], ends=ends or [], **kwargs)
|
|
912
|
+
|
|
913
|
+
def get_shape(self, num_tokens: int) -> torch.Size:
|
|
914
|
+
if self.use_mla:
|
|
915
|
+
return torch.Size([num_tokens, self.hidden_dim_size])
|
|
916
|
+
return torch.Size([num_tokens, 2, self.hidden_dim_size])
|