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,255 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
"""Type codecs for trace argument serialization.
|
|
4
|
+
|
|
5
|
+
The trace recorder needs to serialize arbitrary Python values that
|
|
6
|
+
appear as arguments to decorated functions. Msgpack natively handles
|
|
7
|
+
``int``, ``float``, ``str``, ``bytes``, ``bool``, ``None``, ``list``,
|
|
8
|
+
``tuple``, ``dict``. Anything else needs an explicit codec.
|
|
9
|
+
|
|
10
|
+
A codec is a pair ``(encode, decode)`` keyed on a Python type. At
|
|
11
|
+
encode time the value is wrapped in a ``{"__t__": tag, "v": payload}``
|
|
12
|
+
dict so the decoder can recognize it without losing the round-trip.
|
|
13
|
+
|
|
14
|
+
This registry is shared between the recorder (PR1, encode-only path
|
|
15
|
+
exercised) and the replay driver (PR2, decode-only path). Both halves
|
|
16
|
+
ship together to keep the format and behavior coherent.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
# Future
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
# Standard
|
|
23
|
+
from dataclasses import dataclass
|
|
24
|
+
from typing import Any, Callable
|
|
25
|
+
|
|
26
|
+
# Third Party
|
|
27
|
+
import torch
|
|
28
|
+
|
|
29
|
+
# First Party
|
|
30
|
+
from lmcache.v1.distributed.api import MemoryLayoutDesc, ObjectKey, PrefetchHandle
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True)
|
|
34
|
+
class TypeCodec:
|
|
35
|
+
"""Encode/decode pair for a single Python type."""
|
|
36
|
+
|
|
37
|
+
tag: str
|
|
38
|
+
encode: Callable[[Any], Any]
|
|
39
|
+
decode: Callable[[Any], Any]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Tag dispatch table populated by ``register_codec``. Keyed by type.
|
|
43
|
+
_BY_TYPE: dict[type, TypeCodec] = {}
|
|
44
|
+
# Tag dispatch table for decode. Keyed by tag string.
|
|
45
|
+
_BY_TAG: dict[str, TypeCodec] = {}
|
|
46
|
+
|
|
47
|
+
_WRAP_KEY = "__t__"
|
|
48
|
+
_VALUE_KEY = "v"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def register_codec(t: type, codec: TypeCodec) -> None:
|
|
52
|
+
"""Register a codec for type ``t``.
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
ValueError: If ``t`` or ``codec.tag`` is already registered.
|
|
56
|
+
"""
|
|
57
|
+
if t in _BY_TYPE:
|
|
58
|
+
raise ValueError(f"codec already registered for type {t!r}")
|
|
59
|
+
if codec.tag in _BY_TAG:
|
|
60
|
+
raise ValueError(f"codec tag {codec.tag!r} already in use")
|
|
61
|
+
_BY_TYPE[t] = codec
|
|
62
|
+
_BY_TAG[codec.tag] = codec
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# ---------------------------------------------------------------------------
|
|
66
|
+
# Encode / decode entry points
|
|
67
|
+
# ---------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
# Native msgpack types pass through unchanged. Everything else must be
|
|
70
|
+
# wrapped via a registered codec.
|
|
71
|
+
_PASSTHROUGH = (int, float, str, bytes, bool, type(None))
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def encode_value(v: Any) -> Any:
|
|
75
|
+
"""Encode ``v`` to a msgpack-friendly representation.
|
|
76
|
+
|
|
77
|
+
Recursively encodes lists, tuples, and dicts. Tuples are preserved
|
|
78
|
+
via a tag so they can be decoded back to tuples (msgpack would
|
|
79
|
+
otherwise round-trip them as lists).
|
|
80
|
+
|
|
81
|
+
Raises:
|
|
82
|
+
TypeError: If ``v`` is of a type with no registered codec.
|
|
83
|
+
"""
|
|
84
|
+
# Codec lookup by exact type takes priority so that registered
|
|
85
|
+
# types which happen to subclass ``tuple`` (e.g. ``torch.Size``) are
|
|
86
|
+
# handled by their codec rather than the generic tuple branch.
|
|
87
|
+
codec = _BY_TYPE.get(type(v))
|
|
88
|
+
if codec is not None:
|
|
89
|
+
return {_WRAP_KEY: codec.tag, _VALUE_KEY: codec.encode(v)}
|
|
90
|
+
|
|
91
|
+
if isinstance(v, _PASSTHROUGH):
|
|
92
|
+
return v
|
|
93
|
+
if isinstance(v, list):
|
|
94
|
+
return [encode_value(x) for x in v]
|
|
95
|
+
if isinstance(v, tuple):
|
|
96
|
+
return {_WRAP_KEY: "tuple", _VALUE_KEY: [encode_value(x) for x in v]}
|
|
97
|
+
if isinstance(v, dict):
|
|
98
|
+
# Dict keys must already be strings/ints for msgpack. We do not
|
|
99
|
+
# encode keys, only values, to keep the on-wire form readable.
|
|
100
|
+
return {k: encode_value(x) for k, x in v.items()}
|
|
101
|
+
|
|
102
|
+
raise TypeError(
|
|
103
|
+
f"trace.codecs: no codec registered for type {type(v).__name__!r} "
|
|
104
|
+
f"(value={v!r}). Register one via register_codec() or extend "
|
|
105
|
+
f"the default registry."
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def decode_value(v: Any) -> Any:
|
|
110
|
+
"""Decode a msgpack-deserialized value back to its native form.
|
|
111
|
+
|
|
112
|
+
Raises:
|
|
113
|
+
ValueError: If a wrapped value carries an unknown tag.
|
|
114
|
+
"""
|
|
115
|
+
if isinstance(v, list):
|
|
116
|
+
return [decode_value(x) for x in v]
|
|
117
|
+
if isinstance(v, dict):
|
|
118
|
+
tag = v.get(_WRAP_KEY)
|
|
119
|
+
if tag is None:
|
|
120
|
+
return {k: decode_value(x) for k, x in v.items()}
|
|
121
|
+
if tag == "tuple":
|
|
122
|
+
return tuple(decode_value(x) for x in v[_VALUE_KEY])
|
|
123
|
+
codec = _BY_TAG.get(tag)
|
|
124
|
+
if codec is None:
|
|
125
|
+
raise ValueError(f"trace.codecs: unknown tag {tag!r}")
|
|
126
|
+
return codec.decode(v[_VALUE_KEY])
|
|
127
|
+
return v
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def encode_args(args: dict[str, Any]) -> dict[str, Any]:
|
|
131
|
+
"""Encode an argument dict for serialization."""
|
|
132
|
+
return {k: encode_value(v) for k, v in args.items()}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def decode_args(args: dict[str, Any]) -> dict[str, Any]:
|
|
136
|
+
"""Decode an argument dict back to native values."""
|
|
137
|
+
return {k: decode_value(v) for k, v in args.items()}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# ---------------------------------------------------------------------------
|
|
141
|
+
# Default codecs for LMCache types
|
|
142
|
+
# ---------------------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _enc_object_key(k: ObjectKey) -> dict[str, Any]:
|
|
146
|
+
return {
|
|
147
|
+
"chunk_hash": k.chunk_hash,
|
|
148
|
+
"model_name": k.model_name,
|
|
149
|
+
"kv_rank": k.kv_rank,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _dec_object_key(d: dict[str, Any]) -> ObjectKey:
|
|
154
|
+
return ObjectKey(
|
|
155
|
+
chunk_hash=d["chunk_hash"],
|
|
156
|
+
model_name=d["model_name"],
|
|
157
|
+
kv_rank=d["kv_rank"],
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _enc_layout_desc(d: MemoryLayoutDesc) -> dict[str, Any]:
|
|
162
|
+
return {
|
|
163
|
+
"shapes": [list(s) for s in d.shapes],
|
|
164
|
+
"dtypes": [str(dt) for dt in d.dtypes],
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# Mapping from str(torch.dtype) back to the dtype object. Built lazily
|
|
169
|
+
# the first time a layout desc is decoded.
|
|
170
|
+
_DTYPE_BY_NAME: dict[str, torch.dtype] = {}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _resolve_dtype(name: str) -> torch.dtype:
|
|
174
|
+
if not _DTYPE_BY_NAME:
|
|
175
|
+
for attr in dir(torch):
|
|
176
|
+
obj = getattr(torch, attr)
|
|
177
|
+
if isinstance(obj, torch.dtype):
|
|
178
|
+
_DTYPE_BY_NAME[str(obj)] = obj
|
|
179
|
+
dtype = _DTYPE_BY_NAME.get(name)
|
|
180
|
+
if dtype is None:
|
|
181
|
+
raise ValueError(f"trace.codecs: unknown torch dtype {name!r}")
|
|
182
|
+
return dtype
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _dec_layout_desc(d: dict[str, Any]) -> MemoryLayoutDesc:
|
|
186
|
+
return MemoryLayoutDesc(
|
|
187
|
+
shapes=[torch.Size(s) for s in d["shapes"]],
|
|
188
|
+
dtypes=[_resolve_dtype(dt) for dt in d["dtypes"]],
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _enc_prefetch_handle(h: PrefetchHandle) -> dict[str, Any]:
|
|
193
|
+
return {
|
|
194
|
+
"prefetch_request_id": h.prefetch_request_id,
|
|
195
|
+
"external_request_id": h.external_request_id,
|
|
196
|
+
"l1_prefix_hit_count": h.l1_prefix_hit_count,
|
|
197
|
+
"total_requested_keys": h.total_requested_keys,
|
|
198
|
+
"submit_time": h.submit_time,
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _dec_prefetch_handle(d: dict[str, Any]) -> PrefetchHandle:
|
|
203
|
+
return PrefetchHandle(
|
|
204
|
+
prefetch_request_id=d["prefetch_request_id"],
|
|
205
|
+
external_request_id=d["external_request_id"],
|
|
206
|
+
l1_prefix_hit_count=d["l1_prefix_hit_count"],
|
|
207
|
+
total_requested_keys=d["total_requested_keys"],
|
|
208
|
+
submit_time=d["submit_time"],
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _enc_torch_size(s: torch.Size) -> list[int]:
|
|
213
|
+
return list(s)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _dec_torch_size(s: list[int]) -> torch.Size:
|
|
217
|
+
return torch.Size(s)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _enc_torch_dtype(dt: torch.dtype) -> str:
|
|
221
|
+
return str(dt)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _dec_torch_dtype(name: str) -> torch.dtype:
|
|
225
|
+
return _resolve_dtype(name)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
register_codec(
|
|
229
|
+
ObjectKey,
|
|
230
|
+
TypeCodec(tag="ObjectKey", encode=_enc_object_key, decode=_dec_object_key),
|
|
231
|
+
)
|
|
232
|
+
register_codec(
|
|
233
|
+
MemoryLayoutDesc,
|
|
234
|
+
TypeCodec(
|
|
235
|
+
tag="MemoryLayoutDesc",
|
|
236
|
+
encode=_enc_layout_desc,
|
|
237
|
+
decode=_dec_layout_desc,
|
|
238
|
+
),
|
|
239
|
+
)
|
|
240
|
+
register_codec(
|
|
241
|
+
PrefetchHandle,
|
|
242
|
+
TypeCodec(
|
|
243
|
+
tag="PrefetchHandle",
|
|
244
|
+
encode=_enc_prefetch_handle,
|
|
245
|
+
decode=_dec_prefetch_handle,
|
|
246
|
+
),
|
|
247
|
+
)
|
|
248
|
+
register_codec(
|
|
249
|
+
torch.Size,
|
|
250
|
+
TypeCodec(tag="torch.Size", encode=_enc_torch_size, decode=_dec_torch_size),
|
|
251
|
+
)
|
|
252
|
+
register_codec(
|
|
253
|
+
torch.dtype,
|
|
254
|
+
TypeCodec(tag="torch.dtype", encode=_enc_torch_dtype, decode=_dec_torch_dtype),
|
|
255
|
+
)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
"""``@enable_tracing`` decorator for capturing function calls.
|
|
4
|
+
|
|
5
|
+
The decorator publishes a single :data:`EventType.TRACE_CALL` event on
|
|
6
|
+
**function entry** (inputs only). Output values and exceptions are not
|
|
7
|
+
captured — replay re-runs the function and observes the live outcome.
|
|
8
|
+
|
|
9
|
+
The decorator imposes near-zero overhead when tracing is disabled: a
|
|
10
|
+
single boolean attribute load is added to each call. Argument
|
|
11
|
+
introspection is performed only when the gate is on.
|
|
12
|
+
|
|
13
|
+
Codecs that turn LMCache-specific argument types into msgpack-friendly
|
|
14
|
+
forms live in :mod:`lmcache.v1.mp_observability.trace.codecs`. The
|
|
15
|
+
decorator deliberately does not import them; raw Python values are
|
|
16
|
+
attached to the event and the recorder encodes at write time. This
|
|
17
|
+
keeps the decorator import-cheap and breaks an otherwise circular
|
|
18
|
+
dependency (``StorageManager → decorator → codecs → StorageManager``).
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
# Future
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
# Standard
|
|
25
|
+
from functools import wraps
|
|
26
|
+
from typing import Any, Callable, Sequence, TypeVar
|
|
27
|
+
import inspect
|
|
28
|
+
import time
|
|
29
|
+
|
|
30
|
+
# First Party
|
|
31
|
+
from lmcache.v1.mp_observability.event import Event, EventType
|
|
32
|
+
from lmcache.v1.mp_observability.event_bus import get_event_bus
|
|
33
|
+
|
|
34
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
35
|
+
|
|
36
|
+
# Module-level gate. Flipped on by the trace recorder when it
|
|
37
|
+
# registers, off when it shuts down. A simple bool is sufficient
|
|
38
|
+
# (tracing capture is single-process; mutual visibility across threads
|
|
39
|
+
# is not required for correctness — at worst a few events are missed
|
|
40
|
+
# during the toggle window).
|
|
41
|
+
_tracing_enabled: bool = False
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def is_tracing_enabled() -> bool:
|
|
45
|
+
"""Return whether the trace gate is currently on."""
|
|
46
|
+
return _tracing_enabled
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def set_tracing_enabled(enabled: bool) -> None:
|
|
50
|
+
"""Flip the trace gate.
|
|
51
|
+
|
|
52
|
+
Called by trace recorders during ``__init__`` (on) and ``close()``
|
|
53
|
+
(off). Direct callers should not normally use this.
|
|
54
|
+
"""
|
|
55
|
+
global _tracing_enabled
|
|
56
|
+
_tracing_enabled = enabled
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def publish_call_event(qualname: str, args: dict[str, Any]) -> None:
|
|
60
|
+
"""Publish one ``TRACE_CALL`` event.
|
|
61
|
+
|
|
62
|
+
Used by :func:`enable_tracing` and by manual instrumentation
|
|
63
|
+
points (e.g. context-manager enter/exit) that cannot be wrapped
|
|
64
|
+
by the decorator.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
qualname: Fully-qualified name of the call site.
|
|
68
|
+
args: Mapping of argument name to raw Python value. Codec
|
|
69
|
+
encoding happens later, in the recorder.
|
|
70
|
+
|
|
71
|
+
``time.monotonic()`` is sampled **here** (not on the drain thread)
|
|
72
|
+
so the recorded ``t_mono`` aligns with ``Event.timestamp`` —
|
|
73
|
+
otherwise the two clocks would drift by however long the drain
|
|
74
|
+
lagged behind the publisher.
|
|
75
|
+
"""
|
|
76
|
+
if not _tracing_enabled:
|
|
77
|
+
return
|
|
78
|
+
t_mono = time.monotonic()
|
|
79
|
+
bus = get_event_bus()
|
|
80
|
+
bus.publish(
|
|
81
|
+
Event(
|
|
82
|
+
event_type=EventType.TRACE_CALL,
|
|
83
|
+
metadata={"qualname": qualname, "args": args, "t_mono": t_mono},
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def enable_tracing(
|
|
89
|
+
qualname: str | None = None,
|
|
90
|
+
capture: Sequence[str] | None = None,
|
|
91
|
+
redact: Sequence[str] = (),
|
|
92
|
+
) -> Callable[[F], F]:
|
|
93
|
+
"""Decorate a function so its calls publish ``TRACE_CALL`` events.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
qualname: Fully-qualified call-site name placed in the event
|
|
97
|
+
metadata. Defaults to ``f"{func.__module__}.{func.__qualname__}"``.
|
|
98
|
+
capture: If given, only these argument names are recorded.
|
|
99
|
+
``None`` means capture every parameter except ``self`` and
|
|
100
|
+
``cls``.
|
|
101
|
+
redact: Argument names that must not be recorded. Applied
|
|
102
|
+
after ``capture``.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
A decorator that wraps the target function.
|
|
106
|
+
|
|
107
|
+
The signature is bound once at decoration time via
|
|
108
|
+
:func:`inspect.signature`, so per-call overhead is limited to a
|
|
109
|
+
bool check (when disabled) or a ``Signature.bind_partial`` plus
|
|
110
|
+
dict-comprehension (when enabled).
|
|
111
|
+
"""
|
|
112
|
+
redact_set = frozenset(redact)
|
|
113
|
+
capture_set = frozenset(capture) if capture is not None else None
|
|
114
|
+
|
|
115
|
+
def deco(func: F) -> F:
|
|
116
|
+
sig = inspect.signature(func)
|
|
117
|
+
resolved_qualname = qualname or f"{func.__module__}.{func.__qualname__}"
|
|
118
|
+
|
|
119
|
+
# Pre-compute parameter names to record. ``self`` and ``cls``
|
|
120
|
+
# are always dropped — recording the receiver object yields no
|
|
121
|
+
# useful information for replay and would force a codec for
|
|
122
|
+
# every receiver type.
|
|
123
|
+
param_names = [
|
|
124
|
+
name
|
|
125
|
+
for name in sig.parameters
|
|
126
|
+
if name not in ("self", "cls")
|
|
127
|
+
and (capture_set is None or name in capture_set)
|
|
128
|
+
and name not in redact_set
|
|
129
|
+
]
|
|
130
|
+
param_set = frozenset(param_names)
|
|
131
|
+
|
|
132
|
+
@wraps(func)
|
|
133
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
134
|
+
if _tracing_enabled:
|
|
135
|
+
bound = sig.bind_partial(*args, **kwargs)
|
|
136
|
+
bound.apply_defaults()
|
|
137
|
+
payload = {k: v for k, v in bound.arguments.items() if k in param_set}
|
|
138
|
+
publish_call_event(resolved_qualname, payload)
|
|
139
|
+
return func(*args, **kwargs)
|
|
140
|
+
|
|
141
|
+
# Expose the resolved metadata for tests and dispatcher
|
|
142
|
+
# registration.
|
|
143
|
+
wrapper.__lmc_trace_qualname__ = resolved_qualname # type: ignore[attr-defined]
|
|
144
|
+
wrapper.__lmc_trace_params__ = tuple(param_names) # type: ignore[attr-defined]
|
|
145
|
+
return wrapper # type: ignore[return-value]
|
|
146
|
+
|
|
147
|
+
return deco
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
"""On-disk format for trace files.
|
|
4
|
+
|
|
5
|
+
A trace file is a length-prefixed msgpack stream:
|
|
6
|
+
|
|
7
|
+
[4-byte big-endian frame length][msgpack frame]
|
|
8
|
+
[4-byte big-endian frame length][msgpack frame]
|
|
9
|
+
...
|
|
10
|
+
|
|
11
|
+
The first frame is always a :class:`Header`. All subsequent frames
|
|
12
|
+
are :class:`Record` objects. Length-prefixing keeps the reader
|
|
13
|
+
simple and supports concurrent appenders (each frame is atomic on
|
|
14
|
+
local filesystems for sizes below ``PIPE_BUF``).
|
|
15
|
+
|
|
16
|
+
Format version is policed by the reader. Unknown versions are
|
|
17
|
+
rejected to make corrupt or future-format files fail loudly rather
|
|
18
|
+
than silently producing garbage.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
# Future
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
# Standard
|
|
25
|
+
from typing import Any
|
|
26
|
+
|
|
27
|
+
# Third Party
|
|
28
|
+
import msgspec
|
|
29
|
+
|
|
30
|
+
#: Magic bytes at the start of every file for sanity checking. The
|
|
31
|
+
#: reader rejects files that do not begin with these bytes.
|
|
32
|
+
MAGIC: bytes = b"LMCT"
|
|
33
|
+
|
|
34
|
+
#: Bumped whenever the on-wire framing layout changes in a backwards-
|
|
35
|
+
#: incompatible way (length prefix, header/record struct shape, etc.).
|
|
36
|
+
FORMAT_VERSION: int = 1
|
|
37
|
+
|
|
38
|
+
#: Bumped whenever the captured API surface changes in a way that makes
|
|
39
|
+
#: older traces undecodable or incorrect to replay — e.g. a traced
|
|
40
|
+
#: StorageManager method gains/loses an argument, an argument type's
|
|
41
|
+
#: codec wire form changes, or a new codec tag is introduced. Owned by
|
|
42
|
+
#: the trace subsystem, independent of the LMCache package version,
|
|
43
|
+
#: because ``lmcache.__version__`` bumps cover many changes irrelevant
|
|
44
|
+
#: to the trace contract.
|
|
45
|
+
TRACE_SCHEMA_VERSION: int = 1
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class Header(msgspec.Struct, tag="header", omit_defaults=True):
|
|
49
|
+
"""One-per-file metadata block."""
|
|
50
|
+
|
|
51
|
+
magic: bytes
|
|
52
|
+
"""Always :data:`MAGIC`."""
|
|
53
|
+
|
|
54
|
+
format_version: int
|
|
55
|
+
"""File format version; readers reject unknown values."""
|
|
56
|
+
|
|
57
|
+
level: str
|
|
58
|
+
"""Trace level — currently ``"storage"``. Future levels (``"mq"``,
|
|
59
|
+
``"gpu"``) will share this format."""
|
|
60
|
+
|
|
61
|
+
trace_schema_version: int
|
|
62
|
+
""":data:`TRACE_SCHEMA_VERSION` at record time. Replay drivers may
|
|
63
|
+
refuse mismatched schemas rather than silently misinterpreting old
|
|
64
|
+
traces."""
|
|
65
|
+
|
|
66
|
+
t_mono_start: float
|
|
67
|
+
"""``time.monotonic()`` at recorder construction. Record
|
|
68
|
+
timestamps are relative to this."""
|
|
69
|
+
|
|
70
|
+
t_wall_start: float
|
|
71
|
+
"""``time.time()`` at recorder construction. Used to correlate
|
|
72
|
+
with external logs / metrics in absolute wall-clock time."""
|
|
73
|
+
|
|
74
|
+
sm_config_json: str
|
|
75
|
+
"""JSON dump of ``StorageManagerConfig`` at record time, or an
|
|
76
|
+
empty string when not available."""
|
|
77
|
+
|
|
78
|
+
sm_config_digest: str
|
|
79
|
+
"""SHA-256 hex digest of :attr:`sm_config_json`. Replay drivers
|
|
80
|
+
use this to detect mismatched configurations."""
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class Record(msgspec.Struct, tag="record", omit_defaults=True):
|
|
84
|
+
"""One captured function call.
|
|
85
|
+
|
|
86
|
+
All records share the same shape; the ``qualname`` field
|
|
87
|
+
differentiates operations. Future trace levels can introduce new
|
|
88
|
+
``qualname`` values without bumping the format version.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
t_mono: float
|
|
92
|
+
"""Monotonic seconds since :attr:`Header.t_mono_start`."""
|
|
93
|
+
|
|
94
|
+
t_wall: float
|
|
95
|
+
"""Wall-clock ``time.time()`` at the moment the event was
|
|
96
|
+
published."""
|
|
97
|
+
|
|
98
|
+
qualname: str
|
|
99
|
+
"""Fully-qualified call-site name (e.g.
|
|
100
|
+
``lmcache.v1.distributed.storage_manager.StorageManager.reserve_write``)."""
|
|
101
|
+
|
|
102
|
+
args: dict[str, Any]
|
|
103
|
+
"""Codec-encoded argument dict. See
|
|
104
|
+
:mod:`lmcache.v1.mp_observability.trace.codecs` for the codec
|
|
105
|
+
contract."""
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# msgspec encoders/decoders. Reused per-process; both are thread-safe
|
|
109
|
+
# after construction.
|
|
110
|
+
_ENCODER = msgspec.msgpack.Encoder()
|
|
111
|
+
_DECODER_HEADER = msgspec.msgpack.Decoder(Header)
|
|
112
|
+
_DECODER_RECORD = msgspec.msgpack.Decoder(Record)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def encode_header(h: Header) -> bytes:
|
|
116
|
+
"""Serialize a header to msgpack bytes."""
|
|
117
|
+
return _ENCODER.encode(h)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def encode_record(r: Record) -> bytes:
|
|
121
|
+
"""Serialize a record to msgpack bytes."""
|
|
122
|
+
return _ENCODER.encode(r)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def decode_header(buf: bytes) -> Header:
|
|
126
|
+
"""Parse a header from msgpack bytes."""
|
|
127
|
+
return _DECODER_HEADER.decode(buf)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def decode_record(buf: bytes) -> Record:
|
|
131
|
+
"""Parse a record from msgpack bytes."""
|
|
132
|
+
return _DECODER_RECORD.decode(buf)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
"""Trace recorder lifecycle helpers.
|
|
4
|
+
|
|
5
|
+
Used by the cache server entry points (``server.py`` and
|
|
6
|
+
``http_server.py``) to construct, register, and tear down trace
|
|
7
|
+
recorders alongside the EventBus.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# Future
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
# Standard
|
|
14
|
+
from datetime import datetime, timezone
|
|
15
|
+
import os
|
|
16
|
+
import tempfile
|
|
17
|
+
|
|
18
|
+
# First Party
|
|
19
|
+
from lmcache.logging import init_logger
|
|
20
|
+
from lmcache.v1.distributed.config import StorageManagerConfig
|
|
21
|
+
from lmcache.v1.mp_observability.config import ObservabilityConfig
|
|
22
|
+
from lmcache.v1.mp_observability.event_bus import EventBus
|
|
23
|
+
from lmcache.v1.mp_observability.trace.recorder import (
|
|
24
|
+
StorageTraceRecorder,
|
|
25
|
+
TraceRecorder,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
logger = init_logger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _default_trace_path() -> str:
|
|
32
|
+
"""Mint a timestamped path for an unnamed trace file."""
|
|
33
|
+
stamp = datetime.now(timezone.utc).strftime("%Y%m%d-%H%M%S")
|
|
34
|
+
return os.path.join(
|
|
35
|
+
tempfile.gettempdir(),
|
|
36
|
+
f"lmcache-trace-{os.getpid()}-{stamp}.lct",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def maybe_initialize_trace_recorder(
|
|
41
|
+
bus: EventBus,
|
|
42
|
+
obs_config: ObservabilityConfig,
|
|
43
|
+
storage_manager_config: StorageManagerConfig,
|
|
44
|
+
) -> TraceRecorder | None:
|
|
45
|
+
"""Construct and register a trace recorder if configured.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
bus: The active EventBus to subscribe the recorder to.
|
|
49
|
+
obs_config: Observability config carrying the trace flags.
|
|
50
|
+
storage_manager_config: The StorageManagerConfig in use. Used
|
|
51
|
+
to populate the trace file's header digest so a replay
|
|
52
|
+
driver can detect mismatched configurations.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
The created recorder, or ``None`` when ``obs_config.trace_level``
|
|
56
|
+
is unset.
|
|
57
|
+
|
|
58
|
+
The recorder is registered on the bus, so :meth:`EventBus.stop`
|
|
59
|
+
will invoke its ``shutdown`` (which flushes and closes the file).
|
|
60
|
+
Callers do not need to track the returned reference for cleanup;
|
|
61
|
+
it is returned only for testing and observation.
|
|
62
|
+
"""
|
|
63
|
+
level = obs_config.trace_level
|
|
64
|
+
if not level:
|
|
65
|
+
return None
|
|
66
|
+
if level != "storage":
|
|
67
|
+
raise ValueError(
|
|
68
|
+
f"unsupported trace level {level!r}; only 'storage' is supported"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
output_path = obs_config.trace_output or _default_trace_path()
|
|
72
|
+
if obs_config.trace_output is None:
|
|
73
|
+
logger.info(
|
|
74
|
+
"trace recording enabled (level=%s); no --trace-output given, "
|
|
75
|
+
"writing to %s",
|
|
76
|
+
level,
|
|
77
|
+
output_path,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
recorder = StorageTraceRecorder(output_path=output_path)
|
|
81
|
+
recorder.attach_storage_config(storage_manager_config)
|
|
82
|
+
bus.register_subscriber(recorder)
|
|
83
|
+
return recorder
|