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,100 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
"""Unified event model for the MP observability system."""
|
|
4
|
+
|
|
5
|
+
# Future
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
# Standard
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from enum import Enum
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class EventType(Enum):
|
|
15
|
+
"""All observable event types in the MP system.
|
|
16
|
+
|
|
17
|
+
Naming convention: ``<COMPONENT>_<OPERATION>`` or
|
|
18
|
+
``<COMPONENT>_<OPERATION>_<PHASE>`` for start/end pairs.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
# L1 Manager events
|
|
22
|
+
L1_READ_RESERVED = "l1.read.reserved"
|
|
23
|
+
L1_READ_FINISHED = "l1.read.finished"
|
|
24
|
+
L1_WRITE_RESERVED = "l1.write.reserved"
|
|
25
|
+
L1_WRITE_FINISHED = "l1.write.finished"
|
|
26
|
+
L1_WRITE_FINISHED_AND_READ_RESERVED = "l1.write_finished_and_read_reserved"
|
|
27
|
+
L1_KEYS_EVICTED = "l1.keys.evicted"
|
|
28
|
+
|
|
29
|
+
# StorageManager events
|
|
30
|
+
SM_READ_PREFETCHED = "sm.read.prefetched"
|
|
31
|
+
SM_READ_PREFETCHED_FINISHED = "sm.read.prefetched_finished"
|
|
32
|
+
SM_WRITE_RESERVED = "sm.write.reserved"
|
|
33
|
+
SM_WRITE_FINISHED = "sm.write.finished"
|
|
34
|
+
|
|
35
|
+
# L2 Store Controller events
|
|
36
|
+
L2_STORE_SUBMITTED = "l2.store.submitted"
|
|
37
|
+
L2_STORE_COMPLETED = "l2.store.completed"
|
|
38
|
+
|
|
39
|
+
# L2 Prefetch Controller events
|
|
40
|
+
L2_PREFETCH_LOOKUP_SUBMITTED = "l2.prefetch.lookup.submitted"
|
|
41
|
+
L2_PREFETCH_LOOKUP_COMPLETED = "l2.prefetch.lookup.completed"
|
|
42
|
+
L2_PREFETCH_LOAD_SUBMITTED = "l2.prefetch.load.submitted"
|
|
43
|
+
L2_PREFETCH_LOAD_COMPLETED = "l2.prefetch.load.completed"
|
|
44
|
+
|
|
45
|
+
# MP Server request-level events (start/end pairs)
|
|
46
|
+
MP_STORE_START = "mp.store.start"
|
|
47
|
+
MP_STORE_END = "mp.store.end"
|
|
48
|
+
MP_RETRIEVE_START = "mp.retrieve.start"
|
|
49
|
+
MP_RETRIEVE_END = "mp.retrieve.end"
|
|
50
|
+
MP_LOOKUP_PREFETCH_START = "mp.lookup_prefetch.start"
|
|
51
|
+
MP_LOOKUP_PREFETCH_END = "mp.lookup_prefetch.end"
|
|
52
|
+
|
|
53
|
+
# Chunk hash logging events
|
|
54
|
+
MP_LOOKUP = "mp.lookup"
|
|
55
|
+
|
|
56
|
+
# MP Server lifecycle sentinels (CPU-synchronous)
|
|
57
|
+
MP_REQUEST_START = "mp.request.start"
|
|
58
|
+
MP_RETRIEVE_SUBMITTED = "mp.retrieve.submitted"
|
|
59
|
+
MP_STORE_SUBMITTED = "mp.store.submitted"
|
|
60
|
+
MP_SESSION_END = "mp.session.end"
|
|
61
|
+
|
|
62
|
+
# vLLM block allocation events
|
|
63
|
+
MP_VLLM_BLOCK_ALLOCATION = "mp.vllm.block_allocation"
|
|
64
|
+
|
|
65
|
+
# vLLM end session events
|
|
66
|
+
MP_VLLM_END_SESSION = "mp.vllm.end_session"
|
|
67
|
+
|
|
68
|
+
# Trace recording — unified function-call entry event used by the
|
|
69
|
+
# ``@enable_tracing`` decorator. Metadata layout:
|
|
70
|
+
# ``qualname`` (str): fully-qualified function name
|
|
71
|
+
# ``args`` (dict): name -> raw Python value (codec-encoded at
|
|
72
|
+
# record time by the recorder)
|
|
73
|
+
# ``t_mono`` (float): ``time.monotonic()`` captured at publish
|
|
74
|
+
# time, so it is comparable to
|
|
75
|
+
# ``Event.timestamp`` (wall-clock) even
|
|
76
|
+
# though the drain thread processes the
|
|
77
|
+
# event later
|
|
78
|
+
TRACE_CALL = "trace.call"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass
|
|
82
|
+
class Event:
|
|
83
|
+
"""A single observable event in the MP system.
|
|
84
|
+
|
|
85
|
+
Attributes:
|
|
86
|
+
event_type: The type of event.
|
|
87
|
+
timestamp: Wall-clock time (``time.time()``) stamped by
|
|
88
|
+
``EventBus.publish()`` at the moment it is called — not when the
|
|
89
|
+
drain thread processes the event. For CUDA host-callback events
|
|
90
|
+
this captures GPU-accurate timing.
|
|
91
|
+
metadata: Flat key-value payload. Contents depend on ``event_type``;
|
|
92
|
+
see the metadata contracts in
|
|
93
|
+
``docs/design/v1/mp_observability/event-bus.md`` Section 2.7.
|
|
94
|
+
session_id: Caller-provided ID for correlating start/end pairs.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
event_type: EventType
|
|
98
|
+
timestamp: float = 0.0
|
|
99
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
100
|
+
session_id: str = ""
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
"""EventBus: unified pub/sub dispatcher for MP observability events."""
|
|
4
|
+
|
|
5
|
+
# Future
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
# Standard
|
|
9
|
+
from abc import ABC, abstractmethod
|
|
10
|
+
from collections import defaultdict
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import Any, Callable
|
|
13
|
+
import collections
|
|
14
|
+
import threading
|
|
15
|
+
import time
|
|
16
|
+
|
|
17
|
+
# First Party
|
|
18
|
+
from lmcache.logging import init_logger
|
|
19
|
+
from lmcache.v1.mp_observability.event import Event, EventType
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
# Third Party
|
|
23
|
+
import torch # noqa: F401 — must be imported before lmcache.c_ops
|
|
24
|
+
|
|
25
|
+
# First Party
|
|
26
|
+
import lmcache.c_ops as _lmc_ops
|
|
27
|
+
|
|
28
|
+
_has_native_recorder = hasattr(_lmc_ops, "record_event_on_stream")
|
|
29
|
+
except ImportError:
|
|
30
|
+
_has_native_recorder = False
|
|
31
|
+
|
|
32
|
+
logger = init_logger(__name__)
|
|
33
|
+
|
|
34
|
+
# ---------------------------------------------------------------------------
|
|
35
|
+
# Types
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
EventCallback = Callable[[Event], None]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# ---------------------------------------------------------------------------
|
|
42
|
+
# Config
|
|
43
|
+
# ---------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class EventBusConfig:
|
|
48
|
+
"""Configuration for the EventBus.
|
|
49
|
+
|
|
50
|
+
Attributes:
|
|
51
|
+
enabled: Whether the event bus is active. When disabled,
|
|
52
|
+
``publish()`` is a no-op and the drain thread is not started.
|
|
53
|
+
max_queue_size: Maximum number of events in the queue. When the
|
|
54
|
+
queue is full, new events are silently dropped with a
|
|
55
|
+
rate-limited warning.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
enabled: bool = True
|
|
59
|
+
max_queue_size: int = 10_000
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
# Subscriber ABC
|
|
64
|
+
# ---------------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class EventSubscriber(ABC):
|
|
68
|
+
"""Base class for per-component event subscribers.
|
|
69
|
+
|
|
70
|
+
Subclasses declare which ``EventType``\\s they care about via
|
|
71
|
+
``get_subscriptions()``. The ``register()`` helper wires them up to
|
|
72
|
+
an ``EventBus``.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
@abstractmethod
|
|
76
|
+
def get_subscriptions(self) -> dict[EventType, EventCallback]:
|
|
77
|
+
"""Return event_type -> callback mapping.
|
|
78
|
+
|
|
79
|
+
Called once during ``register()``. The EventBus stores these
|
|
80
|
+
callbacks directly.
|
|
81
|
+
"""
|
|
82
|
+
...
|
|
83
|
+
|
|
84
|
+
def register(self, bus: EventBus) -> None:
|
|
85
|
+
"""Subscribe all declared handlers to *bus*."""
|
|
86
|
+
for event_type, callback in self.get_subscriptions().items():
|
|
87
|
+
bus.subscribe(event_type, callback)
|
|
88
|
+
|
|
89
|
+
def shutdown(self) -> None: # noqa: B027
|
|
90
|
+
"""Optional cleanup hook. Called by ``EventBus.stop()``."""
|
|
91
|
+
pass
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# ---------------------------------------------------------------------------
|
|
95
|
+
# EventBus
|
|
96
|
+
# ---------------------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class EventBus:
|
|
100
|
+
"""Manages event ingestion, queueing, and dispatch to subscribers.
|
|
101
|
+
|
|
102
|
+
Events are appended to a deque on the hot path (``publish()``) and
|
|
103
|
+
drained by a background thread that dispatches to registered callbacks.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
def __init__(self, config: EventBusConfig | None = None) -> None:
|
|
107
|
+
if config is None:
|
|
108
|
+
config = EventBusConfig()
|
|
109
|
+
self._config = config
|
|
110
|
+
self._subscribers: dict[EventType, list[EventCallback]] = defaultdict(list)
|
|
111
|
+
self._queue: collections.deque[Event] = collections.deque()
|
|
112
|
+
self._wake = threading.Event()
|
|
113
|
+
self._stop_flag = threading.Event()
|
|
114
|
+
self._lock = threading.Lock()
|
|
115
|
+
self._thread: threading.Thread | None = None
|
|
116
|
+
self._registered_subscribers: list[EventSubscriber] = []
|
|
117
|
+
self._discard_count: int = 0
|
|
118
|
+
self._last_discard_warning: float = 0.0
|
|
119
|
+
|
|
120
|
+
# -- Public API --------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
def subscribe(self, event_type: EventType, callback: EventCallback) -> None:
|
|
123
|
+
"""Register a callback for a specific event type (thread-safe)."""
|
|
124
|
+
with self._lock:
|
|
125
|
+
self._subscribers[event_type].append(callback)
|
|
126
|
+
|
|
127
|
+
def register_subscriber(self, subscriber: EventSubscriber) -> None:
|
|
128
|
+
"""Register an ``EventSubscriber`` and wire up its callbacks."""
|
|
129
|
+
subscriber.register(self)
|
|
130
|
+
with self._lock:
|
|
131
|
+
self._registered_subscribers.append(subscriber)
|
|
132
|
+
|
|
133
|
+
def has_subscribers(self, event_type: EventType) -> bool:
|
|
134
|
+
"""Return True if at least one callback is registered for *event_type*.
|
|
135
|
+
|
|
136
|
+
Use this to skip expensive event construction on the hot path when
|
|
137
|
+
no subscriber is listening::
|
|
138
|
+
|
|
139
|
+
if bus.has_subscribers(EventType.MP_LOOKUP):
|
|
140
|
+
bus.publish(Event(event_type=EventType.MP_LOOKUP, ...))
|
|
141
|
+
"""
|
|
142
|
+
return bool(self._subscribers.get(event_type))
|
|
143
|
+
|
|
144
|
+
def publish_on_stream(self, stream: Any, event: Event) -> None:
|
|
145
|
+
"""Schedule event recording as a CUDA host function on *stream*.
|
|
146
|
+
|
|
147
|
+
Uses a C++ callback via ``cudaLaunchHostFunc`` so the callback
|
|
148
|
+
never touches the GIL, avoiding the CUDA-driver/GIL deadlock.
|
|
149
|
+
|
|
150
|
+
No-op when the EventBus is disabled, avoiding the overhead of
|
|
151
|
+
scheduling a host function on the CUDA stream entirely.
|
|
152
|
+
"""
|
|
153
|
+
if not self._config.enabled:
|
|
154
|
+
return
|
|
155
|
+
if _has_native_recorder:
|
|
156
|
+
str_metadata: dict[str, str] = {}
|
|
157
|
+
int_metadata: dict[str, int] = {}
|
|
158
|
+
for k, v in event.metadata.items():
|
|
159
|
+
if isinstance(v, int):
|
|
160
|
+
int_metadata[k] = v
|
|
161
|
+
else:
|
|
162
|
+
str_metadata[k] = str(v)
|
|
163
|
+
_lmc_ops.record_event_on_stream(
|
|
164
|
+
stream.ptr,
|
|
165
|
+
event.event_type.value,
|
|
166
|
+
event.session_id,
|
|
167
|
+
str_metadata,
|
|
168
|
+
int_metadata,
|
|
169
|
+
)
|
|
170
|
+
else:
|
|
171
|
+
stream.launch_host_func(self.publish, event)
|
|
172
|
+
|
|
173
|
+
def publish(self, event: Event) -> None:
|
|
174
|
+
"""Submit an event (hot path — non-blocking).
|
|
175
|
+
|
|
176
|
+
The event's ``timestamp`` is set to ``time.time()`` at call time.
|
|
177
|
+
When the queue is full the event is silently discarded with a
|
|
178
|
+
rate-limited warning (at most once per second).
|
|
179
|
+
"""
|
|
180
|
+
if not self._config.enabled:
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
if len(self._queue) >= self._config.max_queue_size:
|
|
184
|
+
self._discard_count += 1
|
|
185
|
+
now = time.monotonic()
|
|
186
|
+
if now - self._last_discard_warning >= 1.0:
|
|
187
|
+
logger.warning(
|
|
188
|
+
"EventBus queue full (max_queue_size=%d), "
|
|
189
|
+
"%d event(s) discarded so far",
|
|
190
|
+
self._config.max_queue_size,
|
|
191
|
+
self._discard_count,
|
|
192
|
+
)
|
|
193
|
+
self._last_discard_warning = now
|
|
194
|
+
return
|
|
195
|
+
|
|
196
|
+
event.timestamp = time.time()
|
|
197
|
+
self._queue.append(event)
|
|
198
|
+
self._wake.set()
|
|
199
|
+
|
|
200
|
+
def start(self) -> None:
|
|
201
|
+
"""Start the background drain thread. No-op when disabled or
|
|
202
|
+
already running."""
|
|
203
|
+
if not self._config.enabled:
|
|
204
|
+
return
|
|
205
|
+
if self._thread is not None and self._thread.is_alive():
|
|
206
|
+
return
|
|
207
|
+
|
|
208
|
+
self._stop_flag.clear()
|
|
209
|
+
self._thread = threading.Thread(
|
|
210
|
+
target=self._run,
|
|
211
|
+
daemon=True,
|
|
212
|
+
name="EventBus",
|
|
213
|
+
)
|
|
214
|
+
logger.debug("Starting EventBus drain thread...")
|
|
215
|
+
self._thread.start()
|
|
216
|
+
|
|
217
|
+
def stop(self) -> None:
|
|
218
|
+
"""Stop the drain thread, flush remaining events, and shut down
|
|
219
|
+
all registered subscribers. Safe to call when not started."""
|
|
220
|
+
self._stop_flag.set()
|
|
221
|
+
self._wake.set()
|
|
222
|
+
if self._thread is not None and self._thread.is_alive():
|
|
223
|
+
self._thread.join()
|
|
224
|
+
|
|
225
|
+
# Final drain
|
|
226
|
+
self._drain_all()
|
|
227
|
+
|
|
228
|
+
# Shutdown subscribers
|
|
229
|
+
with self._lock:
|
|
230
|
+
snapshot = list(self._registered_subscribers)
|
|
231
|
+
for sub in snapshot:
|
|
232
|
+
try:
|
|
233
|
+
sub.shutdown()
|
|
234
|
+
except Exception:
|
|
235
|
+
logger.exception(
|
|
236
|
+
"EventBus: error shutting down %s",
|
|
237
|
+
type(sub).__name__,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# -- Internal ----------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
def _run(self) -> None:
|
|
243
|
+
"""Drain loop: wait for wake signal or timeout, then drain."""
|
|
244
|
+
while not self._stop_flag.is_set():
|
|
245
|
+
self._wake.wait(timeout=0.1)
|
|
246
|
+
self._wake.clear()
|
|
247
|
+
self._drain_all()
|
|
248
|
+
|
|
249
|
+
def _drain_all(self) -> None:
|
|
250
|
+
"""Pop all queued events and dispatch to subscribers."""
|
|
251
|
+
# Drain events buffered on the C++ side (from CUDA host callbacks)
|
|
252
|
+
if _has_native_recorder:
|
|
253
|
+
for name, sid, ts, str_meta, int_meta in _lmc_ops.drain_recorded_events():
|
|
254
|
+
metadata: dict[str, Any] = dict(str_meta)
|
|
255
|
+
metadata.update(int_meta)
|
|
256
|
+
self._queue.append(
|
|
257
|
+
Event(
|
|
258
|
+
event_type=EventType(name),
|
|
259
|
+
session_id=sid,
|
|
260
|
+
timestamp=ts,
|
|
261
|
+
metadata=metadata,
|
|
262
|
+
)
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
with self._lock:
|
|
266
|
+
snapshot = dict(self._subscribers)
|
|
267
|
+
|
|
268
|
+
while True:
|
|
269
|
+
try:
|
|
270
|
+
event = self._queue.popleft()
|
|
271
|
+
except IndexError:
|
|
272
|
+
break
|
|
273
|
+
for cb in snapshot.get(event.event_type, []):
|
|
274
|
+
try:
|
|
275
|
+
cb(event)
|
|
276
|
+
except Exception:
|
|
277
|
+
logger.exception(
|
|
278
|
+
"EventBus: error in callback for %s",
|
|
279
|
+
event.event_type.value,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
# ---------------------------------------------------------------------------
|
|
284
|
+
# Singleton
|
|
285
|
+
# ---------------------------------------------------------------------------
|
|
286
|
+
|
|
287
|
+
_global_bus = EventBus(EventBusConfig(enabled=False))
|
|
288
|
+
_observability_enabled: bool = False
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def is_observability_enabled() -> bool:
|
|
292
|
+
"""Fast check for whether observability is active.
|
|
293
|
+
|
|
294
|
+
Use this to guard expensive event-construction or CUDA host-function
|
|
295
|
+
scheduling when observability is disabled.
|
|
296
|
+
"""
|
|
297
|
+
return _observability_enabled
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def get_event_bus() -> EventBus:
|
|
301
|
+
"""Return the current global EventBus singleton."""
|
|
302
|
+
return _global_bus
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def init_event_bus(config: EventBusConfig | None = None) -> EventBus:
|
|
306
|
+
"""Replace the global singleton with a new EventBus built from *config*.
|
|
307
|
+
|
|
308
|
+
Returns the newly created bus.
|
|
309
|
+
"""
|
|
310
|
+
global _global_bus, _observability_enabled
|
|
311
|
+
_global_bus = EventBus(config)
|
|
312
|
+
_observability_enabled = config.enabled if config else True
|
|
313
|
+
return _global_bus
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
"""OpenTelemetry SDK initialization for the MP observability system.
|
|
4
|
+
|
|
5
|
+
Supports two modes, controlled by the ``otlp_endpoint`` field in
|
|
6
|
+
``ObservabilityConfig``:
|
|
7
|
+
|
|
8
|
+
- **OTLP push** (production): metrics/traces are pushed to an OTel collector.
|
|
9
|
+
- **Prometheus pull** (dev/debug): metrics are served on a local ``/metrics``
|
|
10
|
+
endpoint via ``prometheus_client``, no collector needed.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
# Future
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
# Standard
|
|
17
|
+
from collections.abc import Callable
|
|
18
|
+
|
|
19
|
+
# First Party
|
|
20
|
+
from lmcache.logging import init_logger
|
|
21
|
+
|
|
22
|
+
logger = init_logger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def init_otel_metrics(
|
|
26
|
+
otlp_endpoint: str | None = None,
|
|
27
|
+
prometheus_port: int | None = None,
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Set up the OpenTelemetry MeterProvider.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
otlp_endpoint: OTLP gRPC endpoint (e.g. ``http://localhost:4317``).
|
|
33
|
+
When set, metrics are pushed to an OTel collector.
|
|
34
|
+
When ``None``, falls back to Prometheus pull mode.
|
|
35
|
+
prometheus_port: Port for the fallback Prometheus ``/metrics``
|
|
36
|
+
endpoint. Only used when *otlp_endpoint* is ``None``.
|
|
37
|
+
Defaults to 9090.
|
|
38
|
+
"""
|
|
39
|
+
# Third Party
|
|
40
|
+
from opentelemetry import metrics
|
|
41
|
+
from opentelemetry.sdk.metrics import MeterProvider
|
|
42
|
+
|
|
43
|
+
if otlp_endpoint is not None:
|
|
44
|
+
# OTLP push mode
|
|
45
|
+
# Third Party
|
|
46
|
+
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import (
|
|
47
|
+
OTLPMetricExporter,
|
|
48
|
+
)
|
|
49
|
+
from opentelemetry.sdk.metrics.export import (
|
|
50
|
+
PeriodicExportingMetricReader,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
exporter = OTLPMetricExporter(endpoint=otlp_endpoint, insecure=True)
|
|
54
|
+
reader = PeriodicExportingMetricReader(exporter, export_interval_millis=10000)
|
|
55
|
+
provider = MeterProvider(metric_readers=[reader])
|
|
56
|
+
metrics.set_meter_provider(provider)
|
|
57
|
+
logger.info(
|
|
58
|
+
"OTel MeterProvider initialised with OTLP exporter (%s)",
|
|
59
|
+
otlp_endpoint,
|
|
60
|
+
)
|
|
61
|
+
else:
|
|
62
|
+
# Prometheus pull fallback — no collector needed
|
|
63
|
+
# Third Party
|
|
64
|
+
from opentelemetry.exporter.prometheus import PrometheusMetricReader
|
|
65
|
+
import prometheus_client
|
|
66
|
+
|
|
67
|
+
if prometheus_port is None:
|
|
68
|
+
prometheus_port = 9090
|
|
69
|
+
|
|
70
|
+
reader = PrometheusMetricReader()
|
|
71
|
+
provider = MeterProvider(metric_readers=[reader])
|
|
72
|
+
metrics.set_meter_provider(provider)
|
|
73
|
+
prometheus_client.start_http_server(prometheus_port)
|
|
74
|
+
logger.info(
|
|
75
|
+
"OTel MeterProvider initialised with Prometheus fallback "
|
|
76
|
+
"(http://0.0.0.0:%d/metrics)",
|
|
77
|
+
prometheus_port,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def init_otel_tracing(otlp_endpoint: str | None = None) -> None:
|
|
82
|
+
"""Set up the OpenTelemetry TracerProvider with an OTLP exporter.
|
|
83
|
+
|
|
84
|
+
Tracing requires an OTLP endpoint — there is no local fallback.
|
|
85
|
+
When *otlp_endpoint* is ``None``, tracing init is skipped.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
otlp_endpoint: OTLP gRPC endpoint. When ``None``, tracing
|
|
89
|
+
init is skipped (no-op).
|
|
90
|
+
"""
|
|
91
|
+
if otlp_endpoint is None:
|
|
92
|
+
logger.debug("No OTLP endpoint configured, skipping tracing init")
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
# Third Party
|
|
96
|
+
from opentelemetry import trace
|
|
97
|
+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
|
|
98
|
+
OTLPSpanExporter,
|
|
99
|
+
)
|
|
100
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
101
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
102
|
+
|
|
103
|
+
exporter = OTLPSpanExporter(endpoint=otlp_endpoint, insecure=True)
|
|
104
|
+
provider = TracerProvider()
|
|
105
|
+
provider.add_span_processor(BatchSpanProcessor(exporter))
|
|
106
|
+
trace.set_tracer_provider(provider)
|
|
107
|
+
logger.info(
|
|
108
|
+
"OTel TracerProvider initialised with OTLP exporter (%s)",
|
|
109
|
+
otlp_endpoint,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def register_gauge(
|
|
114
|
+
meter_name: str,
|
|
115
|
+
gauge_name: str,
|
|
116
|
+
description: str,
|
|
117
|
+
func: Callable[[], int | float],
|
|
118
|
+
) -> None:
|
|
119
|
+
"""Register an OTel observable gauge with a callback.
|
|
120
|
+
|
|
121
|
+
This is a convenience wrapper that hides the OTel boilerplate.
|
|
122
|
+
If OTel is not available, the call is silently ignored.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
meter_name: OTel meter name (e.g. ``lmcache.mp_engine``).
|
|
126
|
+
gauge_name: Metric name (e.g.
|
|
127
|
+
``lmcache_mp.active_prefetch_jobs``).
|
|
128
|
+
description: Human-readable description of the gauge.
|
|
129
|
+
func: Zero-arg callable returning the current value.
|
|
130
|
+
"""
|
|
131
|
+
try:
|
|
132
|
+
# Third Party
|
|
133
|
+
from opentelemetry import metrics as otel_metrics
|
|
134
|
+
|
|
135
|
+
meter = otel_metrics.get_meter(meter_name)
|
|
136
|
+
meter.create_observable_gauge(
|
|
137
|
+
gauge_name,
|
|
138
|
+
callbacks=[lambda _: [otel_metrics.Observation(func())]],
|
|
139
|
+
description=description,
|
|
140
|
+
)
|
|
141
|
+
except ImportError:
|
|
142
|
+
logger.debug(
|
|
143
|
+
"opentelemetry package not found, skipping gauge %s",
|
|
144
|
+
gauge_name,
|
|
145
|
+
)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
# First Party
|
|
4
|
+
from lmcache.v1.mp_observability.subscribers.logging import (
|
|
5
|
+
L1LoggingSubscriber,
|
|
6
|
+
MPServerLoggingSubscriber,
|
|
7
|
+
SMLoggingSubscriber,
|
|
8
|
+
)
|
|
9
|
+
from lmcache.v1.mp_observability.subscribers.metrics import (
|
|
10
|
+
L0LifecycleSubscriber,
|
|
11
|
+
L1LifecycleSubscriber,
|
|
12
|
+
L1MetricsSubscriber,
|
|
13
|
+
SMMetricsSubscriber,
|
|
14
|
+
)
|
|
15
|
+
from lmcache.v1.mp_observability.subscribers.tracing import (
|
|
16
|
+
MPServerTracingSubscriber,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"L0LifecycleSubscriber",
|
|
21
|
+
"L1LifecycleSubscriber",
|
|
22
|
+
"L1LoggingSubscriber",
|
|
23
|
+
"L1MetricsSubscriber",
|
|
24
|
+
"MPServerLoggingSubscriber",
|
|
25
|
+
"MPServerTracingSubscriber",
|
|
26
|
+
"SMLoggingSubscriber",
|
|
27
|
+
"SMMetricsSubscriber",
|
|
28
|
+
]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# First Party
|
|
3
|
+
from lmcache.v1.mp_observability.subscribers.logging.l1 import L1LoggingSubscriber
|
|
4
|
+
from lmcache.v1.mp_observability.subscribers.logging.l2 import L2LoggingSubscriber
|
|
5
|
+
from lmcache.v1.mp_observability.subscribers.logging.lookup_hash import (
|
|
6
|
+
LookupHashLoggingSubscriber,
|
|
7
|
+
)
|
|
8
|
+
from lmcache.v1.mp_observability.subscribers.logging.mp_server import (
|
|
9
|
+
MPServerLoggingSubscriber,
|
|
10
|
+
)
|
|
11
|
+
from lmcache.v1.mp_observability.subscribers.logging.sm import SMLoggingSubscriber
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"LookupHashLoggingSubscriber",
|
|
15
|
+
"L1LoggingSubscriber",
|
|
16
|
+
"L2LoggingSubscriber",
|
|
17
|
+
"MPServerLoggingSubscriber",
|
|
18
|
+
"SMLoggingSubscriber",
|
|
19
|
+
]
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
"""L1 logging subscriber — debug logs for L1Manager events.
|
|
4
|
+
|
|
5
|
+
Logs are emitted via Python's standard logging module. When OpenTelemetry
|
|
6
|
+
is installed, ``init_logger`` automatically attaches an OTel
|
|
7
|
+
``LoggingHandler`` so records are forwarded to OTel when a
|
|
8
|
+
``LoggerProvider`` is configured at startup.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# Future
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
# First Party
|
|
15
|
+
from lmcache.logging import init_logger
|
|
16
|
+
from lmcache.v1.mp_observability.event import Event, EventType
|
|
17
|
+
from lmcache.v1.mp_observability.event_bus import EventCallback, EventSubscriber
|
|
18
|
+
|
|
19
|
+
logger = init_logger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class L1LoggingSubscriber(EventSubscriber):
|
|
23
|
+
"""Logs L1Manager events at debug level."""
|
|
24
|
+
|
|
25
|
+
def get_subscriptions(self) -> dict[EventType, EventCallback]:
|
|
26
|
+
return {
|
|
27
|
+
EventType.L1_READ_RESERVED: self._on_read_reserved,
|
|
28
|
+
EventType.L1_READ_FINISHED: self._on_read_finished,
|
|
29
|
+
EventType.L1_WRITE_RESERVED: self._on_write_reserved,
|
|
30
|
+
EventType.L1_WRITE_FINISHED: self._on_write_finished,
|
|
31
|
+
EventType.L1_WRITE_FINISHED_AND_READ_RESERVED: (
|
|
32
|
+
self._on_write_finished_and_read_reserved
|
|
33
|
+
),
|
|
34
|
+
EventType.L1_KEYS_EVICTED: self._on_evicted,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
def _on_read_reserved(self, event: Event) -> None:
|
|
38
|
+
logger.debug("L1 read reserved: %d keys", len(event.metadata["keys"]))
|
|
39
|
+
|
|
40
|
+
def _on_read_finished(self, event: Event) -> None:
|
|
41
|
+
logger.debug("L1 read finished: %d keys", len(event.metadata["keys"]))
|
|
42
|
+
|
|
43
|
+
def _on_write_reserved(self, event: Event) -> None:
|
|
44
|
+
logger.debug("L1 write reserved: %d keys", len(event.metadata["keys"]))
|
|
45
|
+
|
|
46
|
+
def _on_write_finished(self, event: Event) -> None:
|
|
47
|
+
logger.debug("L1 write finished: %d keys", len(event.metadata["keys"]))
|
|
48
|
+
|
|
49
|
+
def _on_write_finished_and_read_reserved(self, event: Event) -> None:
|
|
50
|
+
logger.debug(
|
|
51
|
+
"L1 write finished and read reserved: %d keys",
|
|
52
|
+
len(event.metadata["keys"]),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def _on_evicted(self, event: Event) -> None:
|
|
56
|
+
logger.debug("L1 eviction: %d keys", len(event.metadata["keys"]))
|