distributed-llm 0.4.1__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.
Files changed (806) hide show
  1. distllm/__init__.py +47 -0
  2. distllm/api/__init__.py +11 -0
  3. distllm/api/api_settings.py +126 -0
  4. distllm/api/api_state.py +85 -0
  5. distllm/api/api_versioning.py +984 -0
  6. distllm/api/app_state.py +29 -0
  7. distllm/api/auth/__init__.py +181 -0
  8. distllm/api/auth/models.py +37 -0
  9. distllm/api/auth/oauth2.py +123 -0
  10. distllm/api/auth/oidc.py +317 -0
  11. distllm/api/auth/saml.py +107 -0
  12. distllm/api/auth/store.py +39 -0
  13. distllm/api/auth_deps.py +68 -0
  14. distllm/api/authz/__init__.py +30 -0
  15. distllm/api/authz/opa.py +297 -0
  16. distllm/api/background_tasks.py +295 -0
  17. distllm/api/body_cache_middleware.py +117 -0
  18. distllm/api/circuit_breaker_middleware.py +175 -0
  19. distllm/api/cost_middleware.py +186 -0
  20. distllm/api/csrf_middleware.py +196 -0
  21. distllm/api/dedup.py +180 -0
  22. distllm/api/errors.py +256 -0
  23. distllm/api/grpc_bridge.py +296 -0
  24. distllm/api/ip_utils.py +58 -0
  25. distllm/api/middleware.py +706 -0
  26. distllm/api/observability_middleware.py +169 -0
  27. distllm/api/persistent_store.py +295 -0
  28. distllm/api/prompt_injection.py +418 -0
  29. distllm/api/quota_middleware.py +186 -0
  30. distllm/api/rate_limit_middleware.py +13 -0
  31. distllm/api/rate_limiter.py +250 -0
  32. distllm/api/rate_limiter_unified.py +975 -0
  33. distllm/api/redis_rate_limiter.py +164 -0
  34. distllm/api/routes/__init__.py +42 -0
  35. distllm/api/routes/admin.py +599 -0
  36. distllm/api/routes/api_keys.py +115 -0
  37. distllm/api/routes/assistants.py +443 -0
  38. distllm/api/routes/batch.py +1094 -0
  39. distllm/api/routes/chat.py +875 -0
  40. distllm/api/routes/completion.py +141 -0
  41. distllm/api/routes/debug.py +185 -0
  42. distllm/api/routes/defrag.py +66 -0
  43. distllm/api/routes/embeddings.py +399 -0
  44. distllm/api/routes/eval.py +254 -0
  45. distllm/api/routes/exchange.py +367 -0
  46. distllm/api/routes/experiments.py +293 -0
  47. distllm/api/routes/federated.py +155 -0
  48. distllm/api/routes/files.py +243 -0
  49. distllm/api/routes/fine_tuning.py +381 -0
  50. distllm/api/routes/gossip.py +72 -0
  51. distllm/api/routes/health.py +395 -0
  52. distllm/api/routes/leaderboard.py +377 -0
  53. distllm/api/routes/marketplace.py +320 -0
  54. distllm/api/routes/metrics_history.py +415 -0
  55. distllm/api/routes/model_registry.py +255 -0
  56. distllm/api/routes/moderation.py +420 -0
  57. distllm/api/routes/plugins.py +184 -0
  58. distllm/api/routes/prompts.py +347 -0
  59. distllm/api/routes/router_admin.py +187 -0
  60. distllm/api/routes/scheduler.py +168 -0
  61. distllm/api/routes/tokenize.py +77 -0
  62. distllm/api/routes/tools.py +89 -0
  63. distllm/api/routes/webhooks.py +336 -0
  64. distllm/api/routes/webrtc.py +194 -0
  65. distllm/api/semantic_cache.py +337 -0
  66. distllm/api/server.py +2038 -0
  67. distllm/api/server_config.py +140 -0
  68. distllm/api/server_coordinator.py +125 -0
  69. distllm/api/server_errors.py +79 -0
  70. distllm/api/server_lifespan.py +184 -0
  71. distllm/api/server_routes_api.py +456 -0
  72. distllm/api/server_routes_dashboard.py +246 -0
  73. distllm/api/server_state.py +29 -0
  74. distllm/api/services/__init__.py +2 -0
  75. distllm/api/services/chat_service.py +677 -0
  76. distllm/api/services/completion_service.py +227 -0
  77. distllm/api/services/embedding_service.py +451 -0
  78. distllm/api/services/eval_service.py +198 -0
  79. distllm/api/sso_auth.py +644 -0
  80. distllm/api/sso_middleware.py +808 -0
  81. distllm/api/streaming.py +479 -0
  82. distllm/api/token_estimator.py +86 -0
  83. distllm/api/tool_calling.py +240 -0
  84. distllm/api/tracing_middleware.py +579 -0
  85. distllm/api/validation.py +58 -0
  86. distllm/api/waf.py +344 -0
  87. distllm/api/webhooks/__init__.py +17 -0
  88. distllm/api/webhooks/delivery.py +452 -0
  89. distllm/api/ws_chat.py +495 -0
  90. distllm/backends/__init__.py +121 -0
  91. distllm/backends/config.py +85 -0
  92. distllm/backends/exllama_backend.py +229 -0
  93. distllm/backends/llamacpp_backend.py +266 -0
  94. distllm/backends/mlx_backend.py +199 -0
  95. distllm/backends/nim_backend.py +838 -0
  96. distllm/backends/ollama_backend.py +48 -0
  97. distllm/backends/onnx_backend.py +239 -0
  98. distllm/backends/paged_attention.py +547 -0
  99. distllm/backends/paged_attention_quantized.py +319 -0
  100. distllm/backends/protocol.py +203 -0
  101. distllm/backends/pytorch_backend.py +157 -0
  102. distllm/backends/registry.py +428 -0
  103. distllm/backends/tensorrt_backend.py +333 -0
  104. distllm/backends/tgi_backend.py +120 -0
  105. distllm/backends/triton_backend.py +875 -0
  106. distllm/backends/vllm_backend.py +489 -0
  107. distllm/backends/webgpu_backend.py +255 -0
  108. distllm/benchmarks/__init__.py +10 -0
  109. distllm/benchmarks/evaluation_harness.py +69 -0
  110. distllm/benchmarks/scaling.py +298 -0
  111. distllm/cache/__init__.py +19 -0
  112. distllm/cache/crdt.py +507 -0
  113. distllm/cache/cross_cluster_prefix_index.py +709 -0
  114. distllm/cli/__init__.py +17 -0
  115. distllm/cli/adapters.py +93 -0
  116. distllm/cli/autopsy.py +287 -0
  117. distllm/cli/backup.py +118 -0
  118. distllm/cli/benchmark.py +241 -0
  119. distllm/cli/cert.py +86 -0
  120. distllm/cli/chat.py +79 -0
  121. distllm/cli/chat_stream.py +494 -0
  122. distllm/cli/client.py +233 -0
  123. distllm/cli/cluster.py +405 -0
  124. distllm/cli/completion.py +79 -0
  125. distllm/cli/compress.py +98 -0
  126. distllm/cli/config_commands.py +71 -0
  127. distllm/cli/cost_avoid.py +168 -0
  128. distllm/cli/daas_commands.py +123 -0
  129. distllm/cli/defrag_commands.py +128 -0
  130. distllm/cli/deploy.py +252 -0
  131. distllm/cli/doctor.py +688 -0
  132. distllm/cli/draft_commands.py +82 -0
  133. distllm/cli/error_handler.py +192 -0
  134. distllm/cli/eval.py +168 -0
  135. distllm/cli/federate_commands.py +125 -0
  136. distllm/cli/install.py +198 -0
  137. distllm/cli/logs.py +85 -0
  138. distllm/cli/main.py +1795 -0
  139. distllm/cli/models.py +74 -0
  140. distllm/cli/notify.py +91 -0
  141. distllm/cli/observe.py +314 -0
  142. distllm/cli/onboard.py +671 -0
  143. distllm/cli/output.py +437 -0
  144. distllm/cli/profile.py +152 -0
  145. distllm/cli/profile_presets.py +129 -0
  146. distllm/cli/prompts.py +139 -0
  147. distllm/cli/quota.py +227 -0
  148. distllm/cli/router.py +131 -0
  149. distllm/cli/run.py +59 -0
  150. distllm/cli/setup.py +104 -0
  151. distllm/cli/setup_wizard.py +191 -0
  152. distllm/cli/status.py +65 -0
  153. distllm/cli/system_commands.py +255 -0
  154. distllm/cli/tune.py +488 -0
  155. distllm/cli/tutorial.py +128 -0
  156. distllm/cli/verify.py +37 -0
  157. distllm/cli/webhook.py +85 -0
  158. distllm/client/__init__.py +38 -0
  159. distllm/client/client.py +503 -0
  160. distllm/cloud/__init__.py +53 -0
  161. distllm/cloud/aws.py +199 -0
  162. distllm/cloud/azure.py +179 -0
  163. distllm/cloud/common.py +217 -0
  164. distllm/cloud/gcp.py +238 -0
  165. distllm/cloud/spot_orchestrator.py +1642 -0
  166. distllm/cloud/worker_agent.py +344 -0
  167. distllm/compliance/__init__.py +10 -0
  168. distllm/compliance/evidence_pack.py +699 -0
  169. distllm/config/__init__.py +81 -0
  170. distllm/config/_application.py +41 -0
  171. distllm/config/_backends.py +80 -0
  172. distllm/config/_cache.py +121 -0
  173. distllm/config/_deployment.py +95 -0
  174. distllm/config/_generation.py +36 -0
  175. distllm/config/_hardware.py +42 -0
  176. distllm/config/_model.py +270 -0
  177. distllm/config/_network.py +235 -0
  178. distllm/config/_observability.py +42 -0
  179. distllm/config/_parallelism.py +172 -0
  180. distllm/config/_performance.py +47 -0
  181. distllm/config/loader.py +168 -0
  182. distllm/config/model_heuristics.py +169 -0
  183. distllm/config/profiles.py +168 -0
  184. distllm/config/reference.py +104 -0
  185. distllm/config/resolver.py +240 -0
  186. distllm/config/settings.py +463 -0
  187. distllm/constants.py +117 -0
  188. distllm/core/__init__.py +111 -0
  189. distllm/core/_advanced_scheduling_original.py +1892 -0
  190. distllm/core/ab_test_coordinator.py +178 -0
  191. distllm/core/activation_profiler.py +172 -0
  192. distllm/core/adaptive_batching.py +234 -0
  193. distllm/core/adaptive_cache_compressor.py +168 -0
  194. distllm/core/adaptive_compression.py +427 -0
  195. distllm/core/adaptive_compression_hierarchy.py +402 -0
  196. distllm/core/advanced_scheduling/__init__.py +39 -0
  197. distllm/core/advanced_scheduling/cost_aware.py +55 -0
  198. distllm/core/advanced_scheduling/disaggregated.py +352 -0
  199. distllm/core/advanced_scheduling/energy.py +58 -0
  200. distllm/core/advanced_scheduling/federated.py +59 -0
  201. distllm/core/advanced_scheduling/heterogeneous.py +84 -0
  202. distllm/core/advanced_scheduling/multi_objective.py +372 -0
  203. distllm/core/advanced_scheduling/policy.py +95 -0
  204. distllm/core/advanced_scheduling/predictive.py +47 -0
  205. distllm/core/advanced_scheduling/preemption.py +43 -0
  206. distllm/core/advanced_scheduling/tiered_store.py +604 -0
  207. distllm/core/advanced_scheduling/token_bank.py +62 -0
  208. distllm/core/advanced_scheduling/wan.py +85 -0
  209. distllm/core/aegis_compliance.py +890 -0
  210. distllm/core/aether_federated.py +1326 -0
  211. distllm/core/agentic_router.py +749 -0
  212. distllm/core/api_key_store.py +478 -0
  213. distllm/core/arbitrage_engine.py +613 -0
  214. distllm/core/aria_autoscaler.py +1339 -0
  215. distllm/core/async_connection_pool.py +187 -0
  216. distllm/core/async_pipelined_speculative.py +543 -0
  217. distllm/core/atlas_mesh.py +1437 -0
  218. distllm/core/auto_discovery.py +351 -0
  219. distllm/core/auto_partitioner.py +396 -0
  220. distllm/core/autonomous_healer.py +466 -0
  221. distllm/core/autoq.py +1545 -0
  222. distllm/core/backup_manager.py +344 -0
  223. distllm/core/bargaining_engine.py +450 -0
  224. distllm/core/batch_builder.py +480 -0
  225. distllm/core/batch_scheduler.py +1342 -0
  226. distllm/core/block_affinity_tracker.py +162 -0
  227. distllm/core/block_eviction_policy.py +363 -0
  228. distllm/core/cache_aware_router.py +116 -0
  229. distllm/core/cache_bench.py +239 -0
  230. distllm/core/cache_coherence.py +139 -0
  231. distllm/core/cache_doctor.py +220 -0
  232. distllm/core/cache_eviction.py +181 -0
  233. distllm/core/cache_index.py +91 -0
  234. distllm/core/cache_manager.py +703 -0
  235. distllm/core/cache_migration.py +134 -0
  236. distllm/core/cache_persistence.py +200 -0
  237. distllm/core/cache_query_log.py +195 -0
  238. distllm/core/cache_snapshot.py +178 -0
  239. distllm/core/cache_template_warmer.py +112 -0
  240. distllm/core/cache_warming.py +188 -0
  241. distllm/core/calibration.py +223 -0
  242. distllm/core/carbon_migration.py +338 -0
  243. distllm/core/cert_rotation.py +402 -0
  244. distllm/core/certificate_manager.py +414 -0
  245. distllm/core/cluster_manager.py +212 -0
  246. distllm/core/cluster_predictive_prefetcher.py +239 -0
  247. distllm/core/cluster_registry.py +227 -0
  248. distllm/core/cluster_state_store.py +442 -0
  249. distllm/core/compliance_evidence.py +503 -0
  250. distllm/core/compressed_speculative.py +399 -0
  251. distllm/core/connection_pool.py +387 -0
  252. distllm/core/constrained_decoder.py +678 -0
  253. distllm/core/coordinator.py +1594 -0
  254. distllm/core/coordinator_cli.py +130 -0
  255. distllm/core/coordinator_config.py +203 -0
  256. distllm/core/coordinator_config_wiring.py +316 -0
  257. distllm/core/coordinator_election.py +246 -0
  258. distllm/core/coordinator_failover.py +197 -0
  259. distllm/core/coordinator_health.py +135 -0
  260. distllm/core/coordinator_lifecycle.py +272 -0
  261. distllm/core/coordinator_metrics.py +155 -0
  262. distllm/core/coordinator_multi_model.py +41 -0
  263. distllm/core/coordinator_request.py +246 -0
  264. distllm/core/coordinator_state.py +215 -0
  265. distllm/core/coordinator_subsystem.py +614 -0
  266. distllm/core/correctness_cert.py +133 -0
  267. distllm/core/correctness_harness.py +421 -0
  268. distllm/core/cortex_multimodel.py +939 -0
  269. distllm/core/cost_comparison.py +250 -0
  270. distllm/core/cost_dashboard.py +363 -0
  271. distllm/core/cost_optimizer.py +317 -0
  272. distllm/core/cost_tracker.py +569 -0
  273. distllm/core/cross_cloud_router.py +924 -0
  274. distllm/core/cross_model_prefix_sharing.py +237 -0
  275. distllm/core/cuda_graph.py +165 -0
  276. distllm/core/debug.py +84 -0
  277. distllm/core/device_registry.py +289 -0
  278. distllm/core/di.py +153 -0
  279. distllm/core/differential_privacy.py +183 -0
  280. distllm/core/distributed_distillation.py +402 -0
  281. distllm/core/distributed_speculative.py +1563 -0
  282. distllm/core/dp_inference/__init__.py +657 -0
  283. distllm/core/dp_inference/accounting.py +144 -0
  284. distllm/core/dp_inference/config.py +139 -0
  285. distllm/core/dp_inference/mechanisms.py +137 -0
  286. distllm/core/dp_inference.py +1016 -0
  287. distllm/core/draft_model_router.py +435 -0
  288. distllm/core/draft_quality_scorer.py +157 -0
  289. distllm/core/draft_tree.py +232 -0
  290. distllm/core/dynamic_memory_budget.py +179 -0
  291. distllm/core/dynamic_sharder.py +364 -0
  292. distllm/core/dynamic_speculation.py +131 -0
  293. distllm/core/evaluation/__init__.py +57 -0
  294. distllm/core/evaluation/constants.py +86 -0
  295. distllm/core/evaluation/db.py +185 -0
  296. distllm/core/evaluation/formatters.py +82 -0
  297. distllm/core/evaluation/loaders.py +320 -0
  298. distllm/core/evaluation/models.py +66 -0
  299. distllm/core/evaluation/report.py +79 -0
  300. distllm/core/evaluation/runner.py +518 -0
  301. distllm/core/evaluation/scorers.py +278 -0
  302. distllm/core/evaluation/worker.py +123 -0
  303. distllm/core/evaluation_harness.py +1530 -0
  304. distllm/core/event_bus.py +516 -0
  305. distllm/core/faas_7b.py +201 -0
  306. distllm/core/feature_flags.py +245 -0
  307. distllm/core/federated_finetuner.py +377 -0
  308. distllm/core/federated_incentives.py +267 -0
  309. distllm/core/framework_adapters.py +390 -0
  310. distllm/core/gaia_cache.py +1330 -0
  311. distllm/core/gossip_cache_bridge.py +202 -0
  312. distllm/core/gpu_power_manager.py +173 -0
  313. distllm/core/gpu_profiler.py +59 -0
  314. distllm/core/gpu_resource_manager.py +338 -0
  315. distllm/core/graceful_degradation.py +264 -0
  316. distllm/core/grammar_constrained.py +549 -0
  317. distllm/core/grammar_constrained_draft.py +91 -0
  318. distllm/core/grammar_decoder.py +285 -0
  319. distllm/core/ha_coordinator.py +452 -0
  320. distllm/core/hardware_plugin_registry.py +126 -0
  321. distllm/core/hashing.py +29 -0
  322. distllm/core/health_manager.py +320 -0
  323. distllm/core/heterogeneous_scheduler.py +663 -0
  324. distllm/core/hibernation_manager.py +250 -0
  325. distllm/core/hierarchical_digest.py +168 -0
  326. distllm/core/hybrid_cache.py +253 -0
  327. distllm/core/hydra_diffusion.py +177 -0
  328. distllm/core/inference_engine.py +1072 -0
  329. distllm/core/intelligent_autoscaler.py +219 -0
  330. distllm/core/kraken_chaos.py +1407 -0
  331. distllm/core/kv_backup.py +217 -0
  332. distllm/core/kv_cache.py +1271 -0
  333. distllm/core/kv_cache_adaptive_quantizer.py +168 -0
  334. distllm/core/kv_cache_compressor.py +290 -0
  335. distllm/core/kv_cache_manager.py +142 -0
  336. distllm/core/kv_cache_marketplace.py +319 -0
  337. distllm/core/kv_cache_metrics.py +205 -0
  338. distllm/core/kv_cache_migration.py +137 -0
  339. distllm/core/kv_cache_paged.py +78 -0
  340. distllm/core/kv_cache_replication.py +107 -0
  341. distllm/core/kv_cache_serialization.py +182 -0
  342. distllm/core/latency_tracker.py +17 -0
  343. distllm/core/leaky_bucket_limiter.py +194 -0
  344. distllm/core/learning_router.py +652 -0
  345. distllm/core/llamacpp_backend.py +23 -0
  346. distllm/core/load_balancer.py +286 -0
  347. distllm/core/media_pipeline.py +387 -0
  348. distllm/core/memory_defragmenter.py +666 -0
  349. distllm/core/metering.py +449 -0
  350. distllm/core/metrics_collector.py +39 -0
  351. distllm/core/micro_batch_scheduler.py +170 -0
  352. distllm/core/model_hub_enhanced.py +382 -0
  353. distllm/core/model_registry.py +9 -0
  354. distllm/core/model_router.py +930 -0
  355. distllm/core/model_selector.py +245 -0
  356. distllm/core/model_sizing.py +334 -0
  357. distllm/core/model_version_manager.py +414 -0
  358. distllm/core/moe_orchestrator.py +205 -0
  359. distllm/core/money.py +53 -0
  360. distllm/core/monitor.py +141 -0
  361. distllm/core/mtp_head.py +444 -0
  362. distllm/core/multi_draft_verifier.py +346 -0
  363. distllm/core/multi_model_serving.py +624 -0
  364. distllm/core/multimodal_engine.py +194 -0
  365. distllm/core/neural_partition_optimizer.py +1398 -0
  366. distllm/core/node_recovery.py +27 -0
  367. distllm/core/notification_manager.py +317 -0
  368. distllm/core/param_update_channel.py +104 -0
  369. distllm/core/pareto_optimizer.py +227 -0
  370. distllm/core/performance_alerts.py +198 -0
  371. distllm/core/performance_baseline.py +252 -0
  372. distllm/core/persistence.py +947 -0
  373. distllm/core/persistent_store.py +485 -0
  374. distllm/core/pipeline_composer.py +211 -0
  375. distllm/core/pipeline_executor.py +500 -0
  376. distllm/core/pipeline_orchestrator.py +17 -0
  377. distllm/core/pipeline_overlap.py +177 -0
  378. distllm/core/placement.py +442 -0
  379. distllm/core/plugin_marketplace.py +483 -0
  380. distllm/core/plugin_sandbox.py +751 -0
  381. distllm/core/plugin_system.py +601 -0
  382. distllm/core/plugins/__init__.py +26 -0
  383. distllm/core/plugins/sandbox.py +38 -0
  384. distllm/core/predictive_cache.py +29 -0
  385. distllm/core/predictive_cache_warming.py +323 -0
  386. distllm/core/predictive_failure.py +163 -0
  387. distllm/core/preemptible_scheduler.py +343 -0
  388. distllm/core/preference_learning.py +606 -0
  389. distllm/core/prefix_cache.py +17 -0
  390. distllm/core/pricing_providers.py +576 -0
  391. distllm/core/priority_heap.py +62 -0
  392. distllm/core/privacy_budget.py +177 -0
  393. distllm/core/prompt_caching_service.py +228 -0
  394. distllm/core/prompt_library.py +838 -0
  395. distllm/core/protocols.py +213 -0
  396. distllm/core/provider_health.py +234 -0
  397. distllm/core/provisioning.py +329 -0
  398. distllm/core/pulse_performance_model.py +1558 -0
  399. distllm/core/quantization_selector.py +210 -0
  400. distllm/core/radix_tree_cache.py +306 -0
  401. distllm/core/rebalancer.py +25 -0
  402. distllm/core/redis_prompt_cache.py +311 -0
  403. distllm/core/replication_controller.py +128 -0
  404. distllm/core/request_auditor.py +215 -0
  405. distllm/core/request_fingerprinting.py +231 -0
  406. distllm/core/request_latency.py +211 -0
  407. distllm/core/request_pipeline.py +810 -0
  408. distllm/core/request_replay.py +253 -0
  409. distllm/core/request_tracker.py +184 -0
  410. distllm/core/resource_manager.py +657 -0
  411. distllm/core/route_audit.py +175 -0
  412. distllm/core/routing_extensions.py +604 -0
  413. distllm/core/schedule_simulator.py +289 -0
  414. distllm/core/schedule_viz.py +233 -0
  415. distllm/core/scheduler/__init__.py +34 -0
  416. distllm/core/scheduler/budget.py +25 -0
  417. distllm/core/scheduler/budget_computer.py +322 -0
  418. distllm/core/scheduler/chunked_prefill.py +52 -0
  419. distllm/core/scheduler/kv_cache_manager.py +313 -0
  420. distllm/core/scheduler/preemption_manager.py +251 -0
  421. distllm/core/scheduler/pressure.py +48 -0
  422. distllm/core/scheduler/sequence.py +179 -0
  423. distllm/core/secret_manager.py +315 -0
  424. distllm/core/semantic_cache.py +369 -0
  425. distllm/core/sentinel_qos.py +833 -0
  426. distllm/core/shadow_eval_runner.py +194 -0
  427. distllm/core/shared_layer_pool.py +279 -0
  428. distllm/core/smart_model_router.py +309 -0
  429. distllm/core/spec_equivalence.py +140 -0
  430. distllm/core/spec_verify.py +225 -0
  431. distllm/core/speculative_adaptor.py +108 -0
  432. distllm/core/speculative_dashboard.py +134 -0
  433. distllm/core/speculative_decoder.py +1286 -0
  434. distllm/core/speculative_profiler.py +132 -0
  435. distllm/core/split_brain.py +236 -0
  436. distllm/core/spot_failover.py +292 -0
  437. distllm/core/spot_forecasting.py +463 -0
  438. distllm/core/starvation_monitor.py +70 -0
  439. distllm/core/state_replication.py +261 -0
  440. distllm/core/stats_collector.py +64 -0
  441. distllm/core/step_processor.py +115 -0
  442. distllm/core/straggler_alerts.py +174 -0
  443. distllm/core/straggler_aware_scheduler.py +255 -0
  444. distllm/core/straggler_detector.py +29 -0
  445. distllm/core/streaming_cost.py +286 -0
  446. distllm/core/streaming_generator.py +228 -0
  447. distllm/core/structured_output/__init__.py +348 -0
  448. distllm/core/structured_output/config.py +38 -0
  449. distllm/core/structured_output/engine.py +367 -0
  450. distllm/core/structured_output/streaming.py +183 -0
  451. distllm/core/structured_output/validator.py +199 -0
  452. distllm/core/subsystem_registry.py +171 -0
  453. distllm/core/synapse_debugger.py +226 -0
  454. distllm/core/synth_data_generator.py +122 -0
  455. distllm/core/telemetry.py +240 -0
  456. distllm/core/tenant_billing.py +446 -0
  457. distllm/core/tenant_cost_attribution.py +314 -0
  458. distllm/core/token_generator.py +368 -0
  459. distllm/core/token_streaming_buffer.py +147 -0
  460. distllm/core/topology_aware_lb.py +324 -0
  461. distllm/core/topology_aware_tiering.py +344 -0
  462. distllm/core/tree_speculative_decoder.py +405 -0
  463. distllm/core/types.py +17 -0
  464. distllm/core/unified_router.py +439 -0
  465. distllm/core/unified_sla_router.py +242 -0
  466. distllm/core/usage_meter.py +915 -0
  467. distllm/core/vectorstore/__init__.py +30 -0
  468. distllm/core/vectorstore/base.py +106 -0
  469. distllm/core/vectorstore/chroma_store.py +99 -0
  470. distllm/core/vectorstore/factory.py +97 -0
  471. distllm/core/vectorstore/pgvector_store.py +123 -0
  472. distllm/core/vectorstore/providers/__init__.py +7 -0
  473. distllm/core/vectorstore/providers/milvus.py +219 -0
  474. distllm/core/vectorstore/providers/pinecone.py +142 -0
  475. distllm/core/vectorstore/providers/qdrant.py +176 -0
  476. distllm/core/vectorstore/providers/weaviate.py +185 -0
  477. distllm/core/vectorstore/qdrant_store.py +148 -0
  478. distllm/core/vectorstore/rag.py +151 -0
  479. distllm/core/vllm_backend.py +21 -0
  480. distllm/core/vllm_node.py +174 -0
  481. distllm/core/voyager_multimodal.py +1354 -0
  482. distllm/core/webgpu_manager.py +382 -0
  483. distllm/core/webhook_formatters.py +243 -0
  484. distllm/core/webhook_manager.py +433 -0
  485. distllm/core/wisp_wasm.py +934 -0
  486. distllm/core/workload_classifier.py +137 -0
  487. distllm/dashboard/__init__.py +17 -0
  488. distllm/dashboard/verification_history.py +192 -0
  489. distllm/dashboard/ws_handler.py +586 -0
  490. distllm/dist/__init__.py +85 -0
  491. distllm/dist/__init__.pyi +132 -0
  492. distllm/dist/_pipeline_original.py +2916 -0
  493. distllm/dist/adaptive_speculator.py +384 -0
  494. distllm/dist/admin_cli.py +293 -0
  495. distllm/dist/api_docs.py +594 -0
  496. distllm/dist/async_pipeline.py +578 -0
  497. distllm/dist/attention.py +1699 -0
  498. distllm/dist/attention_block_pool.py +634 -0
  499. distllm/dist/attention_distributed.py +138 -0
  500. distllm/dist/autoscaler.py +196 -0
  501. distllm/dist/backends/__init__.py +29 -0
  502. distllm/dist/backends/backend_profiles.py +357 -0
  503. distllm/dist/backends/graceful_degradation.py +409 -0
  504. distllm/dist/backends/health_monitor.py +518 -0
  505. distllm/dist/backends/llamacpp.py +125 -0
  506. distllm/dist/backends/ray.py +89 -0
  507. distllm/dist/backends/vllm.py +177 -0
  508. distllm/dist/block_pool.py +662 -0
  509. distllm/dist/block_transfer_service.py +267 -0
  510. distllm/dist/byzantine.py +2193 -0
  511. distllm/dist/cache.py +305 -0
  512. distllm/dist/cache_digest.py +405 -0
  513. distllm/dist/chaos/__init__.py +52 -0
  514. distllm/dist/chaos/chaos_orchestrator.py +229 -0
  515. distllm/dist/chaos/fault_injector.py +1273 -0
  516. distllm/dist/chunked_prefill.py +136 -0
  517. distllm/dist/cloud_selector.py +257 -0
  518. distllm/dist/config.py +70 -0
  519. distllm/dist/cross_cluster.py +231 -0
  520. distllm/dist/daas/__init__.py +46 -0
  521. distllm/dist/daas/load_balancer.py +275 -0
  522. distllm/dist/daas/marketplace_integration.py +374 -0
  523. distllm/dist/daas/resource_isolation.py +280 -0
  524. distllm/dist/daas/tenant_dispatcher.py +252 -0
  525. distllm/dist/daas/usage_meter.py +360 -0
  526. distllm/dist/daas_server.py +514 -0
  527. distllm/dist/disagg/__init__.py +162 -0
  528. distllm/dist/disagg/pool.py +214 -0
  529. distllm/dist/disagg/transfer.py +77 -0
  530. distllm/dist/disagg/transfer_compression.py +793 -0
  531. distllm/dist/disagg/transfer_engine.py +998 -0
  532. distllm/dist/discovery.py +166 -0
  533. distllm/dist/draft_bank.py +344 -0
  534. distllm/dist/draft_migration.py +382 -0
  535. distllm/dist/ebpf_transport.py +364 -0
  536. distllm/dist/edge_cloud.py +544 -0
  537. distllm/dist/edge_federation.py +426 -0
  538. distllm/dist/execution_planner.py +148 -0
  539. distllm/dist/federated_merge.py +560 -0
  540. distllm/dist/federation.py +1114 -0
  541. distllm/dist/flash_attention.py +237 -0
  542. distllm/dist/fsdp.py +295 -0
  543. distllm/dist/geo.py +361 -0
  544. distllm/dist/ice_transport.py +2968 -0
  545. distllm/dist/kv_migration.py +237 -0
  546. distllm/dist/latency.py +60 -0
  547. distllm/dist/lifecycle.py +467 -0
  548. distllm/dist/marketplace.py +891 -0
  549. distllm/dist/merkle.py +178 -0
  550. distllm/dist/metrics.py +456 -0
  551. distllm/dist/model_store.py +107 -0
  552. distllm/dist/multi_tenant.py +339 -0
  553. distllm/dist/multimodal.py +392 -0
  554. distllm/dist/nat.py +934 -0
  555. distllm/dist/nccl.py +733 -0
  556. distllm/dist/network.py +126 -0
  557. distllm/dist/node_client.py +568 -0
  558. distllm/dist/node_pb2.py +66 -0
  559. distllm/dist/node_pb2.pyi +236 -0
  560. distllm/dist/node_pb2_grpc.py +312 -0
  561. distllm/dist/node_pb2_grpc.pyi +41 -0
  562. distllm/dist/node_registrar.py +247 -0
  563. distllm/dist/node_service.py +572 -0
  564. distllm/dist/observability.py +258 -0
  565. distllm/dist/otel.py +158 -0
  566. distllm/dist/p2p/__init__.py +22 -0
  567. distllm/dist/p2p/discovery.py +132 -0
  568. distllm/dist/p2p/gossip.py +1339 -0
  569. distllm/dist/p2p/kademlia_dht.py +1058 -0
  570. distllm/dist/p2p/load_balancer.py +131 -0
  571. distllm/dist/p2p/quic_transport.py +700 -0
  572. distllm/dist/p2p/router.py +607 -0
  573. distllm/dist/p2p/transport.py +399 -0
  574. distllm/dist/p2p_model_distributor.py +160 -0
  575. distllm/dist/paged_attention_kernel.py +281 -0
  576. distllm/dist/parallel.py +1061 -0
  577. distllm/dist/parallel_planner.py +586 -0
  578. distllm/dist/parallel_topology.py +231 -0
  579. distllm/dist/partition/__init__.py +146 -0
  580. distllm/dist/partition/adaptive.py +532 -0
  581. distllm/dist/partition/benchmark_suite.py +479 -0
  582. distllm/dist/partition/cli.py +189 -0
  583. distllm/dist/partition/cloud_arbitrage.py +523 -0
  584. distllm/dist/partition/config.py +97 -0
  585. distllm/dist/partition/cost_model.py +553 -0
  586. distllm/dist/partition/learned_cost.py +653 -0
  587. distllm/dist/partition/mixed_precision_tuner.py +310 -0
  588. distllm/dist/partition/network_cost_model.py +664 -0
  589. distllm/dist/partition/optimizer.py +650 -0
  590. distllm/dist/partition/pareto_optimizer.py +466 -0
  591. distllm/dist/partition/partitioner.py +363 -0
  592. distllm/dist/partition/persistence.py +392 -0
  593. distllm/dist/partition/plugins.py +270 -0
  594. distllm/dist/partition/profiles.py +659 -0
  595. distllm/dist/partition/quant_bench.py +373 -0
  596. distllm/dist/partition/quant_calibrate.py +229 -0
  597. distllm/dist/partition/quant_coordinator.py +260 -0
  598. distllm/dist/partition/quant_cost.py +293 -0
  599. distllm/dist/partition/quant_partition.py +432 -0
  600. distllm/dist/partition/quant_report.py +301 -0
  601. distllm/dist/partition/quantization_metrics.py +355 -0
  602. distllm/dist/partition/quantization_search.py +290 -0
  603. distllm/dist/partition/quantization_tuner.py +1383 -0
  604. distllm/dist/partition/topology.py +218 -0
  605. distllm/dist/partition/validator.py +405 -0
  606. distllm/dist/partition/visualizer.py +275 -0
  607. distllm/dist/pipeline/__init__.py +71 -0
  608. distllm/dist/pipeline/bandwidth_controller.py +780 -0
  609. distllm/dist/pipeline/compression_negotiation.py +771 -0
  610. distllm/dist/pipeline/context.py +80 -0
  611. distllm/dist/pipeline/continuous_batching.py +435 -0
  612. distllm/dist/pipeline/disagg_orchestrator.py +284 -0
  613. distllm/dist/pipeline/orchestrator.py +727 -0
  614. distllm/dist/pipeline/pipeline_reconfig.py +1395 -0
  615. distllm/dist/pipeline/profiler.py +84 -0
  616. distllm/dist/pipeline/serialization.py +176 -0
  617. distllm/dist/pipeline/simulator.py +172 -0
  618. distllm/dist/pipeline/strategy.py +193 -0
  619. distllm/dist/pipeline/token_accumulator.py +211 -0
  620. distllm/dist/pipeline/transport.py +230 -0
  621. distllm/dist/pipeline/wan_disagg_orchestrator.py +564 -0
  622. distllm/dist/power_cap.py +358 -0
  623. distllm/dist/predictive_cache.py +399 -0
  624. distllm/dist/preemption.py +198 -0
  625. distllm/dist/prefix_cache.py +461 -0
  626. distllm/dist/prefix_clustering.py +305 -0
  627. distllm/dist/privacy/__init__.py +411 -0
  628. distllm/dist/privacy/privacy_accountant.py +344 -0
  629. distllm/dist/privacy.py +240 -0
  630. distllm/dist/provisioning.py +338 -0
  631. distllm/dist/quality.py +118 -0
  632. distllm/dist/quic_transport.py +335 -0
  633. distllm/dist/quota_enforcer.py +265 -0
  634. distllm/dist/rebalancer.py +234 -0
  635. distllm/dist/recovery.py +827 -0
  636. distllm/dist/recovery_drill.py +281 -0
  637. distllm/dist/redis_cache.py +265 -0
  638. distllm/dist/redundant.py +308 -0
  639. distllm/dist/redundant_executor.py +1536 -0
  640. distllm/dist/reputation.py +231 -0
  641. distllm/dist/router.py +382 -0
  642. distllm/dist/routing/__init__.py +19 -0
  643. distllm/dist/routing/arbitrage_engine.py +575 -0
  644. distllm/dist/routing/composite.py +179 -0
  645. distllm/dist/routing/consistent_hash.py +144 -0
  646. distllm/dist/routing/latency_aware.py +116 -0
  647. distllm/dist/routing/load_aware.py +114 -0
  648. distllm/dist/scheduling/__init__.py +38 -0
  649. distllm/dist/scheduling/batcher.py +95 -0
  650. distllm/dist/scheduling/classifier.py +153 -0
  651. distllm/dist/scheduling/deadline_scheduler.py +958 -0
  652. distllm/dist/scheduling/iteration.py +404 -0
  653. distllm/dist/scheduling/profiler.py +57 -0
  654. distllm/dist/simulation/__init__.py +54 -0
  655. distllm/dist/simulation/chaos_simulator.py +901 -0
  656. distllm/dist/simulation/cluster_simulator.py +667 -0
  657. distllm/dist/simulation/cost_aware_provisioning.py +370 -0
  658. distllm/dist/simulation/digital_twin.py +617 -0
  659. distllm/dist/simulation/topology_optimizer.py +747 -0
  660. distllm/dist/simulation/what_if.py +492 -0
  661. distllm/dist/speculative/__init__.py +47 -0
  662. distllm/dist/speculative/adaptive_spec.py +291 -0
  663. distllm/dist/speculative/draft_cache.py +246 -0
  664. distllm/dist/speculative/draft_orchestrator.py +634 -0
  665. distllm/dist/speculative/draft_registry.py +439 -0
  666. distllm/dist/speculative/multi_draft.py +304 -0
  667. distllm/dist/speculative/online_sisd.py +523 -0
  668. distllm/dist/straggler.py +819 -0
  669. distllm/dist/streaming_kv_transfer.py +174 -0
  670. distllm/dist/structured_output/__init__.py +7 -0
  671. distllm/dist/structured_output/engine.py +144 -0
  672. distllm/dist/tensor_pool.py +120 -0
  673. distllm/dist/tgi_compat.py +254 -0
  674. distllm/dist/topology.py +141 -0
  675. distllm/dist/topology_consensus.py +1961 -0
  676. distllm/dist/topology_dynamic.py +270 -0
  677. distllm/dist/tp_inprocess.py +214 -0
  678. distllm/dist/tp_launcher.py +310 -0
  679. distllm/dist/tracing.py +325 -0
  680. distllm/dist/transport.py +493 -0
  681. distllm/dist/wan_speculative.py +295 -0
  682. distllm/dist/wandb_integration.py +252 -0
  683. distllm/dist/webrtc.py +846 -0
  684. distllm/dist/wide_area.py +515 -0
  685. distllm/dist/worker.py +635 -0
  686. distllm/dist/zero_copy.py +307 -0
  687. distllm/errors/__init__.py +105 -0
  688. distllm/errors/policies.py +106 -0
  689. distllm/errors/retry.py +168 -0
  690. distllm/errors/types.py +721 -0
  691. distllm/health/__init__.py +6 -0
  692. distllm/health/failover.py +81 -0
  693. distllm/health/prober.py +31 -0
  694. distllm/health/service.py +173 -0
  695. distllm/health/state.py +76 -0
  696. distllm/integrations/__init__.py +72 -0
  697. distllm/integrations/_common/__init__.py +7 -0
  698. distllm/integrations/_common/base_tool_provider.py +189 -0
  699. distllm/integrations/_common/cost_tracker.py +144 -0
  700. distllm/integrations/_common/model_router.py +148 -0
  701. distllm/integrations/ci/__init__.py +24 -0
  702. distllm/integrations/ci/_common.py +92 -0
  703. distllm/integrations/ci/gitlab.py +345 -0
  704. distllm/integrations/ci/jenkins.py +273 -0
  705. distllm/integrations/mlflow_tracking.py +372 -0
  706. distllm/integrations/spark_connector.py +909 -0
  707. distllm/integrations/wandb/__init__.py +81 -0
  708. distllm/models/__init__.py +40 -0
  709. distllm/models/_trust_remote.py +48 -0
  710. distllm/models/adapter.py +768 -0
  711. distllm/models/adapter_router.py +198 -0
  712. distllm/models/cache.py +172 -0
  713. distllm/models/model_hub.py +650 -0
  714. distllm/models/partition_planner.py +384 -0
  715. distllm/models/partitioner.py +784 -0
  716. distllm/models/rope_scaling.py +119 -0
  717. distllm/models/safetensors_index.py +179 -0
  718. distllm/observability/__init__.py +107 -0
  719. distllm/observability/alerting_config.py +881 -0
  720. distllm/observability/capacity_models.py +398 -0
  721. distllm/observability/capacity_planning.py +2870 -0
  722. distllm/observability/exporter.py +228 -0
  723. distllm/observability/exporter_datadog.py +1362 -0
  724. distllm/observability/health_config.py +1282 -0
  725. distllm/observability/incident_response.py +779 -0
  726. distllm/observability/logging.py +211 -0
  727. distllm/observability/logging_config.py +864 -0
  728. distllm/observability/loki_sink.py +178 -0
  729. distllm/observability/metrics.py +111 -0
  730. distllm/observability/metrics_completeness.py +393 -0
  731. distllm/observability/otel_logging.py +290 -0
  732. distllm/observability/self_healing_config.py +1308 -0
  733. distllm/observability/slo_config.py +1520 -0
  734. distllm/observability/spans.py +235 -0
  735. distllm/observability/tracing.py +268 -0
  736. distllm/observability/tracing_config.py +676 -0
  737. distllm/observability/wandb_monitor.py +66 -0
  738. distllm/plugins/__init__.py +14 -0
  739. distllm/plugins/airflow.py +110 -0
  740. distllm/plugins/auth_plugin.py +576 -0
  741. distllm/plugins/builtin.py +376 -0
  742. distllm/plugins/cache_plugin.py +576 -0
  743. distllm/plugins/health_plugin.py +396 -0
  744. distllm/plugins/kubeflow.py +84 -0
  745. distllm/plugins/mlflow_plugin.py +71 -0
  746. distllm/plugins/registry.py +135 -0
  747. distllm/prompts/__init__.py +39 -0
  748. distllm/prompts/analysis.py +103 -0
  749. distllm/prompts/code.py +172 -0
  750. distllm/prompts/creative.py +115 -0
  751. distllm/prompts/education.py +91 -0
  752. distllm/prompts/engine.py +119 -0
  753. distllm/prompts/exchange.py +705 -0
  754. distllm/prompts/language.py +81 -0
  755. distllm/prompts/library.py +1198 -0
  756. distllm/prompts/management.py +35 -0
  757. distllm/prompts/productivity.py +86 -0
  758. distllm/prompts/professional.py +111 -0
  759. distllm/prompts/prompt_def.py +33 -0
  760. distllm/prompts/reasoning.py +108 -0
  761. distllm/prompts/specialized.py +140 -0
  762. distllm/prompts/templates.py +128 -0
  763. distllm/prompts/writing.py +140 -0
  764. distllm/py.typed +0 -0
  765. distllm/sdk/__init__.py +82 -0
  766. distllm/sdk/circuit_breaker.py +139 -0
  767. distllm/sdk/client.py +1191 -0
  768. distllm/sdk/observability.py +42 -0
  769. distllm/sdk/streaming.py +228 -0
  770. distllm/sdk/transport.py +224 -0
  771. distllm/sdk/types.py +288 -0
  772. distllm/security/__init__.py +63 -0
  773. distllm/security/content_moderation/__init__.py +44 -0
  774. distllm/security/content_moderation/base.py +405 -0
  775. distllm/security/content_moderation/jailbreak.py +192 -0
  776. distllm/security/content_moderation/pii.py +262 -0
  777. distllm/security/content_moderation/pipeline.py +272 -0
  778. distllm/security/content_moderation/topics.py +153 -0
  779. distllm/security/content_moderation/toxicity.py +131 -0
  780. distllm/security/e2e.py +437 -0
  781. distllm/security/edge_attestation.py +381 -0
  782. distllm/security/log_redaction.py +244 -0
  783. distllm/security/quantum_safe_tls.py +314 -0
  784. distllm/security/spiffe.py +347 -0
  785. distllm/security/tee.py +461 -0
  786. distllm/security/utils.py +139 -0
  787. distllm/security/watermark.py +779 -0
  788. distllm/terraform/__init__.py +260 -0
  789. distllm/ui/__init__.py +7 -0
  790. distllm/ui/app.py +98 -0
  791. distllm/utils/__init__.py +0 -0
  792. distllm/utils/gbnf_grammar.py +99 -0
  793. distllm/utils/lazy_imports.py +90 -0
  794. distllm/utils/scheduling.py +38 -0
  795. distllm/verification/__init__.py +49 -0
  796. distllm/verification/comparator.py +263 -0
  797. distllm/verification/hash_registry.py +220 -0
  798. distllm/verification/report.py +240 -0
  799. distllm/verification/runner.py +822 -0
  800. distllm/verification/test_verify.py +205 -0
  801. distributed_llm-0.4.1.dist-info/METADATA +315 -0
  802. distributed_llm-0.4.1.dist-info/RECORD +806 -0
  803. distributed_llm-0.4.1.dist-info/WHEEL +5 -0
  804. distributed_llm-0.4.1.dist-info/entry_points.txt +5 -0
  805. distributed_llm-0.4.1.dist-info/licenses/LICENSE +97 -0
  806. distributed_llm-0.4.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,666 @@
