Files
wehub-resource-sync 59a0a3844c
PR Test AMD / cancel-on-close (push) Has been skipped
PR Test NVIDIA ARM / scan (push) Has been skipped
PR Test NVIDIA / cancel-on-close (push) Has been skipped
PR Test AMD / scan (push) Has been skipped
PR Test NVIDIA ARM / cancel-on-close (push) Has been skipped
PR Test NVIDIA / scan (push) Has been skipped
Release Docker Images / build (cu129-torch-2.11.0) (push) Has been skipped
Release Docker Images / build (cu130-torch-2.11.0) (push) Has been skipped
Release PyPI / publish (push) Has been skipped
Scheduler Python Test / test (push) Successful in 27m19s
Docs / build (push) Successful in 28m8s
Scheduler C++ Test / test (push) Successful in 28m19s
Scheduler C++ Test / test-flat (push) Successful in 28m18s
Docs / deploy (push) Has been cancelled
PR Test AMD / finish (push) Has been cancelled
PR Test NVIDIA / finish (push) Has been cancelled
PR Test NVIDIA ARM / finish (push) Has been cancelled
PR Test NVIDIA ARM / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
PR Test AMD / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
PR Test NVIDIA / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:32:31 +08:00

135 lines
5.2 KiB
Python

# Copyright (c) 2026 LightSeek Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""Full DeepSeek-V4 sleep/wake integration test (DP4), exercising the V4 KV pool
region wrapping AND the DP idle-forward gate.
Run on a 4-GPU box with the compiled tokenspeed env + torch_memory_saver:
CUDA_VISIBLE_DEVICES=2,3,4,5 python3 test/runtime/test_sleep_wakeup_v4_gpu.py \
deepseek-ai/DeepSeek-V4-Pro
Mirrors the serving config (run.sh): DP4, expert parallel, fp8 KV,
deepseek_v4 tokenizer, mega_moe. Validates that release_memory_occupation frees
GPU memory across all DP ranks, resume restores, generation is coherent after a
sleep cycle, and the multi-stage RL tag flow works.
"""
import os
import subprocess
import sys
def _visible():
v = os.environ.get("CUDA_VISIBLE_DEVICES", "0")
return [int(x) for x in v.split(",") if x != ""]
def gpu_used_mib_total() -> int:
total = 0
for idx in _visible():
out = subprocess.check_output(
[
"nvidia-smi",
"--query-gpu=memory.used",
"--format=csv,noheader,nounits",
"-i",
str(idx),
]
)
total += int(out.decode().strip().splitlines()[0])
return total
def main() -> None:
model = sys.argv[1] if len(sys.argv) > 1 else "deepseek-ai/DeepSeek-V4-Pro"
from tokenspeed.runtime.entrypoints.engine import Engine
engine = Engine(
model=model,
data_parallel_size=len(_visible()),
enable_expert_parallel=True,
kv_cache_dtype="fp8_e4m3",
tokenizer_mode="deepseek_v4",
trust_remote_code=True,
attention_use_fp4_indexer_cache=True,
moe_backend="mega_moe",
enable_memory_saver=True,
# KV release requires prefix caching off until a real prefix-cache reset
# exists (release discards KV; retained entries would be stale on wake).
# KVStore requires prefix caching, so it must be disabled here too.
enable_prefix_caching=False,
disable_kvstore=True,
max_model_len=4096,
max_total_tokens=16384,
chunked_prefill_size=8192,
gpu_memory_utilization=float(os.environ.get("GMU", "0.85")),
log_level="info",
)
prompt = "The capital of France is"
sp = {"temperature": 0.0, "max_new_tokens": 16}
print("[boot] is_sleeping:", engine.is_sleeping())
base = engine.generate(prompt, sp)
base_text = base["text"] if isinstance(base, dict) else base[0]["text"]
print("[baseline]", repr(base_text))
used0 = gpu_used_mib_total()
print(f"[memA] total used before release: {used0} MiB")
# --- Case A: full release frees GPU memory across all DP ranks ---
r = engine.release_memory_occupation()
print("[A] release ->", r, "is_sleeping:", engine.is_sleeping())
used1 = gpu_used_mib_total()
print(f"[memA] total used after release: {used1} MiB (freed {used0 - used1} MiB)")
assert engine.is_sleeping() is True
assert used1 < used0, "release must free GPU memory"
engine.resume_memory_occupation()
print("[A] resume -> is_sleeping:", engine.is_sleeping())
assert engine.is_sleeping() is False
# --- Case B: coherent generation after a sleep cycle (DP idle-forward gate
# must not have hung NCCL while released) ---
after = engine.generate(prompt, sp)
after_text = after["text"] if isinstance(after, dict) else after[0]["text"]
print("[B] after-wake:", repr(after_text))
assert after_text == base_text, f"output changed: {base_text!r} != {after_text!r}"
print("[B] token-identical across sleep cycle (DP4): OK")
# --- Case C: RL multi-stage tag flow ---
engine.release_memory_occupation(tags=["weights", "kv_cache"])
assert engine.is_sleeping() is True
engine.resume_memory_occupation(tags=["weights"])
assert engine.is_sleeping() is True
engine.resume_memory_occupation(tags=["kv_cache"])
assert engine.is_sleeping() is False
c = engine.generate(prompt, sp)
c_text = c["text"] if isinstance(c, dict) else c[0]["text"]
print("[C] multi-stage wake generate:", repr(c_text))
print("[C] multi-stage tag flow (DP4): OK")
print("\nALL V4 GPU CASES PASSED")
engine.shutdown()
if __name__ == "__main__":
main()