[core] Consolidate compiled-kernel caches under SGLANG_CACHE_DIR (#32434)
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
# SGLang public APIs
|
||||
|
||||
# sglang.srt.environ must run before the rest of this file's imports
|
||||
# (hf_transformers_patches, lang.api, ...), which pull in torch and
|
||||
# FlashInfer: those claim these cache dirs early, and the first value set is
|
||||
# the one that sticks. Safe here -- environ has no heavy dependency (no torch).
|
||||
from sglang.srt.environ import redirect_third_party_caches
|
||||
|
||||
redirect_third_party_caches()
|
||||
|
||||
# Install stubs early for platforms where certain dependencies are unavailable
|
||||
# (e.g. macOS/MPS has no triton, and torch.mps lacks Stream / set_device /
|
||||
# get_device_properties). This must run before any downstream imports.
|
||||
|
||||
@@ -82,6 +82,7 @@ from sglang.multimodal_gen.runtime.utils.trace_wrapper import (
|
||||
trace_slice,
|
||||
)
|
||||
from sglang.multimodal_gen.utils import kill_itself_when_parent_died
|
||||
from sglang.srt.environ import third_party_cache_defaults
|
||||
from sglang.srt.utils.network import NetworkAddress
|
||||
|
||||
logger = init_logger(__name__)
|
||||
@@ -175,12 +176,17 @@ class GPUWorker(GPUWorkerPostTrainingMixin):
|
||||
envs.SGLANG_DIFFUSION_CACHE_ROOT, "torch_compile_cache"
|
||||
)
|
||||
tmp_root = tempfile.gettempdir()
|
||||
sglang_defaults = third_party_cache_defaults()
|
||||
for env_name, sub in (
|
||||
("TORCHINDUCTOR_CACHE_DIR", "inductor"),
|
||||
("TRITON_CACHE_DIR", "triton"),
|
||||
):
|
||||
current = os.environ.get(env_name)
|
||||
if current and not current.startswith(tmp_root):
|
||||
if (
|
||||
current
|
||||
and current != sglang_defaults.get(env_name)
|
||||
and not current.startswith(tmp_root)
|
||||
):
|
||||
# Respect an explicit, non-ephemeral user-provided cache dir.
|
||||
continue
|
||||
cache_path = os.path.join(compile_cache_root, sub)
|
||||
|
||||
@@ -1673,6 +1673,34 @@ def _set_envs_and_config(server_args: ServerArgs):
|
||||
if gc_threshold := server_args.gc_threshold:
|
||||
gc.set_threshold(*gc_threshold)
|
||||
|
||||
_log_legacy_kernel_cache_dirs()
|
||||
|
||||
|
||||
def _log_legacy_kernel_cache_dirs():
|
||||
"""Note the pre-SGLANG_CACHE_DIR cache dirs without touching them: other
|
||||
frameworks on the box may still be using them."""
|
||||
# TODO(shuwang21): drop once SGLANG_CACHE_DIR has been the default for a
|
||||
# few releases.
|
||||
legacy_dirs = [
|
||||
d
|
||||
for d in (
|
||||
os.path.expanduser("~/.triton"),
|
||||
os.path.expanduser("~/.cache/flashinfer"),
|
||||
os.path.expanduser("~/.cache/deep_gemm"),
|
||||
)
|
||||
if os.path.isdir(d)
|
||||
]
|
||||
if not legacy_dirs:
|
||||
return
|
||||
logger.info(
|
||||
"Compiled-kernel caches now live under SGLANG_CACHE_DIR (%s). These "
|
||||
"older directories are no longer used by sglang, but may still be "
|
||||
"used by other frameworks on this machine, so they were left alone: "
|
||||
"%s. Remove them yourself if nothing else needs them.",
|
||||
envs.SGLANG_CACHE_DIR.get(),
|
||||
", ".join(legacy_dirs),
|
||||
)
|
||||
|
||||
|
||||
def _scheduler_died_error(rank: int, proc) -> RuntimeError:
|
||||
"""Build a descriptive error for a scheduler process that died during init."""
|
||||
|
||||
@@ -5,7 +5,7 @@ import subprocess
|
||||
import warnings
|
||||
from contextlib import ExitStack, contextmanager
|
||||
from enum import IntEnum
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=1)
|
||||
@@ -25,6 +25,15 @@ def _default_hip() -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _default_cache_subdir(name: str) -> str:
|
||||
"""A directory under SGLANG_CACHE_DIR, for env defaults that track it.
|
||||
|
||||
Pass as a callable default: SGLANG_CACHE_DIR is declared further down the
|
||||
Envs body, and resolving late also lets tests override it.
|
||||
"""
|
||||
return os.path.join(os.path.expanduser(envs.SGLANG_CACHE_DIR.get()), name)
|
||||
|
||||
|
||||
class EnvField:
|
||||
_allow_set_name = True
|
||||
|
||||
@@ -737,7 +746,8 @@ class Envs:
|
||||
SGLANG_JIT_DEEPGEMM_FAST_WARMUP = EnvBool(False)
|
||||
SGLANG_JIT_DEEPGEMM_COMPILE_WORKERS = EnvInt(4)
|
||||
SGLANG_IN_DEEPGEMM_PRECOMPILE_STAGE = EnvBool(False)
|
||||
SGLANG_DG_CACHE_DIR = EnvStr(os.path.expanduser("~/.cache/deep_gemm"))
|
||||
# Resolved lazily so it tracks SGLANG_CACHE_DIR, which is defined below.
|
||||
SGLANG_DG_CACHE_DIR = EnvStr(lambda: _default_cache_subdir("deep_gemm"))
|
||||
SGLANG_DG_USE_NVRTC = EnvBool(False)
|
||||
SGLANG_USE_DEEPGEMM_BMM = EnvBool(False)
|
||||
SGLANG_DEEPGEMM_SANITY_CHECK = EnvBool(False)
|
||||
@@ -1367,6 +1377,33 @@ def _warn_deprecated_env_to_cli_flag(env_name: str, suggestion: str):
|
||||
warnings.warn(f"Environment variable {env_name} is deprecated. {suggestion}")
|
||||
|
||||
|
||||
def third_party_cache_defaults() -> Dict[str, str]:
|
||||
base = os.path.expanduser(envs.SGLANG_CACHE_DIR.get())
|
||||
return {
|
||||
"TRITON_CACHE_DIR": os.path.join(base, "triton"),
|
||||
"TORCHINDUCTOR_CACHE_DIR": os.path.join(base, "inductor"),
|
||||
"CUDA_CACHE_PATH": os.path.join(base, "nv"),
|
||||
# FlashInfer appends ".cache/flashinfer" to this base itself, so this
|
||||
# is the base dir rather than the final cache dir.
|
||||
"FLASHINFER_WORKSPACE_BASE": base,
|
||||
}
|
||||
|
||||
|
||||
def redirect_third_party_caches():
|
||||
"""Point third-party JIT caches at SGLANG_CACHE_DIR, so a run's compiled
|
||||
kernels can be cleaned, warmed or volume-mounted as one directory.
|
||||
|
||||
Must be called early. The redirect silently does nothing if either of
|
||||
these has already happened:
|
||||
|
||||
- FlashInfer was imported. It resolves its workspace at import time.
|
||||
- Inductor made its first ``cache_dir()`` call. That call setdefaults
|
||||
TORCHINDUCTOR_CACHE_DIR itself.
|
||||
"""
|
||||
for key, value in third_party_cache_defaults().items():
|
||||
os.environ.setdefault(key, value)
|
||||
|
||||
|
||||
def _convert_SGL_to_SGLANG():
|
||||
_print_deprecated_env("SGLANG_GC_LOG", "SGLANG_LOG_GC")
|
||||
_print_deprecated_env(
|
||||
|
||||
@@ -35,10 +35,9 @@ _IS_FIRST_RANK_ON_NODE = envs.SGLANG_IS_FIRST_RANK_ON_NODE.get()
|
||||
_IN_PRECOMPILE_STAGE = envs.SGLANG_IN_DEEPGEMM_PRECOMPILE_STAGE.get()
|
||||
_FAST_WARMUP = envs.SGLANG_JIT_DEEPGEMM_FAST_WARMUP.get()
|
||||
|
||||
# Force redirect deep_gemm cache_dir
|
||||
os.environ["DG_JIT_CACHE_DIR"] = os.getenv(
|
||||
"SGLANG_DG_CACHE_DIR", os.path.join(os.path.expanduser("~"), ".cache", "deep_gemm")
|
||||
)
|
||||
# Force redirect deep_gemm cache_dir. Defaults under SGLANG_CACHE_DIR so it
|
||||
# sits with the other compiled-kernel caches; SGLANG_DG_CACHE_DIR still wins.
|
||||
os.environ["DG_JIT_CACHE_DIR"] = envs.SGLANG_DG_CACHE_DIR.get()
|
||||
|
||||
# Refer to https://github.com/deepseek-ai/DeepGEMM/commit/d75b218b7b8f4a5dd5406ac87905039ead3ae42f
|
||||
# NVRTC may have performance loss with some cases.
|
||||
|
||||
Reference in New Issue
Block a user