[NPU] add zbal support for npu (#24575)

This commit is contained in:
litangss
2026-05-13 20:52:42 +08:00
committed by GitHub
parent 4984552cc9
commit 9e00b7ca95
7 changed files with 144 additions and 5 deletions
@@ -1598,7 +1598,7 @@ _DEVICE_TO_DISTRIBUTED_BACKEND = {
"xpu": "xccl",
"hpu": "hccl",
"cpu": "gloo",
"npu": "hccl",
"npu": "hccl" if not envs.SGLANG_ZBAL_LOCAL_MEM_SIZE.get() > 0 else "zbal",
"musa": "mccl",
}
+4
View File
@@ -558,6 +558,10 @@ class Envs:
# TokenizerManager
SGLANG_REQUEST_STATE_WAIT_TIMEOUT = EnvInt(4)
# ZBAL, zero buffer accelerate library, currently worked only in npu
SGLANG_ZBAL_LOCAL_MEM_SIZE = EnvInt(0)
SGLANG_ZBAL_BOOTSTRAP_URL = EnvStr("")
SGLANG_DEFAULT_THINKING = EnvBool(False)
# ====================================================================
@@ -1,5 +1,6 @@
import functools
import logging
import sys
from enum import IntEnum
from typing import TYPE_CHECKING, Callable
@@ -14,6 +15,7 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__)
_is_npu = is_npu()
indexer_weight_stream = None
gva_is_inited = False
class NPUACLFormat(IntEnum):
@@ -184,6 +186,96 @@ def get_indexer_weight_stream():
return indexer_weight_stream
def init_zbal(world_size, gpu_id, world_rank, do_check=True):
"""
init zbal, if is mix alloc mode, only register for sma & comm
"""
zbal_mem_size = envs.SGLANG_ZBAL_LOCAL_MEM_SIZE.get()
if not zbal_mem_size > 0:
return 1
global gva_is_inited
from zbal import is_mix_alloc, switch_to_allocator, zbal_init
if is_mix_alloc():
switch_to_allocator()
# use lazy init for mix alloc
return 1
else:
if envs.SGLANG_ZBAL_BOOTSTRAP_URL.get():
ret = zbal_init(
world_size,
gpu_id,
world_rank,
zbal_mem_size * (1024**2),
ip_port=envs.SGLANG_ZBAL_BOOTSTRAP_URL.get(),
)
else:
ret = zbal_init(world_size, gpu_id, world_rank, zbal_mem_size * (1024**2))
gva_is_inited = True
if do_check and not ret:
logger.error(f"[ZBAL] zbal init failed!")
sys.exit(-1)
return ret
def lazy_init_zbal_gva_mem(
device, gpu_id, world_rank, world_size, cpu_group=None, do_check=True
):
"""
lazy init zbal gva mem, keep weights and kv remains alloc by dma vmm to avoid memory fragment
"""
from zbal import is_mix_alloc, zbal_init
if not is_mix_alloc():
logger.info(
"lazy init is supported only in mix alloc mode, this action will be passed"
)
return 1
global gva_is_inited
from sglang.srt.utils.common import get_available_gpu_memory
# TODO need to use allgather if you want use total_memory stats from mem_get_info as unbalance os
total_memory = 61.2 # 2.5GB for other (workspace & os) outside torch
free_gpu_memory = get_available_gpu_memory(
device,
gpu_id,
distributed=world_size > 1,
cpu_group=cpu_group,
empty_cache=True,
)
used_memory = total_memory - free_gpu_memory
used_memory_in_mb = int(used_memory * 1024)
gva_in_mb = envs.SGLANG_ZBAL_LOCAL_MEM_SIZE.get() - used_memory_in_mb
gva_in_mb = gva_in_mb - gva_in_mb % 128 # align to 128MB
print(f"[ZBAL] rank {world_rank} allocated {gva_in_mb} MB gva space.")
assert not gva_is_inited, "zbal gva should be inited only once"
# zbal_set_logger_level(0)
if envs.SGLANG_ZBAL_BOOTSTRAP_URL.get():
res = zbal_init(
world_size,
gpu_id,
world_rank,
gva_in_mb * (1024**2),
ip_port=envs.SGLANG_ZBAL_BOOTSTRAP_URL.get(),
)
else:
res = zbal_init(world_size, gpu_id, world_rank, gva_in_mb * (1024**2))
gva_is_inited = True
if do_check and not res:
logger.error(f"[ZBAL] zbal lazy init failed!")
sys.exit(-1)
return res
share_stream = None
routed_stream = None
@@ -40,7 +40,11 @@ if TYPE_CHECKING:
from sglang.srt.batch_overlap.single_batch_overlap import CombineOverlapArgs
try:
from deep_ep import Buffer, Config
if _is_npu and envs.SGLANG_ZBAL_LOCAL_MEM_SIZE.get() > 0:
from zbal.zbal.deepep_adaptor import Config
from zbal.zbal_buffer import Buffer
else:
from deep_ep import Buffer, Config
if not _is_npu:
from sglang.srt.layers.quantization.fp8_kernel import (
+13
View File
@@ -417,6 +417,9 @@ class Scheduler(
# Init inter-process communication
self.init_ipc_channels(port_args)
# Init ZBAL, switch allocator should before any torch alloc action
self.init_zbal_on_npu()
# Init PD-multiplexing context
if self.enable_pdmux:
self.init_pdmux()
@@ -496,6 +499,16 @@ class Scheduler(
self.is_initializing = False
def init_zbal_on_npu(self):
if _is_npu:
from sglang.srt.hardware_backend.npu.utils import init_zbal
if self.pp_size > 1:
logger.error(f"only zbal mix mode support pp_size > 1!")
init_zbal(
self.tp_size, self.gpu_id, self.tp_rank
) # only switch allocator if is mix mode
def init_model_config(self):
self.model_config = ModelConfig.from_server_args(self.server_args)
if _is_npu:
@@ -785,9 +785,23 @@ class ModelRunner(ModelRunnerKVCacheMixin):
)
self._pre_initialize_flashinfer_allreduce_workspace()
self.init_device_graphs()
elif self.device in ["npu", "cpu"]:
elif self.device == "cpu":
self.init_attention_backend()
self.init_device_graphs()
elif self.device == "npu":
self.init_attention_backend()
# lazy init for zbal with mix mode(before graph capture when enable_cuda_graph)
if envs.SGLANG_ZBAL_LOCAL_MEM_SIZE.get() > 0 and not self.is_draft_worker:
from sglang.srt.hardware_backend.npu.utils import lazy_init_zbal_gva_mem
lazy_init_zbal_gva_mem(
self.device,
self.gpu_id,
get_world_group().rank_in_group,
get_world_group().world_size,
get_world_group().cpu_group,
)
self.init_device_graphs()
elif current_platform.is_out_of_tree():
self.init_attention_backend()
if current_platform.support_cuda_graph():
+14 -2
View File
@@ -587,7 +587,16 @@ def get_available_gpu_memory(
)
if empty_cache:
empty_device_cache(torch.npu)
free_gpu_memory, total_gpu_memory = torch.npu.mem_get_info()
if envs.SGLANG_ZBAL_LOCAL_MEM_SIZE.get() > 0:
import zbal
if not zbal.is_mix_alloc():
free_gpu_memory, total_gpu_memory = zbal.zbal_module.mem_get_info()
else:
# mix mode fall back into npu mem info since gva may not inited yet
free_gpu_memory, total_gpu_memory = torch.npu.mem_get_info()
else:
free_gpu_memory, total_gpu_memory = torch.npu.mem_get_info()
elif device == "musa":
num_gpus = torch.musa.device_count()
assert gpu_id < num_gpus
@@ -1689,7 +1698,10 @@ def get_npu_memory_capacity():
try:
import torch_npu # noqa: F401
return torch.npu.mem_get_info()[1] // 1024 // 1024 # unit: MB
if envs.SGLANG_ZBAL_LOCAL_MEM_SIZE.get() > 0:
return envs.SGLANG_ZBAL_LOCAL_MEM_SIZE.get() # unit: MB
else:
return torch.npu.mem_get_info()[1] // 1024 // 1024 # unit: MB
except ImportError as e:
raise ImportError("torch_npu is required when run on npu device.")