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
202 lines
6.2 KiB
Python
202 lines
6.2 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
import random
|
|
from collections.abc import Callable
|
|
from typing import TYPE_CHECKING, Optional
|
|
|
|
import torch
|
|
|
|
from sglang.jit_kernel.kv_canary.verify import RealKvSource
|
|
from sglang.srt.kv_canary.buffer_group import CanaryBufferGroup, PoolKind
|
|
from sglang.srt.kv_canary.perturb.config import PerturbConfig, TargetGroupKind
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
if TYPE_CHECKING:
|
|
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
|
|
|
|
|
|
class WarmupGate:
|
|
"""Per-hook warmup window check + once-per-lifetime disable/enable log emission.
|
|
|
|
Shared across the four perturb-point hooks so warmup state is decided in one place
|
|
rather than duplicated per hook.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
config: PerturbConfig,
|
|
outer_step_counter_getter: Callable[[], int],
|
|
) -> None:
|
|
self._config = config
|
|
self._outer_step_counter_getter = outer_step_counter_getter
|
|
self._warmup_disable_logged: bool = False
|
|
self._warmup_enable_logged: bool = False
|
|
|
|
def is_in_warmup(self) -> bool:
|
|
step = self._outer_step_counter_getter()
|
|
warmup_steps = self._config.warmup_steps
|
|
|
|
if step < warmup_steps:
|
|
self._log_warmup_disabled_once(warmup_steps)
|
|
return True
|
|
|
|
self._log_warmup_enabled_once(step)
|
|
return False
|
|
|
|
def _log_warmup_disabled_once(self, warmup_steps: int) -> None:
|
|
if self._warmup_disable_logged:
|
|
return
|
|
|
|
logger.info(
|
|
"kv_canary perturb: disabled during warmup window "
|
|
"(first %d forward steps)",
|
|
warmup_steps,
|
|
)
|
|
self._warmup_disable_logged = True
|
|
|
|
def _log_warmup_enabled_once(self, step: int) -> None:
|
|
if self._warmup_enable_logged:
|
|
return
|
|
|
|
logger.info("kv_canary perturb: enabled after warmup window at step=%d", step)
|
|
self._warmup_enable_logged = True
|
|
|
|
|
|
def should_run_perturbation(
|
|
*,
|
|
perturb_name: str,
|
|
probability: float,
|
|
warmup_gate: WarmupGate,
|
|
maybe_inaccurate_forward_batch: Optional[ForwardBatch],
|
|
require_forward_batch: bool = True,
|
|
) -> bool:
|
|
if probability <= 0.0:
|
|
return False
|
|
if warmup_gate.is_in_warmup():
|
|
return False
|
|
if require_forward_batch and maybe_inaccurate_forward_batch is None:
|
|
logger.info(
|
|
"kv_canary perturb %s: skipped because maybe_inaccurate_forward_batch is unavailable",
|
|
perturb_name,
|
|
)
|
|
return False
|
|
return torch.rand((), device="cpu").item() < probability
|
|
|
|
|
|
def pick_target_group(
|
|
*,
|
|
buffer_groups: tuple[CanaryBufferGroup, ...],
|
|
target_kind: TargetGroupKind,
|
|
) -> Optional[CanaryBufferGroup]:
|
|
"""Filter buffer_groups by target_kind restricted to groups with non-empty real_kv_sources_k.
|
|
|
|
Returns None if no group matches.
|
|
"""
|
|
eligible = [group for group in buffer_groups if group.real_kv_sources_k]
|
|
if not eligible:
|
|
return None
|
|
if target_kind == TargetGroupKind.FULL:
|
|
want = PoolKind.FULL
|
|
elif target_kind == TargetGroupKind.SWA:
|
|
want = PoolKind.SWA
|
|
else:
|
|
raise ValueError(f"Unsupported target_group_kind: {target_kind!r}")
|
|
filtered = [group for group in eligible if group.kind == want]
|
|
if not filtered:
|
|
return None
|
|
pick = random.randrange(len(filtered))
|
|
return filtered[pick]
|
|
|
|
|
|
def flip_random_source_byte_and_log(
|
|
*,
|
|
perturb_name: str,
|
|
group: CanaryBufferGroup,
|
|
slot_idx: int,
|
|
) -> None:
|
|
"""Pick a random K-half real_kv source on group, flip byte 0 of slot_idx's tile
|
|
in it, and log the result. Logs and returns silently when the group has no
|
|
real_kv_sources_k or the slot cannot be mapped into the chosen source."""
|
|
if not group.real_kv_sources_k:
|
|
logger.info(
|
|
"kv_canary perturb %s: skipped because group=%s has no real_kv_sources_k",
|
|
perturb_name,
|
|
group.kind.name,
|
|
)
|
|
return
|
|
source_pick = random.randrange(len(group.real_kv_sources_k))
|
|
source = group.real_kv_sources_k[source_pick]
|
|
flip_result = flip_first_byte_in_source(
|
|
group=group, source=source, slot_idx=slot_idx
|
|
)
|
|
if flip_result is None:
|
|
logger.info(
|
|
"kv_canary perturb %s: skipped because slot=%d could not be mapped "
|
|
"into group=%s source_idx=%d",
|
|
perturb_name,
|
|
slot_idx,
|
|
group.kind.name,
|
|
source_pick,
|
|
)
|
|
return
|
|
row, col, original_byte = flip_result
|
|
logger.info(
|
|
"kv_canary perturb %s: group=%s source_idx=%d slot=%d row=%d col=%d "
|
|
"original_byte=0x%02X new_byte=0x%02X",
|
|
perturb_name,
|
|
group.kind.name,
|
|
source_pick,
|
|
slot_idx,
|
|
row,
|
|
col,
|
|
original_byte,
|
|
original_byte ^ 0xFF,
|
|
)
|
|
|
|
|
|
def flip_first_byte_in_source(
|
|
*,
|
|
group: CanaryBufferGroup,
|
|
source: RealKvSource,
|
|
slot_idx: int,
|
|
slot_is_physical: bool = False,
|
|
) -> Optional[tuple[int, int, int]]:
|
|
"""XOR 0xFF on byte 0 of slot_idx's tile in source.tensor (column
|
|
`(physical_slot % page_size) * num_bytes_per_token`, not row offset 0).
|
|
|
|
For SWA groups, slot_idx is translated through group.swa_index_lut before computing
|
|
(row, col). Returns (row, col, original_byte) for logging, or None if the slot is
|
|
out-of-range / source is degenerate.
|
|
"""
|
|
if source.num_bytes_per_token <= 0 or source.read_bytes <= 0:
|
|
return None
|
|
|
|
physical_slot = slot_idx
|
|
if (
|
|
not slot_is_physical
|
|
and group.kind == PoolKind.SWA
|
|
and group.swa_index_lut is not None
|
|
):
|
|
lut = group.swa_index_lut
|
|
if slot_idx < 0 or slot_idx >= int(lut.shape[0]):
|
|
return None
|
|
physical_slot = int(lut[slot_idx].detach().to("cpu").item())
|
|
if physical_slot < 0:
|
|
return None
|
|
|
|
page_size = max(1, source.page_size)
|
|
row = physical_slot // page_size
|
|
col = (physical_slot % page_size) * source.num_bytes_per_token
|
|
if row < 0 or row >= int(source.tensor.shape[0]):
|
|
return None
|
|
if col < 0 or col >= int(source.tensor.shape[1]):
|
|
return None
|
|
|
|
flat = source.tensor
|
|
original_byte = int(flat[row, col].item())
|
|
flat[row, col] = original_byte ^ 0xFF
|
|
return row, col, original_byte
|