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,129 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
# Third Party
|
|
6
|
+
from vllm.attention import Attention
|
|
7
|
+
from vllm.v1.attention.backends.flash_attn import FlashAttentionImpl
|
|
8
|
+
from vllm.vllm_flash_attn import flash_attn_varlen_func, get_scheduler_metadata
|
|
9
|
+
import torch
|
|
10
|
+
|
|
11
|
+
# First Party
|
|
12
|
+
from lmcache.v1.compute.attention.abstract import AttentionInterface
|
|
13
|
+
from lmcache.v1.compute.attention.metadata import LMCFlashAttnMetadata
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
# First Party
|
|
17
|
+
from lmcache.v1.compute.attention.metadata import LMCAttnMetadata
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class LMCFlashAttnBackend(AttentionInterface):
|
|
21
|
+
"""
|
|
22
|
+
FlashAttention backend for LMCache.
|
|
23
|
+
This backend uses the FlashAttention implementation
|
|
24
|
+
for efficient attention computation.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
vllm_attn: Attention,
|
|
30
|
+
):
|
|
31
|
+
self.vllm_attn = vllm_attn
|
|
32
|
+
self.vllm_attn_impl: FlashAttentionImpl = vllm_attn.impl
|
|
33
|
+
|
|
34
|
+
# TODO(Jiayi): remove this hardcode
|
|
35
|
+
self.aot_schedule = False
|
|
36
|
+
|
|
37
|
+
idx = torch.cuda.current_device()
|
|
38
|
+
self.device = torch.device(f"cuda:{idx}")
|
|
39
|
+
|
|
40
|
+
def forward_contiguous(
|
|
41
|
+
self,
|
|
42
|
+
query: torch.Tensor,
|
|
43
|
+
key: torch.Tensor,
|
|
44
|
+
value: torch.Tensor,
|
|
45
|
+
output: torch.Tensor,
|
|
46
|
+
attn_metadata: "LMCAttnMetadata",
|
|
47
|
+
**kwargs,
|
|
48
|
+
) -> torch.Tensor:
|
|
49
|
+
assert isinstance(attn_metadata, LMCFlashAttnMetadata)
|
|
50
|
+
|
|
51
|
+
cu_seqlens_q = attn_metadata.query_start_loc
|
|
52
|
+
seqused_k = attn_metadata.seq_lens
|
|
53
|
+
cu_seqlens_k = attn_metadata.cu_seqlens_k
|
|
54
|
+
max_seqlen_q = attn_metadata.max_query_len
|
|
55
|
+
max_seqlen_k = attn_metadata.max_seq_len
|
|
56
|
+
|
|
57
|
+
descale_shape = (cu_seqlens_q.shape[0] - 1, key.shape[1])
|
|
58
|
+
|
|
59
|
+
# TODO(Jiayi): Figure out how to use aot_schedule.
|
|
60
|
+
scheduler_metadata = self._schedule(
|
|
61
|
+
batch_size=1, # NOTE(Jiayi): Assuming batch size is 1,
|
|
62
|
+
# since we are processing request by request.
|
|
63
|
+
cu_query_lens=cu_seqlens_q,
|
|
64
|
+
max_query_len=max_seqlen_q,
|
|
65
|
+
seqlens=seqused_k,
|
|
66
|
+
max_seq_len=max_seqlen_k,
|
|
67
|
+
causal=True, # Assuming causal attention
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
flash_attn_varlen_func(
|
|
71
|
+
q=query, # contiguous
|
|
72
|
+
k=key, # contiguous
|
|
73
|
+
v=value, # contiguous
|
|
74
|
+
out=output,
|
|
75
|
+
cu_seqlens_q=cu_seqlens_q,
|
|
76
|
+
max_seqlen_q=max_seqlen_q,
|
|
77
|
+
cu_seqlens_k=cu_seqlens_k,
|
|
78
|
+
# seqused_k=seqused_k,
|
|
79
|
+
max_seqlen_k=max_seqlen_k,
|
|
80
|
+
softmax_scale=self.vllm_attn_impl.scale,
|
|
81
|
+
causal=True,
|
|
82
|
+
alibi_slopes=self.vllm_attn_impl.alibi_slopes,
|
|
83
|
+
window_size=self.vllm_attn_impl.sliding_window,
|
|
84
|
+
block_table=None,
|
|
85
|
+
softcap=self.vllm_attn_impl.logits_soft_cap,
|
|
86
|
+
scheduler_metadata=scheduler_metadata,
|
|
87
|
+
fa_version=self.vllm_attn_impl.vllm_flash_attn_version,
|
|
88
|
+
q_descale=self.vllm_attn._q_scale.expand(descale_shape),
|
|
89
|
+
k_descale=self.vllm_attn._k_scale.expand(descale_shape),
|
|
90
|
+
v_descale=self.vllm_attn._v_scale.expand(descale_shape),
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
return output
|
|
94
|
+
|
|
95
|
+
def _schedule(
|
|
96
|
+
self, batch_size, cu_query_lens, max_query_len, seqlens, max_seq_len, causal
|
|
97
|
+
):
|
|
98
|
+
if self.aot_schedule:
|
|
99
|
+
return get_scheduler_metadata(
|
|
100
|
+
batch_size=batch_size,
|
|
101
|
+
max_seqlen_q=max_query_len,
|
|
102
|
+
max_seqlen_k=max_seq_len,
|
|
103
|
+
cache_seqlens=seqlens,
|
|
104
|
+
num_heads_q=self.vllm_attn_impl.num_heads_q,
|
|
105
|
+
num_heads_kv=self.vllm_attn_impl.num_heads_kv,
|
|
106
|
+
headdim=self.vllm_attn_impl.headdim,
|
|
107
|
+
page_size=self.vllm_attn_impl.block_size,
|
|
108
|
+
cu_seqlens_q=cu_query_lens,
|
|
109
|
+
causal=causal,
|
|
110
|
+
window_size=self.vllm_attn_impl.aot_sliding_window,
|
|
111
|
+
)
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
def init_attn_metadata(
|
|
115
|
+
self,
|
|
116
|
+
input_ids: torch.tensor,
|
|
117
|
+
**kwargs,
|
|
118
|
+
) -> LMCFlashAttnMetadata:
|
|
119
|
+
seq_len = input_ids.shape[0]
|
|
120
|
+
device = input_ids.device
|
|
121
|
+
return LMCFlashAttnMetadata(
|
|
122
|
+
query_start_loc=torch.tensor(
|
|
123
|
+
[0, seq_len], dtype=torch.int32, device=device
|
|
124
|
+
),
|
|
125
|
+
seq_lens=torch.tensor([seq_len], device=device),
|
|
126
|
+
cu_seqlens_k=torch.tensor([0, seq_len], dtype=torch.int32, device=device),
|
|
127
|
+
max_query_len=seq_len,
|
|
128
|
+
max_seq_len=seq_len,
|
|
129
|
+
)
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
from typing import TYPE_CHECKING, Optional, Tuple, Union
|
|
4
|
+
import math
|
|
5
|
+
|
|
6
|
+
# Third Party
|
|
7
|
+
from flashinfer import VariableBlockSparseAttentionWrapper
|
|
8
|
+
from flashinfer.page import block_sparse_indices_to_vector_sparse_offsets
|
|
9
|
+
from flashinfer.utils import (
|
|
10
|
+
TensorLayout,
|
|
11
|
+
_check_pos_encoding_mode,
|
|
12
|
+
check_shape_dtype_device,
|
|
13
|
+
device_support_pdl,
|
|
14
|
+
)
|
|
15
|
+
from vllm.attention import Attention
|
|
16
|
+
from vllm.v1.attention.backends.flashinfer import FlashInferImpl
|
|
17
|
+
import flashinfer
|
|
18
|
+
import torch
|
|
19
|
+
|
|
20
|
+
# First Party
|
|
21
|
+
from lmcache.v1.compute.attention.abstract import AttentionInterface
|
|
22
|
+
from lmcache.v1.compute.attention.metadata import LMCFlashInferSparseMetadata
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
# First Party
|
|
26
|
+
from lmcache.v1.compute.attention.metadata import LMCAttnMetadata
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# NOTE(Jiayi): This flashinfer version is 0.3.1.
|
|
30
|
+
class HackBSAWrapper(VariableBlockSparseAttentionWrapper):
|
|
31
|
+
def run(
|
|
32
|
+
self,
|
|
33
|
+
q: torch.Tensor,
|
|
34
|
+
k: torch.Tensor,
|
|
35
|
+
v: torch.Tensor,
|
|
36
|
+
out: Optional[torch.Tensor] = None,
|
|
37
|
+
lse: Optional[torch.Tensor] = None,
|
|
38
|
+
return_lse: bool = False,
|
|
39
|
+
enable_pdl: Optional[bool] = None,
|
|
40
|
+
) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]:
|
|
41
|
+
"""
|
|
42
|
+
This is adapted from https://github.com/flashinfer-ai/flashinfer/blob/cc5ab77370dd9a489357a47e34315d9a8f3ad5fb/flashinfer/sparse.py#L1073
|
|
43
|
+
|
|
44
|
+
Compute block-sparse attention between Q/K/V tensors.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
q : torch.Tensor
|
|
49
|
+
The query tensor with shape ``(qo_len, num_qo_heads, head_dim)``.
|
|
50
|
+
k : torch.Tensor
|
|
51
|
+
The key tensor with shape ``(kv_len, num_kv_heads, head_dim)``.
|
|
52
|
+
v : torch.Tensor
|
|
53
|
+
The value tensor with shape ``(kv_len, num_kv_heads, head_dim)``.
|
|
54
|
+
out : Optional[torch.Tensor]
|
|
55
|
+
The output tensor, if not provided, will be allocated internally.
|
|
56
|
+
lse : Optional[torch.Tensor]
|
|
57
|
+
The log-sum-exp of attention logits, if not provided, will be
|
|
58
|
+
allocated internally.
|
|
59
|
+
return_lse : bool
|
|
60
|
+
Whether to return the log-sum-exp of attention logits
|
|
61
|
+
enable_pdl : bool
|
|
62
|
+
Whether to enable Programmatic Dependent Launch (PDL). See https://docs.nvidia.com/cuda/cuda-c-programming-guide/#programmatic-dependent-launch-and-synchronization
|
|
63
|
+
Only supported for >= sm90, and currently only for FA2 and CUDA core decode.
|
|
64
|
+
|
|
65
|
+
Returns
|
|
66
|
+
-------
|
|
67
|
+
Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]
|
|
68
|
+
If :attr:`return_lse` is ``False``, the attention output, shape:
|
|
69
|
+
``[M, num_qo_heads, head_dim]``.
|
|
70
|
+
If :attr:`return_lse` is ``True``, a tuple of two tensors:
|
|
71
|
+
|
|
72
|
+
* The attention output, shape: ``[M, num_qo_heads, head_dim]``.
|
|
73
|
+
* The logsumexp of attention output, shape: ``[M, num_qo_heads]``.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
if enable_pdl is None:
|
|
77
|
+
enable_pdl = device_support_pdl(q.device)
|
|
78
|
+
|
|
79
|
+
pos_encoding_mode = self._pos_encoding_mode
|
|
80
|
+
logits_soft_cap = self._logits_soft_cap
|
|
81
|
+
sm_scale = self._sm_scale
|
|
82
|
+
rope_scale = self._rope_scale
|
|
83
|
+
rope_theta = self._rope_theta
|
|
84
|
+
_check_pos_encoding_mode(pos_encoding_mode)
|
|
85
|
+
if logits_soft_cap is None:
|
|
86
|
+
logits_soft_cap = 0.0
|
|
87
|
+
if sm_scale is None:
|
|
88
|
+
sm_scale = 1.0 / math.sqrt(q.size(-1))
|
|
89
|
+
if rope_scale is None:
|
|
90
|
+
rope_scale = 1.0
|
|
91
|
+
if rope_theta is None:
|
|
92
|
+
rope_theta = 1e4
|
|
93
|
+
|
|
94
|
+
# 1 denotes page size
|
|
95
|
+
k = k.reshape(-1, 1, *k.shape[-2:])
|
|
96
|
+
v = v.reshape(-1, 1, *v.shape[-2:])
|
|
97
|
+
|
|
98
|
+
stride_block = k.stride(0)
|
|
99
|
+
stride_n = k.stride(1)
|
|
100
|
+
|
|
101
|
+
if return_lse:
|
|
102
|
+
if lse is None:
|
|
103
|
+
lse = torch.empty(
|
|
104
|
+
(q.size(0), q.size(1)), dtype=torch.float32, device=q.device
|
|
105
|
+
)
|
|
106
|
+
else:
|
|
107
|
+
check_shape_dtype_device(
|
|
108
|
+
lse, (q.size(0), q.size(1)), torch.float32, q.device, "lse"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
if out is None:
|
|
112
|
+
out = torch.empty_like(q, dtype=self._o_dtype)
|
|
113
|
+
else:
|
|
114
|
+
check_shape_dtype_device(out, q.shape, self._o_dtype, q.device, "out")
|
|
115
|
+
|
|
116
|
+
if self._backend == "fa3":
|
|
117
|
+
if (
|
|
118
|
+
self._vector_sparse_indices_buffer.numel()
|
|
119
|
+
<= self._paged_kv_indices_buf.numel()
|
|
120
|
+
):
|
|
121
|
+
raise ValueError(
|
|
122
|
+
"_vector_sparse_indices_buffer is not large enough. "
|
|
123
|
+
"Please increase the buffer size."
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
sparse_indices = block_sparse_indices_to_vector_sparse_offsets(
|
|
127
|
+
self._paged_kv_indices_buf,
|
|
128
|
+
self._paged_kv_indptr_buf,
|
|
129
|
+
self._vector_sparse_indices_buffer, # output
|
|
130
|
+
self._vector_sparse_indptr_buffer,
|
|
131
|
+
self._kv_lens_buffer,
|
|
132
|
+
stride_block // stride_n,
|
|
133
|
+
1, # stride_n // stride_n
|
|
134
|
+
1, # block_size
|
|
135
|
+
)
|
|
136
|
+
sparse_indptr = self._vector_sparse_indptr_buffer
|
|
137
|
+
else:
|
|
138
|
+
sparse_indices = self._paged_kv_indices_buf
|
|
139
|
+
sparse_indptr = self._paged_kv_indptr_buf
|
|
140
|
+
|
|
141
|
+
self._cached_module.paged_run(
|
|
142
|
+
self._float_workspace_buffer,
|
|
143
|
+
self._int_workspace_buffer,
|
|
144
|
+
self._plan_info,
|
|
145
|
+
q,
|
|
146
|
+
k,
|
|
147
|
+
v,
|
|
148
|
+
self._qo_indptr,
|
|
149
|
+
sparse_indptr,
|
|
150
|
+
sparse_indices,
|
|
151
|
+
self._paged_kv_last_page_len,
|
|
152
|
+
out,
|
|
153
|
+
lse,
|
|
154
|
+
self._mask_mode,
|
|
155
|
+
TensorLayout[self._kv_layout].value,
|
|
156
|
+
-1, # window_left
|
|
157
|
+
enable_pdl,
|
|
158
|
+
# ADDITIONAL_FUNC_PARAMS
|
|
159
|
+
# Not supported yet
|
|
160
|
+
None, # packed_mask_buf
|
|
161
|
+
None, # mask_indptr_buf
|
|
162
|
+
None, # alibi_slopes_buf
|
|
163
|
+
None,
|
|
164
|
+
None,
|
|
165
|
+
None,
|
|
166
|
+
logits_soft_cap,
|
|
167
|
+
sm_scale,
|
|
168
|
+
None, # scale_q
|
|
169
|
+
None, # scale_k
|
|
170
|
+
None, # scale_v
|
|
171
|
+
rope_scale,
|
|
172
|
+
rope_theta,
|
|
173
|
+
0, # token_pos_in_items_len
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
return (out, lse) if return_lse else out
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class LMCFlashInferSparseBackend(AttentionInterface):
|
|
180
|
+
"""
|
|
181
|
+
FlashAttention backend for LMCache.
|
|
182
|
+
This backend uses the FlashAttention implementation
|
|
183
|
+
for efficient attention computation.
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
# Workspace buffer size in bytes (128 MiB)
|
|
187
|
+
_WORKSPACE_BUFFER_SIZE_BYTES = 128 * 1024 * 1024
|
|
188
|
+
|
|
189
|
+
def __init__(
|
|
190
|
+
self,
|
|
191
|
+
vllm_attn: Attention,
|
|
192
|
+
):
|
|
193
|
+
self.vllm_attn = vllm_attn
|
|
194
|
+
self.vllm_attn_impl: FlashInferImpl = vllm_attn.impl
|
|
195
|
+
|
|
196
|
+
idx = torch.cuda.current_device()
|
|
197
|
+
self.device = torch.device(f"cuda:{idx}")
|
|
198
|
+
|
|
199
|
+
self.workspace_buffer = torch.empty(
|
|
200
|
+
self._WORKSPACE_BUFFER_SIZE_BYTES, dtype=torch.uint8, device=self.device
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
self.num_qo_heads = self.vllm_attn_impl.num_heads
|
|
204
|
+
self.num_kv_heads = self.vllm_attn_impl.num_kv_heads
|
|
205
|
+
self.head_dim = self.vllm_attn_impl.head_size
|
|
206
|
+
|
|
207
|
+
self.sm_scale = self.vllm_attn_impl.scale
|
|
208
|
+
self.window_left = self.vllm_attn_impl.window_left
|
|
209
|
+
self.logits_soft_cap = self.vllm_attn_impl.logits_soft_cap
|
|
210
|
+
|
|
211
|
+
self.k_scale = vllm_attn._k_scale_float
|
|
212
|
+
self.v_scale = vllm_attn._v_scale_float
|
|
213
|
+
|
|
214
|
+
def forward_contiguous(
|
|
215
|
+
self,
|
|
216
|
+
query: torch.Tensor,
|
|
217
|
+
key: torch.Tensor,
|
|
218
|
+
value: torch.Tensor,
|
|
219
|
+
output: torch.Tensor,
|
|
220
|
+
attn_metadata: "LMCAttnMetadata",
|
|
221
|
+
**kwargs,
|
|
222
|
+
) -> torch.Tensor:
|
|
223
|
+
assert isinstance(attn_metadata, LMCFlashInferSparseMetadata)
|
|
224
|
+
is_causal = attn_metadata.is_causal
|
|
225
|
+
if is_causal:
|
|
226
|
+
output = flashinfer.prefill.single_prefill_with_kv_cache(
|
|
227
|
+
q=query,
|
|
228
|
+
k=key,
|
|
229
|
+
v=value,
|
|
230
|
+
scale_q=None,
|
|
231
|
+
scale_k=self.k_scale,
|
|
232
|
+
scale_v=self.v_scale,
|
|
233
|
+
o_dtype=query.dtype,
|
|
234
|
+
custom_mask=None,
|
|
235
|
+
packed_custom_mask=None,
|
|
236
|
+
causal=True,
|
|
237
|
+
kv_layout="NHD",
|
|
238
|
+
pos_encoding_mode="NONE",
|
|
239
|
+
use_fp16_qk_reduction=False,
|
|
240
|
+
sm_scale=self.sm_scale,
|
|
241
|
+
window_left=self.window_left,
|
|
242
|
+
logits_soft_cap=self.logits_soft_cap,
|
|
243
|
+
rope_scale=None,
|
|
244
|
+
rope_theta=None,
|
|
245
|
+
backend="auto",
|
|
246
|
+
return_lse=False,
|
|
247
|
+
)
|
|
248
|
+
else:
|
|
249
|
+
output = attn_metadata.wrapper.run(query, key, value, output)
|
|
250
|
+
return output
|
|
251
|
+
|
|
252
|
+
def init_attn_metadata(
|
|
253
|
+
self,
|
|
254
|
+
input_ids: torch.Tensor,
|
|
255
|
+
**kwargs,
|
|
256
|
+
) -> LMCFlashInferSparseMetadata:
|
|
257
|
+
"""
|
|
258
|
+
Initialize non-sparse attention metadata first.
|
|
259
|
+
"""
|
|
260
|
+
|
|
261
|
+
wrapper = HackBSAWrapper(self.workspace_buffer)
|
|
262
|
+
seq_len = len(input_ids)
|
|
263
|
+
|
|
264
|
+
# TODO(Jiayi): remove this hardcode
|
|
265
|
+
sparse_blk_row_size = 32
|
|
266
|
+
sparse_blk_col_size = 32
|
|
267
|
+
|
|
268
|
+
num_block_col = seq_len // sparse_blk_col_size
|
|
269
|
+
last_col_len = seq_len % sparse_blk_col_size
|
|
270
|
+
block_col_sizes = torch.tensor(
|
|
271
|
+
[sparse_blk_col_size] * num_block_col, device=self.device
|
|
272
|
+
)
|
|
273
|
+
block_col_sizes[-1] += last_col_len
|
|
274
|
+
return LMCFlashInferSparseMetadata(
|
|
275
|
+
wrapper,
|
|
276
|
+
seq_len,
|
|
277
|
+
self.num_qo_heads,
|
|
278
|
+
self.num_kv_heads,
|
|
279
|
+
self.head_dim,
|
|
280
|
+
block_col_sizes,
|
|
281
|
+
sparse_blk_row_size,
|
|
282
|
+
sparse_blk_col_size,
|
|
283
|
+
is_causal=True,
|
|
284
|
+
)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
from abc import abstractmethod
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
import abc
|
|
7
|
+
|
|
8
|
+
# Third Party
|
|
9
|
+
import torch
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
# First Party
|
|
13
|
+
from lmcache.v1.compute.attention.flash_infer_sparse import HackBSAWrapper
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class LMCAttnMetadata(metaclass=abc.ABCMeta):
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def update_from_top_indices(self, top_indices: torch.Tensor):
|
|
20
|
+
raise NotImplementedError("This method should be implemented in subclasses.")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class LMCFlashAttnMetadata(LMCAttnMetadata):
|
|
25
|
+
query_start_loc: torch.Tensor
|
|
26
|
+
seq_lens: torch.Tensor
|
|
27
|
+
cu_seqlens_k: torch.Tensor
|
|
28
|
+
max_query_len: torch.Tensor
|
|
29
|
+
max_seq_len: torch.Tensor
|
|
30
|
+
|
|
31
|
+
def update_from_top_indices(self, top_indices: torch.Tensor):
|
|
32
|
+
top_k_num = len(top_indices)
|
|
33
|
+
self.max_query_len = top_k_num
|
|
34
|
+
device = self.query_start_loc.device
|
|
35
|
+
dtype = self.query_start_loc.dtype
|
|
36
|
+
self.query_start_loc = torch.tensor([0, top_k_num], dtype=dtype, device=device)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class LMCFlashInferSparseMetadata(LMCAttnMetadata):
|
|
41
|
+
wrapper: "HackBSAWrapper"
|
|
42
|
+
seq_len: int
|
|
43
|
+
num_qo_heads: int
|
|
44
|
+
num_kv_heads: int
|
|
45
|
+
head_dim: int
|
|
46
|
+
block_col_sizes: torch.Tensor
|
|
47
|
+
sparse_blk_row_size: int = 32 # TODO(Jiayi): make this tunable
|
|
48
|
+
sparse_blk_col_size: int = 32 # TODO(Jiayi): make this tunable
|
|
49
|
+
is_causal: bool = True
|
|
50
|
+
q_data_dtype: torch.dtype = torch.bfloat16 # TODO(Jiayi): remove hardcode
|
|
51
|
+
|
|
52
|
+
def update_from_top_indices(self, top_indices: torch.Tensor):
|
|
53
|
+
# self.is_causal = False
|
|
54
|
+
device = top_indices.device
|
|
55
|
+
top_k_num = len(top_indices)
|
|
56
|
+
num_block_row = top_k_num // self.sparse_blk_row_size
|
|
57
|
+
block_row_sizes = torch.tensor(
|
|
58
|
+
[self.sparse_blk_row_size] * num_block_row, device=device
|
|
59
|
+
)
|
|
60
|
+
block_row_sizes[-1] += top_k_num % self.sparse_blk_row_size
|
|
61
|
+
|
|
62
|
+
block_mask_map = torch.zeros(
|
|
63
|
+
num_block_row, len(self.block_col_sizes), dtype=torch.bool, device=device
|
|
64
|
+
)
|
|
65
|
+
cols = torch.arange(block_mask_map.size(1), device=device).expand(
|
|
66
|
+
block_mask_map.size(0), -1
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# NOTE(Jiayi): select every `sparse_blk_row_size`-th index from top_indices
|
|
70
|
+
# to approximate the attention mask at block level.
|
|
71
|
+
top_indices_slice = top_indices[
|
|
72
|
+
self.sparse_blk_row_size - 1 :: self.sparse_blk_row_size
|
|
73
|
+
]
|
|
74
|
+
top_indices_slice //= self.sparse_blk_col_size
|
|
75
|
+
mask = cols < top_indices_slice.unsqueeze(1)
|
|
76
|
+
block_mask_map[mask] = 1
|
|
77
|
+
self.wrapper.plan(
|
|
78
|
+
block_mask_map.expand(self.num_kv_heads, -1, -1),
|
|
79
|
+
block_row_sizes.expand(self.num_kv_heads, -1),
|
|
80
|
+
self.block_col_sizes.expand(self.num_kv_heads, -1),
|
|
81
|
+
self.num_qo_heads,
|
|
82
|
+
self.num_kv_heads,
|
|
83
|
+
self.head_dim,
|
|
84
|
+
q_data_type=self.q_data_dtype,
|
|
85
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Local
|
|
3
|
+
from .flash_attn import LMCFlashAttnBackend
|
|
4
|
+
from .flash_infer_sparse import LMCFlashInferSparseBackend
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def infer_attn_backend_from_vllm(vllm_attn, enable_sparse=False):
|
|
8
|
+
attn_name = type(vllm_attn.impl).__name__
|
|
9
|
+
if attn_name == "FlashInferImpl" and enable_sparse:
|
|
10
|
+
return LMCFlashInferSparseBackend(vllm_attn)
|
|
11
|
+
elif attn_name == "FlashAttentionImpl" and not enable_sparse:
|
|
12
|
+
return LMCFlashAttnBackend(vllm_attn)
|
|
13
|
+
else:
|
|
14
|
+
raise ValueError(f"Attention backend {attn_name} is not supported in LMCache.")
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
from typing import Optional, Union
|
|
4
|
+
|
|
5
|
+
# Third Party
|
|
6
|
+
import torch
|
|
7
|
+
|
|
8
|
+
# First Party
|
|
9
|
+
from lmcache.logging import init_logger
|
|
10
|
+
from lmcache.v1.compute.attention.metadata import LMCAttnMetadata
|
|
11
|
+
from lmcache.v1.compute.blend.metadata import LMCBlendCommonMetadata, LMCBlendMetadata
|
|
12
|
+
from lmcache.v1.compute.models.utils import infer_model_from_vllm
|
|
13
|
+
from lmcache.v1.config import LMCacheEngineConfig
|
|
14
|
+
|
|
15
|
+
logger = init_logger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class LMCBlender:
|
|
19
|
+
"""
|
|
20
|
+
Cache-blender backend for LMCache.
|
|
21
|
+
This backend uses the Blender implementation for efficient blending computation.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
cache_engine,
|
|
27
|
+
gpu_connector,
|
|
28
|
+
vllm_model,
|
|
29
|
+
config: LMCacheEngineConfig,
|
|
30
|
+
):
|
|
31
|
+
self.cache_engine = cache_engine
|
|
32
|
+
self.gpu_connector = gpu_connector
|
|
33
|
+
|
|
34
|
+
enable_sparse = False
|
|
35
|
+
if config.extra_config is not None:
|
|
36
|
+
enable_sparse = config.extra_config.get("enable_sparse", False)
|
|
37
|
+
|
|
38
|
+
self.layerwise_model = infer_model_from_vllm(vllm_model, self, enable_sparse)
|
|
39
|
+
|
|
40
|
+
# TODO: remove this hardcode
|
|
41
|
+
self.num_layers = len(vllm_model.model.layers)
|
|
42
|
+
|
|
43
|
+
# TODO(Jiayi): support threshold-based blending
|
|
44
|
+
# TODO(Jiayi): support different ratios for different layers
|
|
45
|
+
# TODO(Jiayi): support "skipping blending if hit too short"
|
|
46
|
+
self.common_metadata = LMCBlendCommonMetadata(
|
|
47
|
+
check_layers=config.blend_check_layers,
|
|
48
|
+
recomp_ratios=config.blend_recompute_ratios,
|
|
49
|
+
thresholds=config.blend_thresholds,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# This will be set during the blending process
|
|
53
|
+
self.metadata = LMCBlendMetadata(
|
|
54
|
+
imp_indices=None,
|
|
55
|
+
attn_mask=None,
|
|
56
|
+
positions=None,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def process_qkv(
|
|
60
|
+
self,
|
|
61
|
+
q: torch.Tensor,
|
|
62
|
+
k: torch.Tensor,
|
|
63
|
+
v: torch.Tensor,
|
|
64
|
+
residual: torch.Tensor,
|
|
65
|
+
layer_id: int,
|
|
66
|
+
attn_output: Optional[torch.Tensor],
|
|
67
|
+
attn_metadata: LMCAttnMetadata,
|
|
68
|
+
):
|
|
69
|
+
logger.debug(f"Blender is processing KV for layer {layer_id}")
|
|
70
|
+
old_k, old_v = self.gpu_connector.get_kv(layer_id)
|
|
71
|
+
|
|
72
|
+
if attn_output is None:
|
|
73
|
+
attn_output = torch.empty(
|
|
74
|
+
q.shape,
|
|
75
|
+
dtype=q.dtype,
|
|
76
|
+
device=q.device,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# perform positional encoding
|
|
80
|
+
if self.metadata.positions is None:
|
|
81
|
+
self.metadata.positions = torch.arange(
|
|
82
|
+
q.shape[0], device=q.device, dtype=torch.int64
|
|
83
|
+
)
|
|
84
|
+
layer = self.layerwise_model.vllm_model.model.layers[layer_id]
|
|
85
|
+
attn_layer = layer.self_attn
|
|
86
|
+
q, k = attn_layer.rotary_emb(self.metadata.positions, q, k)
|
|
87
|
+
|
|
88
|
+
if layer_id in self.common_metadata.check_layers:
|
|
89
|
+
diff_k = torch.sum(
|
|
90
|
+
(k.to(torch.float32) - old_k.to(torch.float32)) ** 2, dim=[1]
|
|
91
|
+
)
|
|
92
|
+
total_len = diff_k.shape[0]
|
|
93
|
+
|
|
94
|
+
assert self.common_metadata.recomp_ratios is not None
|
|
95
|
+
|
|
96
|
+
# TODO(Jiayi): remove `[0]` hardcode
|
|
97
|
+
topk_num = int(total_len * self.common_metadata.recomp_ratios[0])
|
|
98
|
+
topk_num = max(topk_num, 1)
|
|
99
|
+
|
|
100
|
+
top_indices = torch.topk(diff_k, k=topk_num).indices
|
|
101
|
+
top_indices, _ = torch.sort(top_indices)
|
|
102
|
+
|
|
103
|
+
k, v = k[top_indices], v[top_indices]
|
|
104
|
+
q = q[top_indices]
|
|
105
|
+
residual = residual[top_indices]
|
|
106
|
+
|
|
107
|
+
logger.debug(f"Number of indices picked: {len(top_indices)}")
|
|
108
|
+
|
|
109
|
+
self.metadata.imp_indices = top_indices
|
|
110
|
+
self.metadata.positions = self.metadata.positions[top_indices]
|
|
111
|
+
attn_output = attn_output[:topk_num]
|
|
112
|
+
|
|
113
|
+
attn_metadata.update_from_top_indices(top_indices)
|
|
114
|
+
|
|
115
|
+
if self.metadata.imp_indices is not None:
|
|
116
|
+
old_k[self.metadata.imp_indices] = k
|
|
117
|
+
old_v[self.metadata.imp_indices] = v
|
|
118
|
+
return q, old_k, old_v, residual, attn_output, attn_metadata
|
|
119
|
+
else:
|
|
120
|
+
return q, k, v, residual, attn_output, attn_metadata
|
|
121
|
+
|
|
122
|
+
# NOTE(Jiayi): Exposing this `blend_layer` interface as we might
|
|
123
|
+
# want to ochestrate the blending process elsewhere
|
|
124
|
+
def blend_layer(
|
|
125
|
+
self,
|
|
126
|
+
tokens: torch.Tensor,
|
|
127
|
+
mask: Optional[torch.Tensor] = None,
|
|
128
|
+
**kwargs,
|
|
129
|
+
):
|
|
130
|
+
"""
|
|
131
|
+
Perform layerwiese retrieve + blending.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
# TODO(Jiayi): store is currently not included in this function
|
|
135
|
+
|
|
136
|
+
layerwise_model_executor = self.layerwise_model.compute_layer(tokens)
|
|
137
|
+
layerwise_retriever = self.cache_engine.retrieve_layer(tokens, mask, **kwargs)
|
|
138
|
+
|
|
139
|
+
next(layerwise_retriever)
|
|
140
|
+
yield
|
|
141
|
+
|
|
142
|
+
for i in range(self.num_layers):
|
|
143
|
+
next(layerwise_retriever)
|
|
144
|
+
next(layerwise_model_executor)
|
|
145
|
+
yield
|
|
146
|
+
|
|
147
|
+
next(layerwise_retriever)
|
|
148
|
+
|
|
149
|
+
self.metadata.clean()
|
|
150
|
+
yield
|
|
151
|
+
|
|
152
|
+
def blend(
|
|
153
|
+
self,
|
|
154
|
+
tokens: Union[torch.Tensor, list[int]],
|
|
155
|
+
mask: Optional[torch.Tensor] = None,
|
|
156
|
+
**kwargs,
|
|
157
|
+
):
|
|
158
|
+
"""
|
|
159
|
+
Perform blending for the given tokens.
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
if isinstance(tokens, list):
|
|
163
|
+
tokens = torch.tensor(tokens).cuda()
|
|
164
|
+
|
|
165
|
+
layerwise_blender = self.blend_layer(tokens, mask, **kwargs)
|
|
166
|
+
|
|
167
|
+
for i in range(self.num_layers + 2):
|
|
168
|
+
next(layerwise_blender)
|