浏览代码

plan: SGLang DS4.1 4x lane queued (aidenle recipe, production since 09-17 on their fleet); 8x DS4.1 in-memory engram boot in progress

Alexander Korolev 1 月之前
父节点
当前提交
5937043c71
共有 3 个文件被更改,包括 197 次插入 和 3 次删除
  1. 18 0
      history/night-shifts/2026-09-18.md
  2. 12 3
      recipes/dsv41-flash-8x/recipe.toml
  3. 167 0
      recipes/glm53-full-mxfp4-8x/recipe.toml

+ 18 - 0
history/night-shifts/2026-09-18.md

@@ -243,6 +243,24 @@ qualified).
 3. **DS4.1-Flash lab-policy A/B** (MTP k2, GMU 0.91, seqs 64): requires
    downloading `deepseek-ai/DeepSeek-V4-Flash` @60d8d70 (~510 GB) — a
    multi-hour NAS download; start early if the operator wants it.
+4. **SGLang DS4.1 4x** (operator-added 09-18 evening, aidenle.com recipe
+   `deepseek-v4-1-flash-sglang-4x-dgx-spark`): the SGLang team's own
+   DeepSeek-V4.1 image `lmsysorg/sglang:dev-dsv41` + the `aidendle94/
+   sparkrun-sglang-dsv41-gb10:production-1.0` overlay (MIT, ~1.5k lines of
+   import hooks: Engram rows from node-local NVMe INSIDE the CUDA graph,
+   b12x SM12x kernels for the FP8 dense layers, two SM120 fixes, allocator
+   flush, one-shot RDMA collectives). TP4 + EP4, dsv4 attention backend,
+   FlashInfer MXFP4 MoE runner, DSpark k5 (block size 5, checkpoint's own
+   draft layers). Aiden's fleet has run it as production since 09-17
+   (replaced their vLLM stack): prefill +30-45% vs their vLLM lane, decode
+   level, +23% KV pool. Prereqs we already have: the /var/tmp/engram-local
+   sparse copies on dgx1-4 (reused as-is), weights on the NAS. New: pull
+   the 34 GB image to the 4 nodes, recipe with the SGLang engine args
+   (`sglang serve` entrypoint — a new entrypoint for us: the launcher's
+   SGLang flag set is for the stock engine; this lane needs their overlay's
+   dsv4 backend + EP4), earlyoom tuning, root on the nodes (we have it).
+   The bench A/B target: our vLLM prod (167/176, 1,642 pp / 47.0 tg /
+   1,738 ms @d0 c1).
 
 ### P4 — bookkeeping
 - File the lab issues (garbling bisect + 3 engine bugs from 09-13).

+ 12 - 3
recipes/dsv41-flash-8x/recipe.toml

@@ -7,8 +7,17 @@
 # reads them from memory (no per-token disk reads).
 #
 # Memory math per node (121.6 GiB): weights 307.3 GB / 8 = 38.4 GB + engram
-# rows 50.7 GB + process ~12 GB = ~101 GB. GMU 0.91 (the lab DS4.1 policy,
-# lil-catalog 09-15) leaves a ~9.5 GiB KV pool ≈ 1M tokens = ~1.9x 512K.
+# rows ~25.4 GB (the real table data is ~203 GB — the two 101.5 GB sparse
+# shards whose 4x /var/tmp copies of 48 GB real sum to 192 GB) + process
+# ~12 GB = ~76 GB.
+#
+# GMU: the lab DS4.1 policy says 0.91, but the GB10 admission check needs
+# free >= GMU x 121.63 and the baseline-reserved ~12.8 GiB leaves only
+# 108.8 GiB free at startup — 0.91 (110.7) fails the admission on GB10
+# (first 8x boot, 2026-09-18 16:02: "Free memory on device cuda:0
+# (108.78/121.63 GiB) ... less than desired GPU memory utilization"). 0.85
+# (103.4) is the GB10-qualified prod value and still leaves ~27.6 GiB of KV
+# per rank (103.4 - 38.4 - 25.4 - 12), ≈ 3M tokens ≈ 6x 512K.
 #
 # Image: dsv41-flash:local (the tonyd2wild prod chain — engram.py patch
 # baked in; DSV41_ENGRAM_DISK simply NOT set here = memory mode). The
