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
135 lines
5.2 KiB
Python
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()
|