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,435 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Long-document permutator workload for ``lmcache bench engine``.
|
|
3
|
+
|
|
4
|
+
Stress-tests blended KV cache reuse by sending permutations of a set of
|
|
5
|
+
context documents. Each request is:
|
|
6
|
+
|
|
7
|
+
[System Prompt] + [Doc_i1] + [Doc_i2] + ... + [Doc_iN]
|
|
8
|
+
|
|
9
|
+
where (i1, ..., iN) is one permutation of the N contexts.
|
|
10
|
+
|
|
11
|
+
Stress axes (controlled by config):
|
|
12
|
+
1. Blended Context Boundaries -> num_contexts
|
|
13
|
+
2. Eviction -> num_permutations
|
|
14
|
+
3. Chunk Homogeneity -> vocab_size
|
|
15
|
+
4. Prefix Domination -> system_prompt_length
|
|
16
|
+
5. Concurrency -> num_inflight_requests
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
# Standard
|
|
20
|
+
from dataclasses import dataclass
|
|
21
|
+
import asyncio
|
|
22
|
+
import itertools
|
|
23
|
+
import math
|
|
24
|
+
import random
|
|
25
|
+
|
|
26
|
+
# First Party
|
|
27
|
+
from lmcache.cli.commands.bench.engine_bench.progress import ProgressMonitor
|
|
28
|
+
from lmcache.cli.commands.bench.engine_bench.request_sender import RequestSender
|
|
29
|
+
from lmcache.cli.commands.bench.engine_bench.stats import StatsCollector
|
|
30
|
+
from lmcache.cli.commands.bench.engine_bench.workloads.base import BaseWorkload
|
|
31
|
+
from lmcache.logging import init_logger
|
|
32
|
+
|
|
33
|
+
logger = init_logger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class LongDocPermutatorConfig:
|
|
38
|
+
"""Workload-specific config for the long-doc-permutator workload."""
|
|
39
|
+
|
|
40
|
+
num_contexts: int = 5
|
|
41
|
+
context_length: int = 5000
|
|
42
|
+
system_prompt_length: int = 1000
|
|
43
|
+
num_permutations: int = 10
|
|
44
|
+
vocab_size: int = 8000
|
|
45
|
+
num_inflight_requests: int = 1
|
|
46
|
+
|
|
47
|
+
def __post_init__(self) -> None:
|
|
48
|
+
if self.num_contexts < 1:
|
|
49
|
+
raise ValueError(f"num_contexts must be >= 1, got {self.num_contexts}")
|
|
50
|
+
if self.context_length <= 0:
|
|
51
|
+
raise ValueError(
|
|
52
|
+
f"context_length must be positive, got {self.context_length}"
|
|
53
|
+
)
|
|
54
|
+
if self.num_permutations < 1:
|
|
55
|
+
raise ValueError(
|
|
56
|
+
f"num_permutations must be >= 1, got {self.num_permutations}"
|
|
57
|
+
)
|
|
58
|
+
if self.vocab_size < 1:
|
|
59
|
+
raise ValueError(f"vocab_size must be >= 1, got {self.vocab_size}")
|
|
60
|
+
if self.num_inflight_requests < 1:
|
|
61
|
+
raise ValueError(
|
|
62
|
+
f"num_inflight_requests must be >= 1, got {self.num_inflight_requests}"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def resolve(
|
|
67
|
+
cls,
|
|
68
|
+
num_contexts: int = 5,
|
|
69
|
+
context_length: int = 5000,
|
|
70
|
+
system_prompt_length: int = 1000,
|
|
71
|
+
num_permutations: int = 10,
|
|
72
|
+
vocab_size: int = 8000,
|
|
73
|
+
num_inflight_requests: int = 1,
|
|
74
|
+
) -> "LongDocPermutatorConfig":
|
|
75
|
+
"""Create a config directly from the provided parameters.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
num_contexts: Number of unique context documents.
|
|
79
|
+
context_length: Token length of each context.
|
|
80
|
+
system_prompt_length: Token length of the shared system prompt.
|
|
81
|
+
Use 0 for no system prompt.
|
|
82
|
+
num_permutations: Number of distinct permutations to send.
|
|
83
|
+
Capped at N! where N = num_contexts.
|
|
84
|
+
vocab_size: Vocabulary pool size for context generation.
|
|
85
|
+
Smaller values increase chunk hash collision risk.
|
|
86
|
+
num_inflight_requests: Max concurrent in-flight requests.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
A fully-resolved LongDocPermutatorConfig.
|
|
90
|
+
"""
|
|
91
|
+
return cls(
|
|
92
|
+
num_contexts=num_contexts,
|
|
93
|
+
context_length=context_length,
|
|
94
|
+
system_prompt_length=system_prompt_length,
|
|
95
|
+
num_permutations=num_permutations,
|
|
96
|
+
vocab_size=vocab_size,
|
|
97
|
+
num_inflight_requests=num_inflight_requests,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# ---------------------------------------------------------------------------
|
|
102
|
+
# Prompt generation helpers (module-level, before classes)
|
|
103
|
+
# ---------------------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _generate_vocab_pool(size: int, seed: int = 42) -> list[str]:
|
|
107
|
+
"""Generate a vocabulary pool of ``size`` unique pseudo-words.
|
|
108
|
+
|
|
109
|
+
Deterministically generates synthetic words so every token is unique.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
size: Number of unique words to generate.
|
|
113
|
+
seed: Random seed for reproducibility.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Sorted list of unique pseudo-words.
|
|
117
|
+
"""
|
|
118
|
+
rng = random.Random(seed)
|
|
119
|
+
vowels = "aeiou"
|
|
120
|
+
consonants = "bcdfghjklmnpqrstvwxyz"
|
|
121
|
+
pool: set[str] = set()
|
|
122
|
+
while len(pool) < size:
|
|
123
|
+
length = rng.randint(3, 7)
|
|
124
|
+
word = ""
|
|
125
|
+
for j in range(length):
|
|
126
|
+
if j % 2 == 0:
|
|
127
|
+
word += rng.choice(consonants)
|
|
128
|
+
else:
|
|
129
|
+
word += rng.choice(vowels)
|
|
130
|
+
word = f"{word}{len(pool)}"
|
|
131
|
+
pool.add(word)
|
|
132
|
+
return sorted(pool)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _generate_system_prompt(length: int, seed: int = 42) -> str:
|
|
136
|
+
"""Generate a deterministic shared system prompt of ~``length`` tokens.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
length: Approximate token length of the system prompt.
|
|
140
|
+
seed: Random seed for reproducibility.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
A string of ``length`` space-separated words.
|
|
144
|
+
"""
|
|
145
|
+
if length == 0:
|
|
146
|
+
return ""
|
|
147
|
+
rng = random.Random(seed)
|
|
148
|
+
words = [
|
|
149
|
+
"the",
|
|
150
|
+
"system",
|
|
151
|
+
"will",
|
|
152
|
+
"process",
|
|
153
|
+
"your",
|
|
154
|
+
"request",
|
|
155
|
+
"and",
|
|
156
|
+
"provide",
|
|
157
|
+
"an",
|
|
158
|
+
"answer",
|
|
159
|
+
"based",
|
|
160
|
+
"on",
|
|
161
|
+
"context",
|
|
162
|
+
]
|
|
163
|
+
return " ".join(rng.choices(words, k=length))
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _generate_contexts(
|
|
167
|
+
num_contexts: int,
|
|
168
|
+
length: int,
|
|
169
|
+
vocab_pool: list[str],
|
|
170
|
+
seed: int = 123,
|
|
171
|
+
) -> list[str]:
|
|
172
|
+
"""Generate ``num_contexts`` unique context blocks of ~``length`` tokens.
|
|
173
|
+
|
|
174
|
+
Each context draws from ``vocab_pool`` with a per-context seed so the
|
|
175
|
+
token sequences genuinely diverge.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
num_contexts: Number of context documents to generate.
|
|
179
|
+
length: Approximate token length of each context.
|
|
180
|
+
vocab_pool: Pool of words to sample from.
|
|
181
|
+
seed: Base random seed; each context uses seed + i.
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
List of context strings.
|
|
185
|
+
"""
|
|
186
|
+
contexts = []
|
|
187
|
+
for i in range(num_contexts):
|
|
188
|
+
rng = random.Random(seed + i)
|
|
189
|
+
body = " ".join(rng.choices(vocab_pool, k=length))
|
|
190
|
+
contexts.append(body)
|
|
191
|
+
return contexts
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _enumerate_permutations(
|
|
195
|
+
num_contexts: int,
|
|
196
|
+
num_permutations: int,
|
|
197
|
+
seed: int = 0,
|
|
198
|
+
) -> list[tuple[int, ...]]:
|
|
199
|
+
"""Enumerate up to ``num_permutations`` distinct permutations.
|
|
200
|
+
|
|
201
|
+
Returns all N! permutations when num_permutations >= N!. For large N
|
|
202
|
+
uses random sampling to avoid iterating an enormous search space.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
num_contexts: Number of contexts (N).
|
|
206
|
+
num_permutations: Maximum number of permutations to return.
|
|
207
|
+
seed: Random seed used when sampling is needed.
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
List of permutation tuples.
|
|
211
|
+
"""
|
|
212
|
+
total_possible = math.factorial(num_contexts)
|
|
213
|
+
if num_permutations >= total_possible:
|
|
214
|
+
return list(itertools.permutations(range(num_contexts)))
|
|
215
|
+
|
|
216
|
+
if total_possible > num_permutations * 10:
|
|
217
|
+
rng = random.Random(seed)
|
|
218
|
+
seen: set[tuple[int, ...]] = set()
|
|
219
|
+
indices = list(range(num_contexts))
|
|
220
|
+
while len(seen) < num_permutations:
|
|
221
|
+
perm = tuple(rng.sample(indices, len(indices)))
|
|
222
|
+
seen.add(perm)
|
|
223
|
+
return sorted(seen)
|
|
224
|
+
|
|
225
|
+
result = []
|
|
226
|
+
for perm in itertools.permutations(range(num_contexts)):
|
|
227
|
+
result.append(perm)
|
|
228
|
+
if len(result) >= num_permutations:
|
|
229
|
+
break
|
|
230
|
+
return result
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
# ---------------------------------------------------------------------------
|
|
234
|
+
# Workload class
|
|
235
|
+
# ---------------------------------------------------------------------------
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
class LongDocPermutatorWorkload(BaseWorkload):
|
|
239
|
+
"""Workload that sends permutations of context documents.
|
|
240
|
+
|
|
241
|
+
Generates synthetic contexts from a vocab pool, enumerates permutations,
|
|
242
|
+
and dispatches requests with semaphore-controlled concurrency. Includes
|
|
243
|
+
a single dummy warmup request to prime the engine.
|
|
244
|
+
"""
|
|
245
|
+
|
|
246
|
+
def __init__(
|
|
247
|
+
self,
|
|
248
|
+
config: LongDocPermutatorConfig,
|
|
249
|
+
request_sender: RequestSender,
|
|
250
|
+
stats_collector: StatsCollector,
|
|
251
|
+
progress_monitor: ProgressMonitor,
|
|
252
|
+
seed: int = 42,
|
|
253
|
+
) -> None:
|
|
254
|
+
super().__init__(request_sender, stats_collector, progress_monitor)
|
|
255
|
+
self._config = config
|
|
256
|
+
self._seed = seed
|
|
257
|
+
|
|
258
|
+
vocab_pool = _generate_vocab_pool(config.vocab_size, seed=seed)
|
|
259
|
+
self._system_prompt = _generate_system_prompt(
|
|
260
|
+
config.system_prompt_length, seed=seed
|
|
261
|
+
)
|
|
262
|
+
self._contexts = _generate_contexts(
|
|
263
|
+
config.num_contexts, config.context_length, vocab_pool, seed=seed + 1
|
|
264
|
+
)
|
|
265
|
+
self._permutations = _enumerate_permutations(
|
|
266
|
+
config.num_contexts, config.num_permutations, seed=seed
|
|
267
|
+
)
|
|
268
|
+
self._request_list = self._build_request_list()
|
|
269
|
+
self._request_index = 0
|
|
270
|
+
|
|
271
|
+
self._semaphore = asyncio.Semaphore(config.num_inflight_requests)
|
|
272
|
+
self._pending_tasks: set[asyncio.Task] = set()
|
|
273
|
+
|
|
274
|
+
logger.debug(
|
|
275
|
+
"LongDocPermutator: %d contexts x %d permutations = %d requests",
|
|
276
|
+
config.num_contexts,
|
|
277
|
+
len(self._permutations),
|
|
278
|
+
len(self._request_list),
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
def run(self) -> None:
|
|
282
|
+
"""Run warmup + benchmark, closing the HTTP client in the same loop.
|
|
283
|
+
|
|
284
|
+
Overrides ``BaseWorkload.run()`` to ensure the ``RequestSender``'s
|
|
285
|
+
async HTTP client is closed before the event loop shuts down.
|
|
286
|
+
``asyncio.run()`` closes the loop on exit, which orphans any open
|
|
287
|
+
httpx connections; closing the client here — inside the same
|
|
288
|
+
``asyncio.run()`` — tears them down cleanly so the caller's
|
|
289
|
+
subsequent ``asyncio.run(request_sender.close())`` finds nothing
|
|
290
|
+
to close and completes without error.
|
|
291
|
+
"""
|
|
292
|
+
|
|
293
|
+
async def _run_and_close() -> None:
|
|
294
|
+
try:
|
|
295
|
+
await self._run_async()
|
|
296
|
+
finally:
|
|
297
|
+
await self._request_sender.close()
|
|
298
|
+
|
|
299
|
+
asyncio.run(_run_and_close())
|
|
300
|
+
|
|
301
|
+
def log_config(self) -> None:
|
|
302
|
+
"""Log key workload config before the benchmark starts."""
|
|
303
|
+
c = self._config
|
|
304
|
+
B = "\033[1m"
|
|
305
|
+
C = "\033[96m"
|
|
306
|
+
Y = "\033[93m"
|
|
307
|
+
R = "\033[0m"
|
|
308
|
+
total = len(self._request_list)
|
|
309
|
+
actual_perms = len(self._permutations)
|
|
310
|
+
print(
|
|
311
|
+
f"{B}{'═' * 50}{R}\n"
|
|
312
|
+
f"{B} Workload: {C}long-doc-permutator{R}\n"
|
|
313
|
+
f"{B}{'─' * 50}{R}\n"
|
|
314
|
+
f" Contexts: {Y}{c.num_contexts}{R}\n"
|
|
315
|
+
f" Context length: {Y}{c.context_length}{R} tokens\n"
|
|
316
|
+
f" System prompt: {Y}{c.system_prompt_length}{R} tokens\n"
|
|
317
|
+
f" Permutations: {Y}{actual_perms}{R} "
|
|
318
|
+
f"(of {math.factorial(c.num_contexts)} possible)\n"
|
|
319
|
+
f" Total requests: {Y}{total}{R}\n"
|
|
320
|
+
f" Vocab size: {Y}{c.vocab_size}{R}\n"
|
|
321
|
+
f" Max inflight: {Y}{c.num_inflight_requests}{R}\n"
|
|
322
|
+
f"{B}{'═' * 50}{R}"
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
# ------------------------------------------------------------------
|
|
326
|
+
# Data generation
|
|
327
|
+
# ------------------------------------------------------------------
|
|
328
|
+
|
|
329
|
+
def _build_request_list(self) -> list[tuple[list[dict[str, str]], int]]:
|
|
330
|
+
"""Build the full request list from the enumerated permutations.
|
|
331
|
+
|
|
332
|
+
Each entry is ``(messages, permutation_index)`` where messages
|
|
333
|
+
concatenates all contexts in permutation order into a single user
|
|
334
|
+
message, preceded by the system prompt.
|
|
335
|
+
|
|
336
|
+
Returns:
|
|
337
|
+
List of (messages, permutation_index) tuples.
|
|
338
|
+
"""
|
|
339
|
+
requests: list[tuple[list[dict[str, str]], int]] = []
|
|
340
|
+
for perm_idx, perm in enumerate(self._permutations):
|
|
341
|
+
concatenated = "\n\n".join(self._contexts[i] for i in perm)
|
|
342
|
+
messages: list[dict[str, str]] = []
|
|
343
|
+
if self._system_prompt:
|
|
344
|
+
messages.append({"role": "system", "content": self._system_prompt})
|
|
345
|
+
messages.append({"role": "user", "content": concatenated})
|
|
346
|
+
requests.append((messages, perm_idx))
|
|
347
|
+
return requests
|
|
348
|
+
|
|
349
|
+
# ------------------------------------------------------------------
|
|
350
|
+
# Warmup
|
|
351
|
+
# ------------------------------------------------------------------
|
|
352
|
+
|
|
353
|
+
async def warmup(self) -> None:
|
|
354
|
+
"""Send a single dummy warmup request to prime the engine."""
|
|
355
|
+
request_id = "warmup_0"
|
|
356
|
+
dummy_content = " ".join(["warmup"] * 500)
|
|
357
|
+
messages: list[dict[str, str]] = [
|
|
358
|
+
{"role": "system", "content": "You are a helpful assistant."},
|
|
359
|
+
{"role": "user", "content": dummy_content},
|
|
360
|
+
]
|
|
361
|
+
self._progress_monitor.log_message("Warmup (1 dummy request)")
|
|
362
|
+
self._progress_monitor.on_request_sent(request_id)
|
|
363
|
+
result = await self._request_sender.send_warmup_request(request_id, messages)
|
|
364
|
+
if not result.successful:
|
|
365
|
+
self._progress_monitor.log_message(f"Warmup request failed: {result.error}")
|
|
366
|
+
self._progress_monitor.log_message("Warmup complete")
|
|
367
|
+
|
|
368
|
+
# ------------------------------------------------------------------
|
|
369
|
+
# Benchmark dispatch
|
|
370
|
+
# ------------------------------------------------------------------
|
|
371
|
+
|
|
372
|
+
async def step(self, time_offset: float) -> float:
|
|
373
|
+
"""Dispatch the next permutation request if semaphore allows.
|
|
374
|
+
|
|
375
|
+
Args:
|
|
376
|
+
time_offset: Seconds since benchmark start (unused).
|
|
377
|
+
|
|
378
|
+
Returns:
|
|
379
|
+
0.0 to request an immediate re-call, or -1.0 when all done.
|
|
380
|
+
"""
|
|
381
|
+
if self._request_index < len(self._request_list):
|
|
382
|
+
await self._semaphore.acquire()
|
|
383
|
+
req_idx = self._request_index
|
|
384
|
+
messages, perm_idx = self._request_list[req_idx]
|
|
385
|
+
self._request_index += 1
|
|
386
|
+
|
|
387
|
+
task = asyncio.create_task(self._dispatch(messages, perm_idx, req_idx))
|
|
388
|
+
self._pending_tasks.add(task)
|
|
389
|
+
task.add_done_callback(self._on_task_done)
|
|
390
|
+
return 0.0
|
|
391
|
+
|
|
392
|
+
if self._pending_tasks:
|
|
393
|
+
await asyncio.wait(
|
|
394
|
+
self._pending_tasks,
|
|
395
|
+
return_when=asyncio.FIRST_COMPLETED,
|
|
396
|
+
)
|
|
397
|
+
return 0.0
|
|
398
|
+
|
|
399
|
+
return -1.0
|
|
400
|
+
|
|
401
|
+
async def _dispatch(
|
|
402
|
+
self,
|
|
403
|
+
messages: list[dict[str, str]],
|
|
404
|
+
perm_idx: int,
|
|
405
|
+
req_idx: int,
|
|
406
|
+
) -> None:
|
|
407
|
+
"""Send a single benchmark request, then release the semaphore.
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
messages: Chat messages for the request.
|
|
411
|
+
perm_idx: Index of the permutation (used for request ID).
|
|
412
|
+
req_idx: The request index captured before incrementing the counter.
|
|
413
|
+
"""
|
|
414
|
+
request_id = f"perm{perm_idx}_req{req_idx}"
|
|
415
|
+
self._progress_monitor.on_request_sent(request_id)
|
|
416
|
+
self._progress_monitor.log_message(f"Dispatched permutation {perm_idx}")
|
|
417
|
+
try:
|
|
418
|
+
await self._request_sender.send_request(request_id, messages)
|
|
419
|
+
finally:
|
|
420
|
+
self._semaphore.release()
|
|
421
|
+
|
|
422
|
+
def _on_task_done(self, task: asyncio.Task) -> None:
|
|
423
|
+
"""Clean up completed tasks and log unexpected errors.
|
|
424
|
+
|
|
425
|
+
Args:
|
|
426
|
+
task: The completed asyncio Task.
|
|
427
|
+
"""
|
|
428
|
+
self._pending_tasks.discard(task)
|
|
429
|
+
if not task.cancelled():
|
|
430
|
+
exc = task.exception()
|
|
431
|
+
if exc is not None:
|
|
432
|
+
self._progress_monitor.log_message(f"Dispatch task failed: {exc}")
|
|
433
|
+
|
|
434
|
+
def on_request_finished(self, request_id: str, output: str) -> None:
|
|
435
|
+
"""No-op — this workload is stateless."""
|