@@ -37,7 +46,7 @@ args = [
     "--served-model-name", "deepseek-v4-flash",
     "--trust-remote-code",
     "--distributed-executor-backend", "mp",
-    "--gpu-memory-utilization", "0.91",
+    "--gpu-memory-utilization", "0.85",
     "--max-model-len", "524288",
     "--max-num-seqs", "8",
     "--max-num-batched-tokens", "8192",

+ 167 - 0
recipes/glm53-full-mxfp4-8x/recipe.toml

@@ -0,0 +1,167 @@
+# GLM-5.3 (full) MXFP4 — 8x DGX Spark @512K, no DCP.
+#
+# P2.1 of the 2026-09-18 night: the full model's first 8x trial. The 4x
+# 512K state is blocked by the DCP>1 sparse-decode crash
+# (deepseek_v32/attention.py:596, r35+r37); at 8x no DCP is needed:
+#
+#   weights  403.4 GB / 8 = 50.4 GB/node
+#   budget   GMU 0.85 x 121.63 = 103.4 GiB
+#   KV pool  103.4 - 50.4 - 12 (process) = ~41 GiB/rank
+#   512K req 26.3 GiB  -> 1.5x concurrency (768K would be ~39.5, tight)
+#
+# Same image/contract as the qualified 4x 131K state (marlin linear, B12X
+# attention, instanttensor, block 256, RoCE allreduce) minus DCP and the KV
+# pin (the pool is GMU-driven at 8x). The 4x 131K anchor (dev67 no-spec):
+# 158/176, 934 pp / 19.0 tg / 2,124 ms.
+engine = "vllm"
+name = "GLM-5.3 (full) MXFP4 (r37 img, RedHatAI ckpt, 8x DCP1 @512K)"
+# Image: the r37 DS4.1 build (2026-09-14, night shift) - the r35 tree's DCP4
+# sparse-INDEXER path asserts interleave==1 and then crashes in the DCP sparse
+# decode reshape during graph capture ("shape '[16, 16, 512]' is invalid for
+# input of size 524288" - the x4 DCP factor in the attention.py _sparse_
+# decode). r37 is the newer DS4.1 lock whose DCP sparse-MLA path is the
+# qualified one (same tree family as our DCP2/DFlash2 work); the GlmMoeDsa
+# arch + MTP + b12x ship in the r37 image (verified 2026-09-13).
+docker_image = "jovian-r37-ds41:local"
+docker_image_dir = "glm53-jovian-r27"
+# NOTE: build_profile must stay a TOP-LEVEL key — a bare key after
+# [[extra_mounts]] would parse into the last mount table and be silently
+# ignored (2026-09-08).
+build_profile = "jovian-r37-ds41"
+entrypoint = ["vllm", "serve"]
+model = "RedHatAI/GLM-5.3-MXFP4"
+parent_model = "zai-org/GLM-5.3"
+required_nodes = 8
+tensor_parallel_size = 8
+pipeline_parallel_size = 1
+distributed_backend = "mp"
+shm_size = "32gb"
+
+args = [
+    # R31/r35 delta (their qualified locks): adaptive prefill/decode
+    # compute-time sharing with a fixed 40% prefill floor.
+    "--prefill-compute-share", "0.4",
+    # Stable served name — quant-agnostic (shared across glm53 lanes)
+    "--served-model-name", "glm53",
+    "--trust-remote-code",
+    "--distributed-executor-backend", "mp",
+    # Admission guardrail only (KV is pinned below): 0.85×121.63 = 103.4 GiB.
+    # 0.88 (107.0) is the Flash lane's value and is too tight here — the full
+    # model's weights leave ~24 GiB before the engine's own ~12 GiB.
+    "--gpu-memory-utilization", "0.85",
+    # No KV pin: the pool is GMU-driven at 8x (~41 GiB/rank, see header).
+    # No --kv-cache-dtype: let the r35 fork pick its native default for
+    # GlmMoeDsa attention (the Flash lane's explicit fp8/fp8_ds_mla spellings
+    # both failed auto-selection on this build, and those were Flash-MLA
+    # knobs). The card's --kv-cache-dtype fp8_e4m3 is the fallback spelling
+    # if the pool needs to shrink.
+    "--attention-backend", "B12X",
+    # MXFP4 kernel routing (measured on the first boot, 2026-09-13 ~23:10 UTC):
+    # - MoE: the compressed-tensors W4A4-MXFP4 scheme picks MarlinExperts on
+    #   its own (A16 dequant GEMM - correct on GB10). The --moe-backend flag
+    #   does not reach that scheme (verified inert: it still logged "Using
+    #   MarlinExperts for MXFP4 MoE" with the flag set), so we do not set it.
+    # - LINEAR: the default priority [FlashInfer, Marlin, Humming, B12x]
+    #   starts with the FlashInfer kernel, whose is_supported() wrongly
+    #   accepts capability 121 (the numeric has_device_capability(100) check
+    #   passes on GB10) while the cute-dsl mm_fp4 GEMM it calls rejects it at
+    #   runtime with:
+    #     BackendSupportedError: mm_fp4 does not support backend 'cute-dsl'
+    #     with capability 121
+    #   (the first probe boot died there, kv_b_proj dequant in mla_attention.py).
+    # --linear-backend b12x forces the B12xMxFp4LinearKernel - "MXFP4 linear
+    # through the native B12X SM120 dense GEMM" - the right path on GB10,
+    # verified per component: is_device_capability_family(120)=True, b12x
+    # blockscaled.is_supported()=True, and the cute-dsl input quantize
+    # (flashinfer_mxfp4_quantize) works on capability 121; only the cute-dsl
+    # mm_fp4 GEMM is unsupported there. Boot log to look for:
+    #   "Using B12xMxFp4LinearKernel for MXFP4 GEMM"
+    # (The lab's GLM-5.1 runbook describes the same kernel family for the
+    # quant_method=mxfp4 ingestion path - this checkpoint goes through the
+    # compressed-tensors path, which is why --moe-backend was the wrong lever.)
+    # First attempt: b12x (the native SM120 GEMM) - correct selection, but the
+    # unconditional b12x warmup (b12x_warmup.py, no config gate) crashes on
+    # this checkpoint's layer shapes during kernel compile:
+    #   RuntimeError: Expected source and destination tensors to have the same
+    #   rank, but got 3 and 4  (b12x/gemm/blockscaled/_linear.py dense_gemm,
+    #   via _apply_b12x_mxfp4_linear on a synthetic zero source)
+    # so the mxfp4 LINEAR layers run on Marlin (weight-only A16 dequant GEMM -
+    # the same family as the MarlinExperts the MoE scheme picked). Slower than
+    # native FP4 for the attention projections, but the MoE experts (the
+    # dominant cost) are Marlin either way. The b12x warmup rank bug is
+    # filed-worthy for the lab (RedHatAI GLM-5.3-MXFP4 on GB10/sm_121a).
+    "--linear-backend", "marlin",
+    # pure I/O loader (kept across every GLM config)
+    "--load-format", "instanttensor",
+    "--block-size", "256",
+    "--max-model-len", "524288",
+    "--max-num-seqs", "8",
+    "--max-num-batched-tokens", "4096",
+    "--enable-chunked-prefill",
+    "--async-scheduling",
+    "--enable-prefix-caching",
+    # Their proven boot: no flashinfer autotune, no CuTe-DSL warmup (the
+    # autotune scratch at 512K shapes does not fit the headroom, 2026-08-28).
+    "--kernel-config", """
+'{"enable_cutedsl_warmup":false,"enable_flashinfer_autotune":false}'""",
+    "--language-model-only",
+    # NO --speculative-config on the first boot — see the header. MTP head is
+    # in the checkpoint (num_nextn_predict_layers=1); add mtp k=3 after a
+    # clean boot + bench.
+    "--tool-call-parser", "glm47",
+    "--enable-auto-tool-choice",
+    "--reasoning-parser", "glm45",
+]
+
+[env]
+
+# R31 lock: 16 NCCL channels (their qualified runtime).
+NCCL_NCHANNELS = "16"
+HF_HUB_OFFLINE = "1"
+# RoCEnante (b12x one-shot RoCE all-reduce/all-gather) — default on for r27+
+# lanes since the 2026-09-08 A/B (4x DCP4: decode +31..+90%, quality 160 vs
+# 155; specs/tech-architecture/glm53-recipe-state.md). Needs the CX-7 RoCE
+# fabric (all of ours); single-node serves skip it silently.
+VLLM_ENABLE_ROCE_ALLREDUCE = "1"
+# Compile-OOM guard: first boot JIT-compiles the mxfp8 gemm module with 12
+# parallel nvcc jobs (~3 GiB each) behind ~94 GiB of resident weights →
+# cicc OOM-killed (2026-09-04). flashinfer's run_ninja reads MAX_JOBS.
+MAX_JOBS = "2"
+# NoPE-MLA rope-pad runtime gate (mod baked into the image)
+VLLM_MLA_NOPE_PAD_ROPE = "1"
+VLLM_ENGINE_READY_TIMEOUT_S = "3600"
+# Upstream launch-script env (memory + compile knobs)
+PYTORCH_CUDA_ALLOC_CONF = "expandable_segments:True"
+VLLM_USE_AOT_COMPILE = "0"
+VLLM_USE_STANDALONE_COMPILE = "1"
+VLLM_USE_FLASHINFER_SAMPLER = "1"
+VLLM_USE_BREAKABLE_CUDAGRAPH = "0"
+TORCH_USE_RTLD_GLOBAL = "1"
+VLLM_NO_USAGE_STATS = "1"
+
+# Architecture (aarch64 / sm_121a DGX Spark)
+TORCH_CUDA_ARCH_LIST = "12.1a"
+FLASHINFER_CUDA_ARCH_LIST = "12.1f"
+CUTE_DSL_ARCH = "sm_121a"
+CMAKE_CUDA_ARCHITECTURES = "121"
+OMP_NUM_THREADS = "2"
+
+[[extra_mounts]]
+host = "~/sm121-cache/glm53-jit-121f/b12x"
+container = "/root/.cache/b12x"
+
+# JIT caches persist per-node across serves (was: cold /root/.cache per
+# container -> ~20 min flashinfer/torch recompile every serve). The host
+# dirs are shared between lanes of the same arch — each cache
+# self-namespaces by its engine version key internally.
+[[extra_mounts]]
+host = "~/sm121-cache/jit-121f/flashinfer"
+container = "/root/.cache/flashinfer"
+
+[[extra_mounts]]
+host = "~/sm121-cache/jit-121f/torchinductor"
+container = "/root/.cache/torchinductor"
+
+[[extra_mounts]]
+host = "~/sm121-cache/jit-121f/vllm"
+container = "/root/.cache/vllm"