1
+ """GPU memory defragmentation for PagedAttention blocks.
2
+
3
+ Compacts fragmented KV cache blocks to free contiguous GPU memory.
4
+ Prevents OOM errors caused by memory fragmentation during long-running
5
+ inference sessions with many concurrent requests.
6
+
7
+ Supports multiple compaction policies and async execution.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import asyncio
13
+ import enum
14
+ import threading
15
+ import time
16
+ from dataclasses import dataclass, field
17
+ from typing import Any
18
+
19
+ import torch
20
+ from loguru import logger
21
+
22
+
23
+ class DefragPolicy(str, enum.Enum):
24
+ """Compaction aggressiveness policy."""
25
+
26
+ LAZY = "lazy"
27
+ """Only compact when fragmentation exceeds 50%. Max 64 blocks per pass."""
28
+
29
+ BALANCED = "balanced"
30
+ """Compact when fragmentation exceeds 30%. Max 128 blocks per pass."""
31
+
32
+ AGGRESSIVE = "aggressive"
33
+ """Compact when fragmentation exceeds 15%. Compact all fragmented blocks."""
34
+
35
+ @property
36
+ def threshold(self) -> float:
37
+ if self == DefragPolicy.LAZY:
38
+ return 0.50
39
+ if self == DefragPolicy.AGGRESSIVE:
40
+ return 0.15
41
+ return 0.30
42
+
43
+ @property
44
+ def max_blocks_per_pass(self) -> int:
45
+ if self == DefragPolicy.LAZY:
46
+ return 64
47
+ if self == DefragPolicy.AGGRESSIVE:
48
+ return 0 # unlimited
49
+ return 128
50
+
51
+
52
+ class TieredCompactionLevel(str, enum.Enum):
53
+ L1_HOT = "l1_hot"
54
+ """Compact within GPU memory. Fast, no offloading."""
55
+
56
+ L2_WARM = "l2_warm"
57
+ """Swap cold sequences to CPU, recompact GPU, remap page table."""
58
+
59
+ L3_COLD = "l3_cold"
60
+ """Offload to NVMe for extreme memory pressure."""
61
+
62
+
63
+ @dataclass
64
+ class DefragConfig:
65
+ """Configuration for the memory defragmenter.
66
+
67
+ Args:
68
+ enabled: Whether defragmentation is active.
69
+ policy: Compaction aggressiveness policy.
70
+ interval_seconds: Seconds between background defrag checks.
71
+ max_blocks_per_pass: Override max blocks to move per pass (0 = unlimited).
72
+ tiered_compaction: Enable tiered (L1/L2/L3) compaction.
73
+ l2_cpu_swap_threshold: Fragmentation threshold to trigger L2 warm swap.
74
+ l3_nvme_swap_threshold: Fragmentation threshold to trigger L3 cold swap.
75
+ cuda_stream_priority: CUDA stream priority for copy operations.
76
+ enable_predictive: Enable predictive (preemptive) defragmentation.
77
+ enable_prometheus: Export Prometheus metrics.
78
+ """
79
+
80
+ enabled: bool = True
81
+ policy: DefragPolicy = DefragPolicy.BALANCED
82
+ interval_seconds: float = 60.0
83
+ max_blocks_per_pass: int = 0
84
+ tiered_compaction: bool = False
85
+ l2_cpu_swap_threshold: float = 0.60
86
+ l3_nvme_swap_threshold: float = 0.80
87
+ cuda_stream_priority: int = -1
88
+ enable_predictive: bool = False
89
+ enable_prometheus: bool = False
90
+
91
+
92
+ @dataclass
93
+ class FragmentInfo:
94
+ """Information about a fragmented memory region."""
95
+
96
+ block_id: int
97
+ device: str
98
+ size_bytes: int
99
+ is_free: bool
100
+ adjacent_free: int
101
+
102
+
103
+ @dataclass
104
+ class DefragResult:
105
+ """Result of a single defragmentation pass."""
106
+
107
+ blocks_moved: int = 0
108
+ bytes_compacted: int = 0
109
+ time_ms: float = 0.0
110
+ fragmentation_before: float = 0.0
111
+ fragmentation_after: float = 0.0
112
+ tier_used: TieredCompactionLevel | None = None
113
+ error: str | None = None
114
+
115
+ def to_dict(self) -> dict:
116
+ result = {
117
+ "blocks_moved": self.blocks_moved,
118
+ "bytes_compacted": self.bytes_compacted,
119
+ "time_ms": self.time_ms,
120
+ "fragmentation_before": round(self.fragmentation_before, 4),
121
+ "fragmentation_after": round(self.fragmentation_after, 4),
122
+ }
123
+ if self.tier_used:
124
+ result["tier_used"] = self.tier_used.value
125
+ if self.error:
126
+ result["error"] = self.error
127
+ return result
128
+
129
+
130
+ class MemoryDefragmenter:
131
+ """Defragments PagedAttention KV cache blocks.
132
+
133
+ Identifies fragmented regions where free blocks are scattered
134
+ between allocated blocks, then compacts by moving allocated
135
+ blocks to fill gaps.
136
+
137
+ Thread-safe: uses a reentrant lock around all mutation operations.
138
+ Async-safe: provides async ``defragment_async()`` for use in event loops.
139
+
140
+ Args:
141
+ config: Defragmentation configuration.
142
+ metrics_collector: Optional Prometheus-style metrics collector.
143
+ """
144
+
145
+ def __init__(
146
+ self,
147
+ config: DefragConfig | None = None,
148
+ metrics_collector: Any = None,
149
+ ):
150
+ self._config = config or DefragConfig()
151
+ self._lock = threading.RLock()
152
+ self._async_lock = asyncio.Lock()
153
+ self._cuda_stream: torch.cuda.Stream | None = None
154
+ self._metrics = metrics_collector
155
+ self._stats = {
156
+ "defrag_count": 0,
157
+ "blocks_moved": 0,
158
+ "bytes_compacted": 0,
159
+ "total_time_ms": 0.0,
160
+ "last_fragmentation_ratio": 0.0,
161
+ "peak_fragmentation_ratio": 0.0,
162
+ "l1_count": 0,
163
+ "l2_count": 0,
164
+ "l3_count": 0,
165
+ }
166
+
167
+ # Predictive state
168
+ self._fragmentation_history: list[float] = []
169
+ self._history_max_len = 100
170
+ # M-10: Block cooldown — prevents moving the same block repeatedly.
171
+ # A block moved within _block_cooldown_seconds is skipped on next pass.
172
+ self._block_cooldown_seconds: float = 30.0
173
+ self._block_last_moved: dict[int, float] = {}
174
+
175
+ # Prometheus-style gauges (lazy init)
176
+ self._metric_frag_ratio: Any = None
177
+ self._metric_blocks_moved: Any = None
178
+ self._metric_duration: Any = None
179
+
180
+ # ── Configuration ──
181
+
182
+ @property
183
+ def config(self) -> DefragConfig:
184
+ return self._config
185
+
186
+ def reconfigure(self, config: DefragConfig) -> None:
187
+ with self._lock:
188
+ self._config = config
189
+
190
+ # ── Fragmentation Analysis ──
191
+
192
+ def analyze_fragmentation(self, blocks: list[Any]) -> list[FragmentInfo]:
193
+ """Analyze fragmentation in a block pool.
194
+
195
+ Args:
196
+ blocks: List of KVCacheBlock objects from PagedAttentionManager.
197
+
198
+ Returns:
199
+ List of FragmentInfo for each block.
200
+ """
201
+ fragments = []
202
+ for i, block in enumerate(blocks):
203
+ adjacent_free = 0
204
+ if i > 0 and not blocks[i - 1].is_allocated:
205
+ adjacent_free += 1
206
+ if i < len(blocks) - 1 and not blocks[i + 1].is_allocated:
207
+ adjacent_free += 1
208
+
209
+ size_bytes = 0
210
+ if block.is_allocated and block.key_cache is not None:
211
+ size_bytes = (
212
+ block.key_cache.element_size() * block.key_cache.numel()
213
+ + block.value_cache.element_size() * block.value_cache.numel()
214
+ )
215
+
216
+ fragments.append(
217
+ FragmentInfo(
218
+ block_id=block.block_id,
219
+ device=str(block.key_cache.device) if block.key_cache is not None else "cpu",
220
+ size_bytes=size_bytes,
221
+ is_free=not block.is_allocated,
222
+ adjacent_free=adjacent_free,
223
+ )
224
+ )
225
+
226
+ return fragments
227
+
228
+ def compute_compaction_plan(self, blocks: list[Any]) -> list[tuple[int, int, int]]:
229
+ """Compute which blocks need to move to eliminate fragmentation.
230
+
231
+ Returns list of (source_index, dest_index, ref_count) tuples.
232
+ Respects copy-on-write: blocks with ref_count > 1 are not moved.
233
+ """
234
+ moves = []
235
+ free_slots = []
236
+ allocated = []
237
+
238
+ for i, block in enumerate(blocks):
239
+ if not block.is_allocated:
240
+ free_slots.append(i)
241
+ elif free_slots:
242
+ if block.ref_count <= 1:
243
+ allocated.append(i)
244
+
245
+ max_blocks = self._config.max_blocks_per_pass
246
+ if max_blocks > 0 and len(allocated) > max_blocks:
247
+ allocated = allocated[:max_blocks]
248
+ free_slots = free_slots[:max_blocks]
249
+
250
+ for alloc_idx, free_idx in zip(reversed(allocated), free_slots):
251
+ if alloc_idx > free_idx:
252
+ moves.append((alloc_idx, free_idx, blocks[alloc_idx].ref_count))
253
+
254
+ return moves
255
+
256
+ @staticmethod
257
+ def compute_fragmentation_ratio(blocks: list[Any]) -> float:
258
+ """Compute the fragmentation ratio.
259
+
260
+ Ratio = fragmented free blocks / total blocks.
261
+ A free block is "fragmented" if it has at least one allocated neighbor
262
+ (i.e. it's scattered among allocated blocks, not contiguous).
263
+ """
264
+ total = len(blocks)
265
+ if total == 0:
266
+ return 0.0
267
+
268
+ fragmented = 0
269
+ for i, block in enumerate(blocks):
270
+ if not block.is_allocated:
271
+ has_alloc_neighbor = False
272
+ if i > 0 and blocks[i - 1].is_allocated:
273
+ has_alloc_neighbor = True
274
+ if i < len(blocks) - 1 and blocks[i + 1].is_allocated:
275
+ has_alloc_neighbor = True
276
+ if has_alloc_neighbor:
277
+ fragmented += 1
278
+
279
+ return fragmented / total
280
+
281
+ _compute_fragmentation_ratio = compute_fragmentation_ratio
282
+
283
+ # ── Defragmentation Trigger ──
284
+
285
+ def should_defragment(self, blocks: list[Any]) -> bool:
286
+ """Check if defragmentation is needed based on policy threshold."""
287
+ ratio = self._compute_fragmentation_ratio(blocks)
288
+ return ratio >= self._config.policy.threshold
289
+
290
+ # ── Synchronous Defragmentation ──
291
+
292
+ def defragment(self, paged_attention_mgr: Any) -> DefragResult:
293
+ """Defragment the PagedAttention block pool.
294
+
295
+ Thread-safe: acquires internal lock around all mutation.
296
+ Also acquires the mgr's lock to prevent concurrent free_sequence()
297
+ or allocate_sequence() calls from racing with block moves.
298
+
299
+ Args:
300
+ paged_attention_mgr: A PagedAttentionManager (or any object
301
+ conforming to the Defragmentable protocol).
302
+
303
+ Returns:
304
+ DefragResult with statistics.
305
+ """
306
+ # Acquire both locks (self first, then mgr) to prevent deadlock
307
+ with self._lock:
308
+ mgr_lock = getattr(paged_attention_mgr, '_lock', None)
309
+ if mgr_lock is not None:
310
+ mgr_lock.acquire()
311
+ try:
312
+ return self._defragment_impl(paged_attention_mgr)
313
+ finally:
314
+ if mgr_lock is not None:
315
+ mgr_lock.release()
316
+
317
+ def _defragment_impl_locked(
318
+ self,
319
+ mgr: Any,
320
+ tier: TieredCompactionLevel | None = None,
321
+ ) -> DefragResult:
322
+ """Run ``_defragment_impl`` under both ``_lock`` and ``mgr._lock``.
323
+
324
+ Mirrors the lock acquisition in the synchronous ``defragment()``
325
+ (self first, then mgr) so a defrag task running in an executor
326
+ thread cannot race with a concurrent synchronous defrag or with
327
+ ``allocate_sequence()``/``free_sequence()`` on the manager.
328
+ Intended for the executor-worker path used by the async variants.
329
+ """
330
+ with self._lock:
331
+ mgr_lock = getattr(mgr, '_lock', None)
332
+ if mgr_lock is not None:
333
+ mgr_lock.acquire()
334
+ try:
335
+ return self._defragment_impl(mgr, tier)
336
+ finally:
337
+ if mgr_lock is not None:
338
+ mgr_lock.release()
339
+
340
+ @staticmethod
341
+ def _resolve_blocks(mgr: Any) -> tuple[list[Any], dict[str, Any]]:
342
+ """Get blocks and seq_blocks from mgr via protocol or fallback."""
343
+ try:
344
+ blocks = mgr.get_blocks()
345
+ if not isinstance(blocks, list):
346
+ raise TypeError
347
+ except (AttributeError, TypeError):
348
+ blocks = mgr._blocks
349
+ try:
350
+ seq_blocks = mgr.get_seq_blocks()
351
+ if not isinstance(seq_blocks, dict):
352
+ raise TypeError
353
+ except (AttributeError, TypeError):
354
+ seq_blocks = mgr._seq_blocks
355
+ return blocks, seq_blocks
356
+
357
+ @staticmethod
358
+ def _set_free_blocks(mgr: Any, free_ids: list[int]) -> None:
359
+ try:
360
+ mgr.set_free_blocks(free_ids)
361
+ except (AttributeError, TypeError):
362
+ mgr._free_blocks = free_ids
363
+
364
+ def _defragment_impl(
365
+ self,
366
+ mgr: Any,
367
+ tier: TieredCompactionLevel | None = None,
368
+ ) -> DefragResult:
369
+ """Internal defrag implementation (caller must hold _lock)."""
370
+ start = time.monotonic()
371
+ result = DefragResult()
372
+
373
+ blocks, seq_blocks = self._resolve_blocks(mgr)
374
+ if not blocks:
375
+ return result
376
+
377
+ result.fragmentation_before = self._compute_fragmentation_ratio(blocks)
378
+
379
+ self._fragmentation_history.append(result.fragmentation_before)
380
+ if len(self._fragmentation_history) > self._history_max_len:
381
+ self._fragmentation_history.pop(0)
382
+
383
+ moves = self.compute_compaction_plan(blocks)
384
+ if not moves:
385
+ result.fragmentation_after = result.fragmentation_before
386
+ return result
387
+
388
+ # M-10: Filter out blocks moved recently (cooldown).
389
+ # Prevents thrashing where the same block is moved on every pass.
390
+ now = time.monotonic()
391
+ filtered_moves = []
392
+ for src_idx, dst_idx, ref_count in moves:
393
+ src_block = blocks[src_idx]
394
+ last_moved = self._block_last_moved.get(src_block.block_id, 0)
395
+ if now - last_moved > self._block_cooldown_seconds:
396
+ filtered_moves.append((src_idx, dst_idx, ref_count))
397
+ moves = filtered_moves
398
+ if not moves:
399
+ result.fragmentation_after = result.fragmentation_before
400
+ return result
401
+
402
+ # L2/L3 tier: swap cold sequences to CPU/NVMe before compacting
403
+ if tier in (TieredCompactionLevel.L2_WARM, TieredCompactionLevel.L3_COLD):
404
+ self._offload_cold_sequences(mgr, tier)
405
+
406
+ # Initialize CUDA stream if needed
407
+ stream = self._get_cuda_stream()
408
+
409
+ bytes_moved = 0
410
+ for src_idx, dst_idx, ref_count in moves:
411
+ src_block = blocks[src_idx]
412
+ dst_block = blocks[dst_idx]
413
+
414
+ if src_block.key_cache is None:
415
+ continue
416
+
417
+ # Allocate destination block if it hasn't been allocated yet
418
+ if dst_block.key_cache is None:
419
+ dst_block.allocate(
420
+ num_heads=src_block.key_cache.shape[1],
421
+ head_dim=src_block.key_cache.shape[-1],
422
+ device=str(src_block.key_cache.device),
423
+ )
424
+
425
+ if stream is not None:
426
+ with torch.cuda.stream(stream):
427
+ dst_block.key_cache.copy_(src_block.key_cache)
428
+ dst_block.value_cache.copy_(src_block.value_cache)
429
+ else:
430
+ dst_block.key_cache.copy_(src_block.key_cache)
431
+ dst_block.value_cache.copy_(src_block.value_cache)
432
+
433
+ dst_block.num_tokens = src_block.num_tokens
434
+ dst_block.is_allocated = True
435
+ dst_block.ref_count = ref_count
436
+
437
+ src_block.key_cache = None
438
+ src_block.value_cache = None
439
+ src_block.is_allocated = False
440
+ src_block.num_tokens = 0
441
+ src_block.ref_count = 0
442
+
443
+ bytes_moved += (
444
+ dst_block.key_cache.element_size() * dst_block.key_cache.numel()
445
+ + dst_block.value_cache.element_size() * dst_block.value_cache.numel()
446
+ )
447
+
448
+ # Synchronize CUDA stream before updating bookkeeping
449
+ if stream is not None:
450
+ stream.synchronize()
451
+
452
+ # Update sequence block references using block_ids (not list indices).
453
+ # This is robust even if block_id != list index in future implementations.
454
+ for src_idx, dst_idx, _ in moves:
455
+ src_block_id = blocks[src_idx].block_id
456
+ dst_block_id = blocks[dst_idx].block_id
457
+ for seq in seq_blocks.values():
458
+ for i, bid in enumerate(seq.block_ids):
459
+ if bid == src_block_id:
460
+ seq.block_ids[i] = dst_block_id
461
+
462
+ # Rebuild free list
463
+ self._set_free_blocks(mgr, [b.block_id for b in blocks if not b.is_allocated])
464
+
465
+ # M-10: Record when each block was last moved (for cooldown)
466
+ now_cd = time.monotonic()
467
+ for src_idx, _dst_idx, _ref_count in moves:
468
+ src_block = blocks[src_idx]
469
+ self._block_last_moved[src_block.block_id] = now_cd
470
+
471
+ result.fragmentation_after = self._compute_fragmentation_ratio(blocks)
472
+ result.blocks_moved = len(moves)
473
+ result.bytes_compacted = bytes_moved
474
+ result.time_ms = (time.monotonic() - start) * 1000
475
+
476
+ # Only reclaim GPU memory when blocks were actually moved.
477
+ # torch.cuda.empty_cache() causes 10-100ms stalls and should not
478
+ # be called on every defrag pass. See backends/paged_attention.py
479
+ # line 471 for the same rationale.
480
+ if bytes_moved > 0:
481
+ try:
482
+ torch.cuda.empty_cache()
483
+ except Exception:
484
+ pass
485
+
486
+ result.tier_used = tier or TieredCompactionLevel.L1_HOT
487
+
488
+ # Update stats
489
+ self._stats["defrag_count"] += 1
490
+ self._stats["blocks_moved"] += result.blocks_moved
491
+ self._stats["bytes_compacted"] += result.bytes_compacted
492
+ self._stats["total_time_ms"] += result.time_ms
493
+ self._stats["last_fragmentation_ratio"] = result.fragmentation_after
494
+ self._stats["peak_fragmentation_ratio"] = max(
495
+ self._stats["peak_fragmentation_ratio"],
496
+ result.fragmentation_before,
497
+ )
498
+
499
+ tier_key = f"{tier or TieredCompactionLevel.L1_HOT}_count".replace("-", "_")
500
+ ts = tier or TieredCompactionLevel.L1_HOT
501
+ if ts == TieredCompactionLevel.L1_HOT:
502
+ self._stats["l1_count"] += 1
503
+ elif ts == TieredCompactionLevel.L2_WARM:
504
+ self._stats["l2_count"] += 1
505
+ elif ts == TieredCompactionLevel.L3_COLD:
506
+ self._stats["l3_count"] += 1
507
+
508
+ self._emit_prometheus(result)
509
+
510
+ logger.info(
511
+ f"Defrag [{tier or TieredCompactionLevel.L1_HOT.value}]: "
512
+ f"moved {result.blocks_moved} blocks, "
513
+ f"{result.bytes_compacted / 1024 / 1024:.1f}MB compacted, "
514
+ f"frag {result.fragmentation_before:.1%} -> {result.fragmentation_after:.1%}, "
515
+ f"{result.time_ms:.1f}ms"
516
+ )
517
+
518
+ return result
519
+
520
+ def _offload_cold_sequences(self, mgr: Any, tier: TieredCompactionLevel) -> int:
521
+ """Offload cold sequences to CPU (L2) or NVMe (L3).
522
+
523
+ Returns number of sequences offloaded.
524
+ """
525
+ offloaded = 0
526
+ _, seq_blocks = self._resolve_blocks(mgr)
527
+ seq_ids = list(seq_blocks.keys())
528
+ for seq_id in seq_ids:
529
+ if tier == TieredCompactionLevel.L2_WARM:
530
+ offloaded += mgr.swap_blocks_to_cpu(seq_id)
531
+ elif tier == TieredCompactionLevel.L3_COLD:
532
+ logger.warning(
533
+ "L3 NVMe offload not yet implemented; "
534
+ "falling back to CPU swap for seq_id={}",
535
+ seq_id,
536
+ )
537
+ try:
538
+ mgr.swap_blocks_to_cpu(seq_id)
539
+ offloaded += 1
540
+ except Exception:
541
+ pass
542
+ return offloaded
543
+
544
+ def _get_cuda_stream(self) -> torch.cuda.Stream | None:
545
+ """Get or create a CUDA stream for async copies."""
546
+ if not torch.cuda.is_available():
547
+ return None
548
+ if self._cuda_stream is None:
549
+ self._cuda_stream = torch.cuda.Stream(
550
+ priority=self._config.cuda_stream_priority
551
+ )
552
+ return self._cuda_stream
553
+
554
+ # ── Async Defragmentation ──
555
+
556
+ async def defragment_async(self, paged_attention_mgr: Any) -> DefragResult:
557
+ """Async variant that yields the event loop during compaction.
558
+
559
+ Thread-safe: uses asyncio.Lock for cooperative concurrency and
560
+ re-acquires the same threading locks as the synchronous path
561
+ inside the executor worker (self first, then the manager's lock).
562
+ """
563
+ async with self._async_lock:
564
+ loop = asyncio.get_running_loop()
565
+ return await loop.run_in_executor(
566
+ None, self._defragment_impl_locked, paged_attention_mgr, None,
567
+ )
568
+
569
+ async def defragment_with_tier_async(
570
+ self,
571
+ paged_attention_mgr: Any,
572
+ tier: TieredCompactionLevel,
573
+ ) -> DefragResult:
574
+ """Async defragmentation with explicit tier selection."""
575
+ async with self._async_lock:
576
+ loop = asyncio.get_running_loop()
577
+ return await loop.run_in_executor(
578
+ None, self._defragment_impl_locked, paged_attention_mgr, tier,
579
+ )
580
+
581
+ # ── Predictive Defragmentation ──
582
+
583
+ def predict_fragmentation(self, steps_ahead: int = 5) -> float:
584
+ """Predict future fragmentation using exponential smoothing.
585
+
586
+ Args:
587
+ steps_ahead: Number of inference steps to forecast.
588
+
589
+ Returns:
590
+ Predicted fragmentation ratio (0.0-1.0).
591
+ """
592
+ history = self._fragmentation_history
593
+ if len(history) < 3:
594
+ return history[-1] if history else 0.0
595
+
596
+ alpha = 0.3
597
+ smoothed = history[0]
598
+ for val in history[1:]:
599
+ smoothed = alpha * val + (1 - alpha) * smoothed
600
+
601
+ trend = (history[-1] - history[0]) / max(len(history) - 1, 1)
602
+ predicted = smoothed + trend * steps_ahead
603
+ return max(0.0, min(1.0, predicted))
604
+
605
+ # ── Prometheus Metrics ──
606
+
607
+ def _ensure_prometheus(self) -> None:
608
+ if not self._config.enable_prometheus:
609
+ return
610
+ if self._metric_frag_ratio is not None:
611
+ return
612
+ try:
613
+ from prometheus_client import Gauge, Histogram
614
+
615
+ self._metric_frag_ratio = Gauge(
616
+ "kv_cache_fragmentation_ratio",
617
+ "Current KV cache fragmentation ratio (0-1)",
618
+ )
619
+ self._metric_blocks_moved = Gauge(
620
+ "defrag_blocks_moved_total",
621
+ "Total blocks moved by defragmentation",
622
+ )
623
+ self._metric_duration = Histogram(
624
+ "defrag_duration_ms",
625
+ "Defragmentation pass duration in ms",
626
+ buckets=[10, 50, 100, 500, 1000, 5000],
627
+ )
628
+ except ImportError:
629
+ pass
630
+
631
+ def _emit_prometheus(self, result: DefragResult) -> None:
632
+ if not self._config.enable_prometheus:
633
+ return
634
+ self._ensure_prometheus()
635
+ try:
636
+ if self._metric_frag_ratio is not None:
637
+ self._metric_frag_ratio.set(result.fragmentation_after)
638
+ if self._metric_blocks_moved is not None:
639
+ self._metric_blocks_moved.inc(result.blocks_moved)
640
+ if self._metric_duration is not None:
641
+ self._metric_duration.observe(result.time_ms)
642
+ except Exception:
643
+ pass
644
+
645
+ # ── Properties ──
646
+
647
+ @property
648
+ def stats(self) -> dict:
649
+ with self._lock:
650
+ return dict(self._stats)
651
+
652
+ @property
653
+ def fragmentation_history(self) -> list[float]:
654
+ return list(self._fragmentation_history)
655
+
656
+ @property
657
+ def needs_tier_upgrade(self) -> bool:
658
+ """Check if fragmentation warrants an upgrade to L2 or L3."""
659
+ if not self._fragmentation_history:
660
+ return False
661
+ current = self._fragmentation_history[-1]
662
+ return current > self._config.l2_cpu_swap_threshold
663
+
664
+ @property
665
+ def defrag_count(self) -> int:
666
+ return self._stats["defrag_count"]