diff --git a/python/sglang/test/kits/fwd_occupancy_kit.py b/python/sglang/test/kits/fwd_occupancy_kit.py index 1743c001e..e18659a2f 100644 --- a/python/sglang/test/kits/fwd_occupancy_kit.py +++ b/python/sglang/test/kits/fwd_occupancy_kit.py @@ -212,15 +212,18 @@ class FwdOccupancyMixin: ] if avg_accept is not None: perf_rows.append(["avg spec accept", f"{avg_accept:.3f}"]) + # Lead each table with a text title line so the two tables stay + # visually separated even when CI prefixes every line with a timestamp + # (which turns blank separator lines into non-empty lines). print( - "\n" + "\n[perf metrics]\n" + tabulate.tabulate( perf_rows, headers=["perf metric", "value"], tablefmt="github" ) ) print( - "\n\n" + "\n[fwd_occupancy stats]\n" + tabulate.tabulate( [ ["samples (n)", len(samples)], diff --git a/test/registered/core/test_basic_sanity_dflash.py b/test/registered/core/test_basic_sanity_dflash.py new file mode 100644 index 000000000..2bb03feb7 --- /dev/null +++ b/test/registered/core/test_basic_sanity_dflash.py @@ -0,0 +1,82 @@ +"""Stage-a basic sanity with DFLASH spec decoding enabled. Mirrors +test_basic_sanity.py / test_basic_sanity_eagle3.py with the DFLASH path active +(overlap scheduling on by default).""" + +import unittest + +from sglang.srt.utils import kill_process_tree +from sglang.test.ci.ci_register import register_cuda_ci +from sglang.test.kits.basic_api_contract_kit import BasicAPIContractMixin +from sglang.test.kits.basic_decode_correctness_kit import BasicDecodeCorrectnessMixin +from sglang.test.kits.basic_scheduler_stress_kit import BasicSchedulerStressMixin +from sglang.test.kits.eval_accuracy_kit import GSM8KMixin +from sglang.test.kits.fwd_occupancy_kit import FwdOccupancyMixin +from sglang.test.test_utils import ( + DEFAULT_DRAFT_MODEL_DFLASH, + DEFAULT_TARGET_MODEL_DFLASH, + DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH, + DEFAULT_URL_FOR_TEST, + CustomTestCase, + popen_launch_server, +) + +register_cuda_ci(est_time=200, stage="base-a", runner_config="1-gpu-small") + + +class TestBasicSanityDFlash( + BasicAPIContractMixin, + BasicDecodeCorrectnessMixin, + BasicSchedulerStressMixin, + FwdOccupancyMixin, + GSM8KMixin, + CustomTestCase, +): + served_model_name = DEFAULT_TARGET_MODEL_DFLASH + fwd_occupancy_threshold = 97.5 + fwd_occupancy_max_new_tokens = 4096 + # DFLASH accepts a full block per verify, so its acc length runs well above + # EAGLE3's; keep a safe lower bound here. + fwd_occupancy_acc_length_threshold: float = 2.0 + + model = DEFAULT_TARGET_MODEL_DFLASH + gsm8k_num_questions = 1400 + gsm8k_accuracy_thres = 0.74 + gsm8k_accept_length_thres = 2.8 + + attention_backend = "triton" + draft_attention_backend = "triton" + + @classmethod + def setUpClass(cls): + cls.base_url = DEFAULT_URL_FOR_TEST + cls.process = popen_launch_server( + DEFAULT_TARGET_MODEL_DFLASH, + cls.base_url, + timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH, + other_args=[ + "--trust-remote-code", + "--attention-backend", + cls.attention_backend, + "--speculative-draft-attention-backend", + cls.draft_attention_backend, + "--speculative-algorithm", + "DFLASH", + "--speculative-draft-model-path", + DEFAULT_DRAFT_MODEL_DFLASH, + "--cuda-graph-max-bs", + "4", + "--mem-fraction-static", + "0.7", + "--enable-metrics", + "--disable-piecewise-cuda-graph", + ], + env={"SGLANG_ENABLE_METRICS_DEVICE_TIMER": "1"}, + ) + + @classmethod + def tearDownClass(cls): + kill_process_tree(cls.process.pid) + + +if __name__ == "__main__": + unittest.main()