git-diff.patch 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. diff --git a/.env.example b/.env.example
  2. index c777fb4..4c30834 100644
  3. --- a/.env.example
  4. +++ b/.env.example
  5. @@ -84,13 +84,9 @@ DSV41_STATS_SECONDS=60
  6. # single prompts to 208k and 4 concurrent 46k prompts are verified; a 256k prompt
  7. # missed the 1.5 GB guard by 20 MB. Keep long prompts guarded (scripts/verify/memguard.py).
  8. CONTEXT_LENGTH=262144
  9. +# Lowering the fraction does not free RAM; it only starves the KV pool.
  10. +# 0.95 is the working value.
  11. MEM_FRACTION_STATIC=0.95
  12. -# Rank 0 pays ~1.3 GiB the workers do not (HTTP server + tokenizer +
  13. -# detokenizer) and also serves the checkpoint over NFS. The knob exists to tune
  14. -# it separately, but note LOWERING it does not give the head headroom: weights
  15. -# cost the same either way, so a smaller fraction only starves the KV pool.
  16. -# Measured on this box: 0.9436 is where KV goes negative, and 0.945 still leaves
  17. -# only 0.12 GB -- less than the 0.34 GB DSV4 SWA cap. 0.95 is the working value.
  18. HEAD_MEM_FRACTION_STATIC=0.95
  19. MAX_RUNNING_REQUESTS=4
  20. # 1024: with the prefill empty_cache hook the per-chunk indexer buffers ([chunk, prefix]
  21. @@ -140,6 +136,20 @@ EXTRA_SGLANG_ARGS="--fp8-gemm-backend flashinfer_cutlass --watchdog-timeout 1800
  22. # SM120 kernel at decode M); cudnn is the alternative; cutlass restores SGLang's
  23. # default, which measured no faster than Triton (both ~50 ms of a decode step).
  24. DSV41_MXFP8_BACKEND=b12x
  25. +
  26. +# Present in the image, off on TP3. The autotune pass is a target-verify
  27. +# forward and rank 2 is the padded shard; wo_a DROP plus the prefetch/remap
  28. +# hooks inside that forward unloaded spark3. Enable one at a time after a
  29. +# clean boot.
  30. +DSV41_WO_A_W8=0
  31. +DSV41_WO_A_W8_MID=0
  32. +DSV41_WO_A_W8_DROP=0
  33. +DSV41_DRAFT_HEAD_FP8=0
  34. +DSV41_VERIFY_CAP=0
  35. +DSV41_DRAFT_TAU=1
  36. +DSV41_BLOCK_VERIFY=0
  37. +DSV41_ENGRAM_PREFETCH=0
  38. +DSV41_FOLDED_FENCE=0
  39. # FlashInfer's fused MoE finalize sums the top-k expert outputs with atomic bf16
  40. # adds. The autotuner picks it for the 32-token bucket (17-32 token prefills,
  41. # decode at concurrency 3-4), which made greedy outputs nondeterministic by up to
  42. diff --git a/Dockerfile b/Dockerfile
  43. index 8beaba4..96bd0d5 100644
  44. --- a/Dockerfile
  45. +++ b/Dockerfile
  46. @@ -12,7 +12,11 @@ COPY tests /opt/dsv41/tests
  47. COPY benchmarks /opt/dsv41/benchmarks
  48. RUN PYTHONPATH=/opt/dsv41/adapter python3 /opt/dsv41/tests/test_thinking_alias.py \
  49. && PYTHONPATH=/opt/dsv41/adapter python3 /opt/dsv41/tests/test_max_new_tokens.py \
  50. - && PYTHONPATH=/opt/dsv41/adapter python3 /opt/dsv41/tests/test_loop_abort.py
  51. + && PYTHONPATH=/opt/dsv41/adapter python3 /opt/dsv41/tests/test_loop_abort.py \
  52. + && PYTHONPATH=/opt/dsv41/adapter python3 /opt/dsv41/tests/test_wo_a_w8.py \
  53. + && PYTHONPATH=/opt/dsv41/adapter python3 /opt/dsv41/tests/test_draft_head_fp8.py \
  54. + && PYTHONPATH=/opt/dsv41/adapter python3 /opt/dsv41/tests/test_draft_tau.py \
  55. + && PYTHONPATH=/opt/dsv41/adapter python3 /opt/dsv41/tests/test_folded_fence.py
  56. ENV PYTHONPATH=/opt/dsv41/adapter \
  57. MODEL_PATH=/models/DeepSeek-V4.1-Flash \
  58. STATE_PATH=/state OFFLOAD_MODE=nvme DSV41_CACHE_GIB=16
  59. diff --git a/adapter/sitecustomize.py b/adapter/sitecustomize.py
  60. index 2d717e2..b1d85bb 100644
  61. --- a/adapter/sitecustomize.py
  62. +++ b/adapter/sitecustomize.py
  63. @@ -16,6 +16,10 @@ class EngramLoader(importlib.abc.Loader):
  64. if module.__name__ == 'sglang.srt.layers.engram':
  65. from engram_backend import install
  66. install(module)
  67. + # After engram_backend: row lookups on a side stream after the hasher.
  68. + # Gated on DSV41_ENGRAM_PREFETCH.
  69. + from engram_prefetch import install as install_engram_prefetch
  70. + install_engram_prefetch(module)
  71. elif module.__name__ == 'sglang.srt.model_loader.utils':
  72. if os.environ.get('DSV41_SERIAL_WEIGHT_LOAD', '0') == '1':
  73. # On GB10 the CPU shard pages and CUDA allocations share RAM.
  74. @@ -46,6 +50,52 @@ class EngramLoader(importlib.abc.Loader):
  75. elif module.__name__ == 'sglang.srt.managers.schedule_batch':
  76. from loop_abort import install as install_loop_abort
  77. install_loop_abort(module)
  78. + elif module.__name__ == 'sglang.srt.models.deepseek_v4':
  79. + if os.environ.get('DSV41_WO_A_W8', '0').strip() not in ('0', 'off', 'false', ''):
  80. + from wo_a_w8 import install_model as install_wo_a_w8
  81. + install_wo_a_w8(module)
  82. + if os.environ.get('DSV41_VERIFY_CAP', '').strip() not in ('', '0', 'off'):
  83. + from verify_cap import install_model as install_verify_cap_model
  84. + install_verify_cap_model(module)
  85. + elif module.__name__ == 'sglang.srt.models.deepseek_v4_dspark':
  86. + # conf:T needs the draft confidence head, which the engine only builds
  87. + # for ragged verify. install_dspark builds it in static mode too.
  88. + if os.environ.get('DSV41_VERIFY_CAP', '').strip().startswith('conf:'):
  89. + from verify_cap import install_dspark as install_verify_cap_dspark
  90. + install_verify_cap_dspark(module)
  91. + if os.environ.get('DSV41_WO_A_W8', '0').strip() not in ('0', 'off', 'false', ''):
  92. + from wo_a_w8 import install_dspark as install_wo_a_w8_dspark
  93. + install_wo_a_w8_dspark(module)
  94. + if os.environ.get('DSV41_DRAFT_HEAD_FP8', '0').strip() not in ('0', 'off', 'false', ''):
  95. + from draft_head_fp8 import install as install_draft_head_fp8
  96. + install_draft_head_fp8(module)
  97. + elif module.__name__ == 'sglang.srt.speculative.dspark_components.dspark_draft_sampler':
  98. + if os.environ.get('DSV41_DRAFT_TAU', '1').strip() not in ('', '1', '1.0'):
  99. + from draft_tau import install as install_draft_tau
  100. + install_draft_tau(module)
  101. + elif module.__name__ == 'sglang.kernels.ops.speculative.dspark.dspark_accept':
  102. + if os.environ.get('DSV41_BLOCK_VERIFY', '0').strip() not in ('0', 'off', 'false', ''):
  103. + from block_verify import install as install_block_verify
  104. + install_block_verify(module)
  105. + elif module.__name__ == 'sglang.srt.speculative.dspark_components.dspark_verify':
  106. + if os.environ.get('DSV41_FOLDED_FENCE', '0').strip() not in ('0', 'off', 'false', ''):
  107. + from folded_result_fence import install as install_folded_fence
  108. + install_folded_fence(module)
  109. + if os.environ.get('DSV41_VERIFY_CAP', '').strip() not in ('', '0', 'off'):
  110. + from verify_cap import install_verify as install_verify_cap_verify
  111. + install_verify_cap_verify(module)
  112. + elif module.__name__ == 'sglang.kernels.ops.moe.moe_fused_gate':
  113. + if os.environ.get('DSV41_VERIFY_CAP', '').strip() not in ('', '0', 'off'):
  114. + from verify_cap import install_gate as install_verify_cap_gate
  115. + install_verify_cap_gate(module)
  116. + elif module.__name__ == 'sglang.srt.speculative.dspark_components.dspark_draft':
  117. + if os.environ.get('DSV41_VERIFY_CAP', '').strip() not in ('', '0', 'off'):
  118. + from verify_cap import install_draft as install_verify_cap_draft
  119. + install_verify_cap_draft(module)
  120. + elif module.__name__ == 'sglang.srt.speculative.dspark_components.dspark_planner':
  121. + if os.environ.get('DSV41_VERIFY_CAP', '').strip() not in ('', '0', 'off'):
  122. + from verify_cap import install_planner as install_verify_cap_planner
  123. + install_verify_cap_planner(module)
  124. else:
  125. # V4.1 ratio-1/2 indexers always call the FP4 DeepGEMM kernel.
  126. # SM120 needs its split-128 planner even when the legacy FP8
  127. @@ -73,6 +123,14 @@ class EngramFinder(importlib.abc.MetaPathFinder):
  128. 'sglang.srt.entrypoints.openai.encoding_dsv41',
  129. 'sglang.srt.entrypoints.openai.serving_chat',
  130. 'sglang.srt.managers.schedule_batch',
  131. + 'sglang.srt.models.deepseek_v4',
  132. + 'sglang.srt.models.deepseek_v4_dspark',
  133. + 'sglang.srt.speculative.dspark_components.dspark_draft_sampler',
  134. + 'sglang.kernels.ops.speculative.dspark.dspark_accept',
  135. + 'sglang.srt.speculative.dspark_components.dspark_verify',
  136. + 'sglang.kernels.ops.moe.moe_fused_gate',
  137. + 'sglang.srt.speculative.dspark_components.dspark_draft',
  138. + 'sglang.srt.speculative.dspark_components.dspark_planner',
  139. 'sglang.srt.layers.attention.dsv4.metadata'):
  140. return None
  141. spec = importlib.machinery.PathFinder.find_spec(fullname, path)
  142. diff --git a/start.sh b/start.sh
  143. index dc7a79d..46bdb67 100755
  144. --- a/start.sh
  145. +++ b/start.sh
  146. @@ -135,6 +135,32 @@ CHUNKED_PREFILL_SIZE="${CHUNKED_PREFILL_SIZE:-2048}"
  147. MAX_TOTAL_TOKENS="${MAX_TOTAL_TOKENS:-320000}"
  148. SPEC_ALGO="${SPEC_ALGO:-DSPARK}"
  149. DSPARK_BLOCK_SIZE="${DSPARK_BLOCK_SIZE:-3}"
  150. +# The TP4 decode adapters are loaded in the image but off. Turning them on
  151. +# made spark3 drop its weights at FlashInfer autotune: that pass is a
  152. +# target-verify forward, rank 2 is the padded shard, and wo_a DROP has already
  153. +# replaced those parameters with a 1-element stand-in while Engram prefetch
  154. +# and the verify remap run inside the profiled forward.
  155. +if [[ "$TP_SIZE" == "3" ]]; then
  156. + DSV41_WO_A_W8="${DSV41_WO_A_W8:-0}"
  157. + DSV41_WO_A_W8_MID="${DSV41_WO_A_W8_MID:-0}"
  158. + DSV41_WO_A_W8_DROP="${DSV41_WO_A_W8_DROP:-0}"
  159. + DSV41_DRAFT_HEAD_FP8="${DSV41_DRAFT_HEAD_FP8:-0}"
  160. + DSV41_VERIFY_CAP="${DSV41_VERIFY_CAP:-0}"
  161. + DSV41_DRAFT_TAU="${DSV41_DRAFT_TAU:-1}"
  162. + DSV41_BLOCK_VERIFY="${DSV41_BLOCK_VERIFY:-0}"
  163. + DSV41_ENGRAM_PREFETCH="${DSV41_ENGRAM_PREFETCH:-0}"
  164. + DSV41_FOLDED_FENCE="${DSV41_FOLDED_FENCE:-0}"
  165. +else
  166. + DSV41_WO_A_W8="${DSV41_WO_A_W8:-0}"
  167. + DSV41_WO_A_W8_MID="${DSV41_WO_A_W8_MID:-0}"
  168. + DSV41_WO_A_W8_DROP="${DSV41_WO_A_W8_DROP:-0}"
  169. + DSV41_DRAFT_HEAD_FP8="${DSV41_DRAFT_HEAD_FP8:-0}"
  170. + DSV41_VERIFY_CAP="${DSV41_VERIFY_CAP:-0}"
  171. + DSV41_DRAFT_TAU="${DSV41_DRAFT_TAU:-1}"
  172. + DSV41_BLOCK_VERIFY="${DSV41_BLOCK_VERIFY:-0}"
  173. + DSV41_ENGRAM_PREFETCH="${DSV41_ENGRAM_PREFETCH:-0}"
  174. + DSV41_FOLDED_FENCE="${DSV41_FOLDED_FENCE:-0}"
  175. +fi
  176. SERVED_MODEL_NAME="${SERVED_MODEL_NAME:-deepseek-v4.1-flash}"
  177. SKIP_PREPARE="${SKIP_PREPARE:-1}"
  178. SKIP_VERIFY="${SKIP_VERIFY:-1}"
  179. @@ -288,6 +314,15 @@ docker_common_args() {
  180. -e "CUDA_GRAPH_MAX_BS_DECODE=$MAX_RUNNING_REQUESTS"
  181. -e "SPEC_ALGO=$SPEC_ALGO"
  182. -e "DSPARK_BLOCK_SIZE=$DSPARK_BLOCK_SIZE"
  183. + -e "DSV41_WO_A_W8=$DSV41_WO_A_W8"
  184. + -e "DSV41_WO_A_W8_MID=$DSV41_WO_A_W8_MID"
  185. + -e "DSV41_WO_A_W8_DROP=$DSV41_WO_A_W8_DROP"
  186. + -e "DSV41_DRAFT_HEAD_FP8=$DSV41_DRAFT_HEAD_FP8"
  187. + -e "DSV41_VERIFY_CAP=$DSV41_VERIFY_CAP"
  188. + -e "DSV41_DRAFT_TAU=$DSV41_DRAFT_TAU"
  189. + -e "DSV41_BLOCK_VERIFY=$DSV41_BLOCK_VERIFY"
  190. + -e "DSV41_ENGRAM_PREFETCH=$DSV41_ENGRAM_PREFETCH"
  191. + -e "DSV41_FOLDED_FENCE=$DSV41_FOLDED_FENCE"
  192. -e "SERVED_MODEL_NAME=$SERVED_MODEL_NAME"
  193. -e "SKIP_PREPARE=$SKIP_PREPARE"
  194. -e "SKIP_VERIFY=$SKIP_VERIFY"
  195. @@ -393,6 +428,15 @@ worker_env_lines() {
  196. -e "CUDA_GRAPH_MAX_BS_DECODE=$MAX_RUNNING_REQUESTS"
  197. -e "SPEC_ALGO=$SPEC_ALGO"
  198. -e "DSPARK_BLOCK_SIZE=$DSPARK_BLOCK_SIZE"
  199. + -e "DSV41_WO_A_W8=$DSV41_WO_A_W8"
  200. + -e "DSV41_WO_A_W8_MID=$DSV41_WO_A_W8_MID"
  201. + -e "DSV41_WO_A_W8_DROP=$DSV41_WO_A_W8_DROP"
  202. + -e "DSV41_DRAFT_HEAD_FP8=$DSV41_DRAFT_HEAD_FP8"
  203. + -e "DSV41_VERIFY_CAP=$DSV41_VERIFY_CAP"
  204. + -e "DSV41_DRAFT_TAU=$DSV41_DRAFT_TAU"
  205. + -e "DSV41_BLOCK_VERIFY=$DSV41_BLOCK_VERIFY"
  206. + -e "DSV41_ENGRAM_PREFETCH=$DSV41_ENGRAM_PREFETCH"
  207. + -e "DSV41_FOLDED_FENCE=$DSV41_FOLDED_FENCE"
  208. -e "SERVED_MODEL_NAME=$SERVED_MODEL_NAME"
  209. -e "SKIP_PREPARE=1"
  210. -e "SKIP_VERIFY=1"
  211. @@ -475,6 +519,7 @@ cmd_doctor() {
  212. echo "model: $MODEL_DIR"
  213. echo "parallel: nnodes=$NNODES TP=$TP_SIZE EP=$EP_SIZE ctx=$CONTEXT_LENGTH util=$MEM_FRACTION_STATIC (head $HEAD_MEM_FRACTION_STATIC)"
  214. echo "offload: $OFFLOAD_MODE cache=${DSV41_CACHE_GIB}GiB spec=$SPEC_ALGO-$DSPARK_BLOCK_SIZE port=$PORT"
  215. + echo "decode: wo_a_w8=$DSV41_WO_A_W8 mid=$DSV41_WO_A_W8_MID drop=$DSV41_WO_A_W8_DROP draft_head_fp8=$DSV41_DRAFT_HEAD_FP8 verify_cap=$DSV41_VERIFY_CAP draft_tau=$DSV41_DRAFT_TAU block_verify=$DSV41_BLOCK_VERIFY engram_prefetch=$DSV41_ENGRAM_PREFETCH folded_fence=$DSV41_FOLDED_FENCE"
  216. echo
  217. local ok=0
  218. command -v docker >/dev/null || { warn "docker missing on head"; ok=1; }