diff --git a/python/sglang/srt/managers/scheduler.py b/python/sglang/srt/managers/scheduler.py index 92a405dd8..ea657dfa1 100644 --- a/python/sglang/srt/managers/scheduler.py +++ b/python/sglang/srt/managers/scheduler.py @@ -2900,9 +2900,9 @@ class Scheduler( # skip staging requests that are ongoing prefetch continue # Pop the number of tokens loaded from storage (L3 hits) - req.storage_hit_length = self.tree_cache.pop_prefetch_loaded_tokens( - req.rid - ) + loaded_tokens = self.tree_cache.pop_prefetch_loaded_tokens(req.rid) + if loaded_tokens > 0: + req.storage_hit_length = loaded_tokens req.init_next_round_input(self.tree_cache) res = adder.add_one_req( diff --git a/python/sglang/srt/server_args.py b/python/sglang/srt/server_args.py index 0ad76225d..51d68ac83 100644 --- a/python/sglang/srt/server_args.py +++ b/python/sglang/srt/server_args.py @@ -6425,14 +6425,26 @@ class ServerArgs: os.environ[key] = value logger.info("Auto-set %s=%s (from --crash-dump-folder)", key, value) - if key == "CUDA_COREDUMP_FILE": - # cuda curedump cannot write to a folder that does not exist, - # so we have to create the folder first. - hostname = socket.gethostname() - os.makedirs( - os.path.join(self.crash_dump_folder, hostname), - exist_ok=True, - ) + coredump_dir = os.path.dirname( + os.environ["CUDA_COREDUMP_FILE"].replace("%h", socket.gethostname()) + ) + if "%" in coredump_dir: + logger.warning( + "Cannot pre-create CUDA coredump directory %s: only %%h is " + "supported in the directory part of CUDA_COREDUMP_FILE; " + "coredumps may fail to write.", + coredump_dir, + ) + elif coredump_dir: + try: + os.makedirs(coredump_dir, exist_ok=True) + except OSError as e: + logger.warning( + "Failed to create CUDA coredump directory %s: %s; " + "coredumps may fail to write.", + coredump_dir, + e, + ) def _handle_debug_utils(self): if is_in_ci() and self.soft_watchdog_timeout is None: diff --git a/test/registered/unit/server_args/test_server_args.py b/test/registered/unit/server_args/test_server_args.py index 7b6cb291b..14b0af87c 100644 --- a/test/registered/unit/server_args/test_server_args.py +++ b/test/registered/unit/server_args/test_server_args.py @@ -1,6 +1,7 @@ import importlib import json import os +import socket import tempfile import unittest from types import SimpleNamespace @@ -1294,6 +1295,48 @@ class TestSamplingBackendTokenOracleEnvGate(CustomTestCase): self.assertEqual(parsed.sampling_backend, "token_oracle") +class TestHandleCrashDumpEnv(CustomTestCase): + _COREDUMP_ENV_KEYS = ( + "CUDA_ENABLE_COREDUMP_ON_EXCEPTION", + "CUDA_ENABLE_USER_TRIGGERED_COREDUMP", + "CUDA_COREDUMP_SHOW_PROGRESS", + "CUDA_COREDUMP_GENERATION_FLAGS", + "CUDA_COREDUMP_FILE", + "CUDA_COREDUMP_PIPE", + ) + + def _run_handler(self, crash_dump_folder, preset_env=None): + server_args = ServerArgs.__new__(ServerArgs) + server_args.crash_dump_folder = crash_dump_folder + with patch.dict(os.environ, preset_env or {}): + for key in self._COREDUMP_ENV_KEYS: + if key not in (preset_env or {}): + os.environ.pop(key, None) + ServerArgs._handle_crash_dump_env(server_args) + + def test_creates_coredump_dir_when_auto_set(self): + with tempfile.TemporaryDirectory() as tmp: + self._run_handler(tmp) + self.assertTrue( + os.path.isdir(os.path.join(tmp, socket.gethostname())), + "coredump dir not created for auto-set CUDA_COREDUMP_FILE", + ) + + def test_creates_coredump_dir_when_env_preset(self): + # Regression test: when CUDA_COREDUMP_FILE is preset, the coredump + # directory must still be created up front. + with tempfile.TemporaryDirectory() as tmp: + preset_dir = os.path.join(tmp, "preset-location") + self._run_handler( + tmp, + preset_env={"CUDA_COREDUMP_FILE": f"{preset_dir}/%h/core.cuda.%t.%p"}, + ) + self.assertTrue( + os.path.isdir(os.path.join(preset_dir, socket.gethostname())), + "coredump dir not created for preset CUDA_COREDUMP_FILE", + ) + + class TestGrpcServerArgs(CustomTestCase): """Native gRPC is enabled by --grpc-port (or SGLANG_GRPC_PORT) and runs alongside HTTP; --smg-grpc-mode (and the deprecated --grpc-mode) select the