94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
195 lines
6.4 KiB
Python
195 lines
6.4 KiB
Python
import gzip
|
|
import os
|
|
|
|
import torch
|
|
|
|
from sglang.multimodal_gen.runtime.platforms import current_platform
|
|
from sglang.multimodal_gen.runtime.utils.logging_utils import CYAN, RESET, init_logger
|
|
from sglang.srt.utils.torch_npu_patch_utils import apply_torch_npu_patches
|
|
|
|
if current_platform.is_npu():
|
|
import torch_npu
|
|
|
|
patches = [
|
|
["profiler.profile", torch_npu.profiler.profile],
|
|
["profiler.schedule", torch_npu.profiler.schedule],
|
|
]
|
|
apply_torch_npu_patches(torch_npu, patches)
|
|
|
|
logger = init_logger(__name__)
|
|
|
|
|
|
def _resolve_profiler_log_dir(log_dir: str | None) -> str:
|
|
if log_dir is not None:
|
|
return log_dir
|
|
|
|
diffusion_profiler_dir = os.getenv("SGLANG_DIFFUSION_TORCH_PROFILER_DIR")
|
|
if diffusion_profiler_dir:
|
|
return diffusion_profiler_dir
|
|
|
|
return os.getenv("SGLANG_TORCH_PROFILER_DIR", "./logs")
|
|
|
|
|
|
class SGLDiffusionProfiler:
|
|
"""
|
|
A wrapper around torch.profiler to simplify usage in pipelines.
|
|
Supports both full profiling and scheduled profiling.
|
|
|
|
|
|
1. if profile_all_stages is on: profile all stages, including all denoising steps
|
|
2. otherwise, if num_profiled_timesteps is specified: profile {num_profiled_timesteps} denoising steps. profile all steps if num_profiled_timesteps==-1
|
|
"""
|
|
|
|
_instance = None
|
|
|
|
def __init__(
|
|
self,
|
|
request_id: str | None = None,
|
|
rank: int = 0,
|
|
full_profile: bool = False,
|
|
num_steps: int | None = None,
|
|
num_inference_steps: int | None = None,
|
|
log_dir: str | None = None,
|
|
):
|
|
self.request_id = request_id or "profile_trace"
|
|
self.rank = rank
|
|
self.full_profile = full_profile
|
|
|
|
self.log_dir = _resolve_profiler_log_dir(log_dir)
|
|
|
|
try:
|
|
os.makedirs(self.log_dir, exist_ok=True)
|
|
except OSError:
|
|
pass
|
|
|
|
activities = [torch.profiler.ProfilerActivity.CPU]
|
|
if torch.cuda.is_available() or (
|
|
hasattr(torch, "musa") and torch.musa.is_available()
|
|
):
|
|
activities.append(torch.profiler.ProfilerActivity.CUDA)
|
|
if current_platform.is_npu():
|
|
activities.append(torch_npu.profiler.ProfilerActivity.NPU)
|
|
|
|
if hasattr(torch, "xpu") and torch.xpu.is_available():
|
|
activities.append(torch.profiler.ProfilerActivity.XPU)
|
|
|
|
common_torch_profiler_args = dict(
|
|
activities=activities,
|
|
record_shapes=True,
|
|
with_stack=True,
|
|
on_trace_ready=(
|
|
None
|
|
if not current_platform.is_npu()
|
|
else torch_npu.profiler.tensorboard_trace_handler(self.log_dir)
|
|
),
|
|
)
|
|
if self.full_profile:
|
|
# profile all stages
|
|
self.profiler = torch.profiler.profile(**common_torch_profiler_args)
|
|
self.profile_mode_id = "full stages"
|
|
else:
|
|
# profile denoising stage only
|
|
warmup = 1
|
|
num_actual_steps = num_inference_steps if num_steps == -1 else num_steps
|
|
self.num_active_steps = num_actual_steps + warmup
|
|
self.profiler = torch.profiler.profile(
|
|
**common_torch_profiler_args,
|
|
schedule=torch.profiler.schedule(
|
|
skip_first=0,
|
|
wait=0,
|
|
warmup=warmup,
|
|
active=self.num_active_steps,
|
|
repeat=1,
|
|
),
|
|
)
|
|
self.profile_mode_id = f"{num_actual_steps} steps"
|
|
|
|
logger.info(f"Profiling request: {request_id} for {self.profile_mode_id}...")
|
|
|
|
self.has_stopped = False
|
|
|
|
SGLDiffusionProfiler._instance = self
|
|
self.start()
|
|
|
|
def start(self):
|
|
logger.info("Starting Profiler...")
|
|
self.profiler.start()
|
|
|
|
def _step(self):
|
|
self.profiler.step()
|
|
|
|
def step_stage(self):
|
|
if self.full_profile:
|
|
self._step()
|
|
|
|
def step_denoising_step(self):
|
|
if not self.full_profile:
|
|
if self.num_active_steps >= 0:
|
|
self._step()
|
|
self.num_active_steps -= 1
|
|
else:
|
|
# early exit when enough steps are captured, to reduce the trace file size
|
|
self.stop(dump_rank=0)
|
|
|
|
@classmethod
|
|
def get_instance(cls) -> "SGLDiffusionProfiler":
|
|
return cls._instance
|
|
|
|
def stop(self, export_trace: bool = True, dump_rank: int | None = None):
|
|
if self.has_stopped:
|
|
return
|
|
self.has_stopped = True
|
|
logger.info("Stopping Profiler...")
|
|
if torch.cuda.is_available() or (
|
|
hasattr(torch, "musa") and torch.musa.is_available()
|
|
):
|
|
torch.cuda.synchronize()
|
|
if current_platform.is_npu():
|
|
torch.npu.synchronize()
|
|
export_trace = False # set to false because our internal torch_npu.profiler will generate trace file
|
|
self.profiler.stop()
|
|
|
|
if export_trace:
|
|
if dump_rank is not None and dump_rank != self.rank:
|
|
pass
|
|
else:
|
|
self._export_trace()
|
|
|
|
SGLDiffusionProfiler._instance = None
|
|
|
|
def _export_trace(self):
|
|
|
|
try:
|
|
os.makedirs(self.log_dir, exist_ok=True)
|
|
sanitized_profile_mode_id = self.profile_mode_id.replace(" ", "_")
|
|
trace_path = os.path.abspath(
|
|
os.path.join(
|
|
self.log_dir,
|
|
f"{self.request_id}-{sanitized_profile_mode_id}-global-rank{self.rank}.trace.json.gz",
|
|
)
|
|
)
|
|
self.profiler.export_chrome_trace(trace_path)
|
|
|
|
if self._check_trace_integrity(trace_path):
|
|
logger.info(f"Saved profiler traces to: {CYAN}{trace_path}{RESET}")
|
|
else:
|
|
logger.warning(f"Trace file may be corrupted: {trace_path}")
|
|
except Exception as e:
|
|
logger.error(f"Failed to save trace: {e}")
|
|
|
|
def _check_trace_integrity(self, trace_path: str) -> bool:
|
|
try:
|
|
if not os.path.exists(trace_path) or os.path.getsize(trace_path) == 0:
|
|
return False
|
|
|
|
with gzip.open(trace_path, "rb") as f:
|
|
content = f.read()
|
|
if content.count(b"\x1f\x8b") > 1:
|
|
logger.warning("Multiple gzip headers detected")
|
|
return False
|
|
|
|
return True
|
|
except Exception as e:
|
|
logger.warning(f"Trace file integrity check failed: {e}")
|
|
return False
|