router_live.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. """The verify_cap dead-row remap folded into the router kernel (DSV41_ROUTER_LIVE=1, needs DSV41_VERIFY_CAP).
  2. verify_cap copies the anchor row's router ids/weights over every dead verify row with a separate
  3. kernel after the router (40 launches, ~0.21 ms/step at c1). Here the router kernel itself loads the
  4. ANCHOR row's scores (and token id) for dead rows, so it computes the anchor's ids and weights for
  5. them: the same values the copy produced, one launch fewer per layer. Built from the engine's own
  6. module source with two text substitutions; any drift in that source disables the patch at import.
  7. """
  8. import importlib.util
  9. import inspect
  10. import os
  11. import tempfile
  12. import torch
  13. ENABLED = os.environ.get("DSV41_ROUTER_LIVE", "0").strip() not in ("0", "", "off", "false")
  14. _SUBS = [
  15. # kernel signature: the live-length buffer and the verify stride
  16. (" stride_pk,\n) -> None:\n",
  17. " stride_pk,\n live_ptr,\n LIVE: tl.constexpr,\n LIVE_STRIDE: tl.constexpr,\n) -> None:\n"),
  18. # dead rows read the anchor row (first row of their request)
  19. (" live_m = mask_m\n",
  20. " live_m = mask_m\n"
  21. " src_m = offs_m\n"
  22. " if LIVE:\n"
  23. " req = offs_m // LIVE_STRIDE\n"
  24. " lv = tl.load(live_ptr + req, mask=mask_m, other=LIVE_STRIDE)\n"
  25. " src_m = tl.where((offs_m % LIVE_STRIDE) >= lv, req * LIVE_STRIDE, offs_m)\n"),
  26. (" row_ptr = scores_ptr + offs_m[:, None] * stride_sm + offs_n[None, :] * stride_sn\n",
  27. " row_ptr = scores_ptr + src_m[:, None] * stride_sm + offs_n[None, :] * stride_sn\n"),
  28. (" input_ids = tl.load(\n input_ids_ptr + offs_m * stride_input_ids, mask=live_m, other=0\n )\n",
  29. " input_ids = tl.load(\n input_ids_ptr + src_m * stride_input_ids, mask=live_m, other=0\n )\n"),
  30. # python wrapper: accept live=, stride= and pass them on
  31. (" packed_out: Optional[torch.Tensor] = None,\n) -> Tuple[torch.Tensor, torch.Tensor]:\n",
  32. " packed_out: Optional[torch.Tensor] = None,\n live: Optional[torch.Tensor] = None,\n"
  33. " live_stride: int = 6,\n) -> Tuple[torch.Tensor, torch.Tensor]:\n"),
  34. ]
  35. def build(module):
  36. """Exec a patched copy of sglang.kernels.ops.moe.moe_fused_gate; return its moe_fused_gate."""
  37. src = inspect.getsource(module)
  38. for a, b in _SUBS:
  39. if src.count(a) != 1:
  40. raise RuntimeError(f"router_live: engine source drifted ({a.strip()[:40]!r})")
  41. src = src.replace(a, b)
  42. tail = " stride_pk=packed_out.stride(1) if packed_out is not None else 0,\n"
  43. if src.count(tail) != 1:
  44. raise RuntimeError("router_live: engine launch drifted")
  45. src = src.replace(tail, tail + " live_ptr=live if live is not None else _unused_i32,\n"
  46. " LIVE=live is not None,\n LIVE_STRIDE=live_stride,\n")
  47. # Triton reads @jit sources from a real file
  48. path = os.path.join(tempfile.gettempdir(), f"dsv41_router_live_{os.getpid()}.py")
  49. with open(path, "w") as f:
  50. f.write(src)
  51. spec = importlib.util.spec_from_file_location("dsv41_router_live", path)
  52. mod = importlib.util.module_from_spec(spec)
  53. spec.loader.exec_module(mod)
  54. return mod.moe_fused_gate