Files
enginex-ascend-910-vllm/tests/ut/worker/a2/test_worker_v1.py

1512 lines
64 KiB
Python
Raw Normal View History

import unittest
from unittest.mock import MagicMock, patch
import torch
from vllm.config import CacheConfig, ModelConfig, ParallelConfig, ProfilerConfig, VllmConfig
from tests.ut.base import TestBase
init_cached_hf_modules_path = "vllm.utils.import_utils.init_cached_hf_modules"
class TestNPUWorker(TestBase):
def setUp(self):
"""Setup test environment"""
# Create configuration mocks
self.cache_config_mock = MagicMock(spec=CacheConfig)
self.cache_config_mock.cache_dtype = "auto"
self.model_config_mock = MagicMock(spec=ModelConfig)
self.model_config_mock.dtype = torch.float16
self.model_config_mock.trust_remote_code = False
self.hf_config_mock = MagicMock()
self.hf_config_mock.model_type = "test_model"
if hasattr(self.hf_config_mock, "index_topk"):
delattr(self.hf_config_mock, "index_topk")
self.model_config_mock.hf_config = self.hf_config_mock
self.parallel_config_mock = MagicMock(spec=ParallelConfig)
self.vllm_config_mock = MagicMock(spec=VllmConfig)
self.vllm_config_mock.cache_config = self.cache_config_mock
self.vllm_config_mock.model_config = self.model_config_mock
self.vllm_config_mock.parallel_config = self.parallel_config_mock
self.vllm_config_mock.additional_config = None
self.vllm_config_mock.load_config = None
self.vllm_config_mock.scheduler_config = None
self.vllm_config_mock.device_config = None
self.vllm_config_mock.compilation_config = MagicMock()
self.vllm_config_mock.compilation_config.ir_enable_torch_wrap = False
self.vllm_config_mock.kernel_config = MagicMock()
self.vllm_config_mock.kernel_config.ir_op_priority = MagicMock()
self.vllm_config_mock.kernel_config.ir_op_priority.set_default = MagicMock()
self.vllm_config_mock.profiler_config = MagicMock()
self.vllm_config_mock.quant_config = MagicMock()
self.vllm_config_mock.speculative_config = None
self.vllm_config_mock.observability_config = None
self.vllm_config_mock.weight_transfer_config = None
self.local_rank = 0
self.rank = 0
self.distributed_init_method = "tcp://localhost:12345"
self.is_driver_worker = False
@patch("vllm_ascend.utils.adapt_patch")
@patch("vllm_ascend.ops")
@patch("vllm_ascend.worker.worker._register_atb_extensions")
@patch("vllm_ascend.worker.worker.register_ascend_customop")
@patch("vllm_ascend.worker.worker.get_ascend_config")
@patch("vllm_ascend.worker.worker.init_ascend_config")
@patch("vllm_ascend.worker.worker.check_ascend_device_type")
@patch(init_cached_hf_modules_path, create=True)
@patch("vllm_ascend.worker.worker.TorchNPUProfilerWrapper")
def test_init_npu_worker_normal_case(
self,
mock_profiler_wrapper,
mock_init_cached_hf_modules,
mock_check_ascend_device_type,
mock_init_ascend_config,
mock_get_ascend_config,
mock_register_ascend_customop,
mock_register_atb_extensions,
mock_ops,
mock_adapt_patch,
):
"""Test NPUWorker normal initialization"""
# Setup mock behavior
mock_ops.register_dummy_fusion_op.return_value = None
mock_ascend_config = MagicMock()
mock_ascend_config.enable_cpu_binding = True
mock_get_ascend_config.return_value = mock_ascend_config
# Import and create NPUWorker instance
from vllm_ascend.worker.worker import NPUWorker
worker = NPUWorker(
vllm_config=self.vllm_config_mock,
local_rank=self.local_rank,
rank=self.rank,
distributed_init_method=self.distributed_init_method,
is_driver_worker=self.is_driver_worker,
)
# Verify initialization call order
mock_adapt_patch.assert_called_once()
mock_ops.register_dummy_fusion_op.assert_called_once()
mock_register_atb_extensions.assert_called_once()
mock_register_ascend_customop.assert_called_once()
mock_init_ascend_config.assert_called_once_with(self.vllm_config_mock)
mock_check_ascend_device_type.assert_called_once()
# Verify cache_dtype setting
self.assertEqual(worker.cache_dtype, torch.float16)
# Profiler is lazily initialized - not created during __init__ (RFC #6954)
mock_profiler_wrapper.assert_not_called()
# Verify init_cached_hf_modules is not called (trust_remote_code=False)
mock_init_cached_hf_modules.assert_not_called()
@patch("vllm_ascend.utils.adapt_patch")
@patch("vllm_ascend.ops")
@patch("vllm_ascend.worker.worker._register_atb_extensions")
@patch("vllm_ascend.worker.worker.register_ascend_customop")
@patch("vllm_ascend.worker.worker.get_ascend_config")
@patch("vllm_ascend.worker.worker.init_ascend_config")
@patch("vllm_ascend.worker.worker.check_ascend_device_type")
@patch(init_cached_hf_modules_path, create=True)
@patch("vllm_ascend.worker.worker.TorchNPUProfilerWrapper")
def test_init_npu_worker_with_trust_remote_code(
self,
mock_profiler_wrapper,
mock_init_cached_hf_modules,
mock_check_ascend_device_type,
mock_init_ascend_config,
mock_get_ascend_config,
mock_register_ascend_customop,
mock_register_atb_extensions,
mock_ops,
mock_adapt_patch,
):
"""Test NPUWorker initialization with trust_remote_code=True"""
# Set trust_remote_code=True
self.model_config_mock.trust_remote_code = True
mock_ops.register_dummy_fusion_op.return_value = None
mock_ascend_config = MagicMock()
mock_ascend_config.enable_cpu_binding = True
mock_get_ascend_config.return_value = mock_ascend_config
# Create NPUWorker instance
from vllm_ascend.worker.worker import NPUWorker
_ = NPUWorker(
vllm_config=self.vllm_config_mock,
local_rank=self.local_rank,
rank=self.rank,
distributed_init_method=self.distributed_init_method,
is_driver_worker=self.is_driver_worker,
)
# Verify init_cached_hf_modules is called (trust_remote_code=True)
mock_init_cached_hf_modules.assert_not_called()
@patch("vllm_ascend.utils.adapt_patch")
@patch("vllm_ascend.ops")
@patch("vllm_ascend.worker.worker._register_atb_extensions")
@patch("vllm_ascend.worker.worker.register_ascend_customop")
@patch("vllm_ascend.worker.worker.get_ascend_config")
@patch("vllm_ascend.worker.worker.init_ascend_config")
@patch("vllm_ascend.worker.worker.check_ascend_device_type")
@patch(init_cached_hf_modules_path, create=True)
@patch("vllm_ascend.worker.worker.TorchNPUProfilerWrapper")
def test_init_npu_worker_with_custom_cache_dtype(
self,
mock_profiler_wrapper,
mock_init_cached_hf_modules,
mock_check_ascend_device_type,
mock_init_ascend_config,
mock_get_ascend_config,
mock_register_ascend_customop,
mock_register_atb_extensions,
mock_ops,
mock_adapt_patch,
):
"""Test NPUWorker initialization with custom cache_dtype"""
# Set custom cache_dtype
self.cache_config_mock.cache_dtype = "float32"
mock_ops.register_dummy_fusion_op.return_value = None
mock_ascend_config = MagicMock()
mock_ascend_config.enable_cpu_binding = True
mock_get_ascend_config.return_value = mock_ascend_config
# Create NPUWorker instance
from vllm_ascend.worker.worker import NPUWorker
with patch("vllm.utils.torch_utils.STR_DTYPE_TO_TORCH_DTYPE", {"float32": torch.float32}):
worker = NPUWorker(
vllm_config=self.vllm_config_mock,
local_rank=self.local_rank,
rank=self.rank,
distributed_init_method=self.distributed_init_method,
is_driver_worker=self.is_driver_worker,
)
# Verify cache_dtype is set to custom value
self.assertEqual(worker.cache_dtype, torch.float32)
def test_initialize_cache(self):
"""Test initialize_cache method"""
from vllm_ascend.worker.worker import NPUWorker
# Create a simple worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.cache_config = MagicMock()
# Test initialize_cache
worker.initialize_cache(100, 50)
# Verify parameter setting
self.assertEqual(worker.cache_config.num_gpu_blocks, 100)
self.assertEqual(worker.cache_config.num_cpu_blocks, 50)
@patch("vllm_ascend.worker.worker.CaMemAllocator")
@patch("vllm_ascend.worker.worker.get_ascend_config")
def test_wake_up_mode_enabled(self, mock_get_config, mock_allocator_class):
mock_config = MagicMock()
mock_config.weight_nz_mode = 0
mock_config.enable_sleep_mode_extra_cleanup = True
mock_get_config.return_value = mock_config
"""Test wake_up method when sleep mode is enabled"""
from vllm_ascend.worker.worker import NPUWorker
# Setup mock
mock_allocator = MagicMock()
mock_allocator_class.get_instance.return_value = mock_allocator
mock_hidden_size = MagicMock()
mock_hf_config = MagicMock()
mock_hf_config.hidden_size = mock_hidden_size
mock_model_config = MagicMock()
mock_model_config.hf_config = mock_hf_config
mock_vllm_config = MagicMock()
mock_vllm_config.model_config = mock_model_config
mock_model_runner = MagicMock()
mock_model_runner.model = MagicMock()
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.model_runner = mock_model_runner
worker.vllm_config = mock_vllm_config
worker._sleep_saved_buffers = {}
worker.sleep_wakeup_manager = MagicMock()
# Test wake_up method
worker.wake_up(tags=["test_tag"])
mock_allocator.wake_up.assert_called_once_with(tags=["test_tag"])
worker.sleep_wakeup_manager.wakeup.assert_called_once_with(["test_tag"])
@patch("vllm_ascend.worker.worker.current_platform")
@patch("vllm_ascend.worker.worker.MemorySnapshot")
@patch("vllm_ascend.worker.worker.NPUWorker._init_worker_distributed_environment")
@patch("vllm_ascend.worker.worker.init_device_properties_triton")
@patch("vllm_ascend.worker.worker.get_ascend_device_type")
@patch("torch.npu.set_device")
@patch("torch.npu.empty_cache")
@patch("torch.npu.mem_get_info")
def test_init_device(
self,
mock_mem_get_info,
mock_empty_cache,
mock_set_device,
mock_get_device_type,
mock_init_triton,
mock_init_dist_env,
mock_snapshot_cls,
mock_current_platform,
):
"""Test _init_device method"""
from vllm_ascend.worker.worker import AscendDeviceType, NPUWorker
# Setup mock
mock_mem_get_info.return_value = (1000, 2000)
mock_get_device_type.return_value = AscendDeviceType.A2
# Mock MemorySnapshot
mock_snapshot = MagicMock()
mock_snapshot.free_memory = 1000
mock_snapshot.total_memory = 2000
mock_snapshot_cls.return_value = mock_snapshot
# Mock current_platform for v0.24.0 init_device path
mock_current_platform.logical_device_id_to_visible_device_id.return_value = 0
mock_current_platform.device_type = "npu"
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.local_rank = 0
worker.model_config = MagicMock()
worker.model_config.seed = 42
worker.parallel_config = MagicMock()
worker.parallel_config.local_world_size = 0
worker.parallel_config.data_parallel_size = 1
worker.parallel_config.assigned_physical_gpu_ids = None
worker.parallel_config.distributed_executor_backend = "ray"
worker.vllm_config = MagicMock()
worker.vllm_config.kv_transfer_config = None
worker.cache_config = MagicMock()
worker.cache_config.gpu_memory_utilization = 0.5
# Test _init_device
result = worker._init_device()
mock_init_dist_env.assert_called_once()
self.assertEqual(str(result), "npu:0")
self.assertEqual(worker.init_snapshot, mock_snapshot)
self.assertEqual(worker.requested_memory, 2000 * 0.5)
def test_profile_start_stop(self):
"""Test profile method start and stop"""
from vllm_ascend.worker.worker import NPUWorker
profiler_config = ProfilerConfig(
profiler="torch",
torch_profiler_dir="/path/to/traces",
)
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.profiler_config = profiler_config
worker.rank = 0
mock_profiler = MagicMock()
worker.profiler = mock_profiler
with patch("vllm.distributed.utils.get_worker_rank_suffix", return_value="dp0_pp0_tp0_dcp0_ep0_rank0"):
worker.profile(is_start=True)
mock_profiler.start.assert_called_once()
worker.profile(is_start=False)
mock_profiler.stop.assert_called_once()
def test_profile_no_profiler_raises_error(self):
"""Test profile method raises exception when profiler is not available"""
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock - profiler_config indicates profiling disabled
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.profiler = None
worker.profiler_config = ProfilerConfig(profiler=None, torch_profiler_dir="")
# Test should raise exception
with self.assertRaises(RuntimeError) as cm:
worker.profile()
self.assertIn("Profiling is not enabled", str(cm.exception))
def test_profile_with_prefix_uses_trace_name(self):
"""[RFC #6954] profile() accepts profile_prefix and passes trace_name to TorchNPUProfilerWrapper"""
from vllm_ascend.worker.worker import NPUWorker
profiler_config = ProfilerConfig(
profiler="torch",
torch_profiler_dir="/path/to/traces",
)
vllm_config_mock = MagicMock()
vllm_config_mock.profiler_config = profiler_config
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.profiler_config = profiler_config
worker.profiler = None
worker.rank = 0
with (
patch("vllm.distributed.utils.get_worker_rank_suffix", return_value="dp0_pp0_tp0_dcp0_ep0_rank0"),
patch("vllm_ascend.worker.worker.TorchNPUProfilerWrapper") as mock_profiler_wrapper,
):
worker.profile(is_start=True, profile_prefix="warmup")
mock_profiler_wrapper.assert_called_once_with(
profiler_config,
"warmup_dp0_pp0_tp0_dcp0_ep0_rank0",
)
mock_profiler_wrapper.return_value.start.assert_called_once()
def test_profile_lazy_init(self):
"""[RFC #6954] Profiler is lazily created on first profile(is_start=True) call"""
from vllm_ascend.worker.worker import NPUWorker
profiler_config = ProfilerConfig(
profiler="torch",
torch_profiler_dir="/path/to/traces",
)
vllm_config_mock = MagicMock()
vllm_config_mock.profiler_config = profiler_config
with patch("vllm_ascend.worker.worker.TorchNPUProfilerWrapper") as mock_profiler_wrapper:
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.profiler_config = profiler_config
worker.profiler = None
worker.rank = 0
self.assertIsNone(worker.profiler)
mock_profiler_wrapper.assert_not_called()
with patch("vllm.distributed.utils.get_worker_rank_suffix", return_value="dp0_pp0_tp0_dcp0_ep0_rank0"):
worker.profile(is_start=True)
mock_profiler_wrapper.assert_called_once_with(
profiler_config,
"dp0_pp0_tp0_dcp0_ep0_rank0",
)
self.assertIs(worker.profiler, mock_profiler_wrapper.return_value)
mock_profiler_wrapper.return_value.start.assert_called_once()
def test_profile_restart_reuses_existing_profiler(self):
"""[RFC #6954] Restarting profile reuses existing profiler."""
from vllm_ascend.worker.worker import NPUWorker
profiler_config = ProfilerConfig(
profiler="torch",
torch_profiler_dir="/path/to/traces",
)
mock_profiler = MagicMock()
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.profiler_config = profiler_config
worker.profiler = None
worker.rank = 0
with (
patch("vllm.distributed.utils.get_worker_rank_suffix", return_value="dp0_pp0_tp0_dcp0_ep0_rank0"),
patch("vllm_ascend.worker.worker.TorchNPUProfilerWrapper", return_value=mock_profiler) as mock_wrapper,
):
worker.profile(is_start=True, profile_prefix="session1")
mock_wrapper.assert_called_once_with(
profiler_config,
"session1_dp0_pp0_tp0_dcp0_ep0_rank0",
)
worker.profile(is_start=False)
worker.profile(is_start=True) # Restart without new prefix
# Should NOT create new profiler, just restart existing
mock_wrapper.assert_called_once()
self.assertEqual(mock_profiler.start.call_count, 2)
mock_profiler.stop.assert_called_once()
@patch("vllm_ascend.worker.worker.logger")
def test_profile_stop_without_start_logs_warning(self, mock_logger):
"""Test stopping profiling before start logs a warning and returns."""
from vllm_ascend.worker.worker import NPUWorker
profiler_config = ProfilerConfig(
profiler="torch",
torch_profiler_dir="/path/to/traces",
)
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.profiler_config = profiler_config
worker.profiler = None
worker.profile(is_start=False)
mock_logger.warning.assert_called_once_with("Profiler was not started, nothing to stop.")
def test_lora_methods(self):
"""Test LoRA related methods"""
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
mock_model_runner = MagicMock()
worker.model_runner = mock_model_runner
# Set return values
mock_model_runner.add_lora.return_value = True
mock_model_runner.remove_lora.return_value = True
mock_model_runner.list_loras.return_value = {1, 2, 3}
mock_model_runner.pin_lora.return_value = True
# Test each method
mock_request = MagicMock()
self.assertTrue(worker.add_lora(mock_request))
mock_model_runner.add_lora.assert_called_once_with(mock_request)
self.assertTrue(worker.remove_lora(1))
mock_model_runner.remove_lora.assert_called_once_with(1)
self.assertEqual(worker.list_loras(), {1, 2, 3})
mock_model_runner.list_loras.assert_called_once()
self.assertTrue(worker.pin_lora(2))
mock_model_runner.pin_lora.assert_called_once_with(2)
def test_get_methods(self):
"""Test various get methods"""
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
mock_model_runner = MagicMock()
worker.model_runner = mock_model_runner
# Set return values
mock_model = MagicMock()
mock_kv_cache_spec = {"test": "spec"}
mock_pooling_tasks = ["task1", "task2"]
mock_supported_tasks = ("task1", "task2")
mock_model_runner.get_model.return_value = mock_model
mock_model_runner.get_kv_cache_spec.return_value = mock_kv_cache_spec
mock_model_runner.get_supported_pooling_tasks.return_value = mock_pooling_tasks
mock_model_runner.get_supported_tasks.return_value = mock_supported_tasks
# Test each get method
self.assertEqual(worker.get_model(), mock_model)
self.assertEqual(worker.get_kv_cache_spec(), mock_kv_cache_spec)
self.assertEqual(worker.get_supported_pooling_tasks(), mock_pooling_tasks)
self.assertEqual(worker.get_supported_tasks(), mock_supported_tasks)
def test_execute_dummy_batch(self):
"""Test execute_dummy_batch method"""
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.compilation_config = MagicMock()
worker.compilation_config.cudagraph_mode = MagicMock()
mock_model_runner = MagicMock()
mock_decode_token_per_req = mock_model_runner.decode_token_per_req
worker.model_runner = mock_model_runner
# Test execute_dummy_batch
worker.execute_dummy_batch()
# Verify call
mock_model_runner._dummy_run.assert_called_once_with(
num_tokens=mock_decode_token_per_req, uniform_decode=True
)
@patch("vllm_ascend.worker.worker.memory_profiling")
@patch("torch.npu.reset_peak_memory_stats")
@patch("torch.npu.empty_cache")
@patch("torch_npu.npu.memory_stats")
@patch("torch_npu.npu.mem_get_info")
@patch("vllm_ascend.worker.worker.logger")
def test_determine_available_memory_normal_case(
self,
mock_logger,
mock_torch_mem_get_info,
mock_torch_memory_stats,
mock_torch_empty_cache,
mock_torch_reset_peak_memory_stats,
mock_memory_profiling,
):
"""Test determine_available_memory normal case (no non-torch memory allocation)"""
from vllm_ascend.worker.worker import NPUWorker
# Mock memory_profiling context manager
mock_profile_result = MagicMock()
mock_profile_result.non_torch_increase = 1000
mock_profile_result.torch_peak_increase = 2000
mock_profile_result.weights_memory = 500
mock_profile_result.before_profile = MagicMock()
mock_profile_result.before_profile.torch_peak = 0
mock_profile_result.after_profile = MagicMock()
mock_profile_result.after_profile.free_memory = 6500
mock_context = MagicMock()
mock_context.__enter__ = MagicMock(return_value=mock_profile_result)
mock_context.__exit__ = MagicMock(return_value=False)
mock_memory_profiling.return_value = mock_context
# Mock init_snapshot
mock_init_snapshot = MagicMock()
mock_init_snapshot.free_memory = 8000
mock_init_snapshot.total_memory = 10000
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.init_snapshot = mock_init_snapshot
worker.requested_memory = 10000 * 0.8
worker.model_runner = MagicMock()
worker.model_runner.model_memory_usage = 500
worker.cache_config = MagicMock()
worker.cache_config.gpu_memory_utilization = 0.8
worker.cache_config.kv_cache_memory_bytes = None
worker.device = torch.device("npu:0")
# Mock torch.npu.memory_stats for profile_torch_peak
# profile_torch_peak = memory_stats()["allocated_bytes.all.peak"] = 2000
mock_torch_memory_stats.return_value = {"allocated_bytes.all.peak": 2000}
result = worker.determine_available_memory()
worker.model_runner.profile_run.assert_called_once()
# non_kv_cache_memory = non_torch_increase(1000) + torch_peak_increase(2000-0) + weights_memory(500) = 3500
# result = requested_memory(8000) - non_kv_cache_memory(3500) = 4500
expected_result = int(10000 * 0.8 - 3500)
self.assertEqual(result, expected_result)
@patch("vllm_ascend.worker.worker.memory_profiling")
@patch("torch.npu.reset_peak_memory_stats")
@patch("torch.npu.empty_cache")
@patch("torch_npu.npu.memory_stats")
@patch("torch_npu.npu.mem_get_info")
def test_determine_available_memory_with_non_torch_allocations(
self,
mock_torch_mem_get_info,
mock_torch_memory_stats,
mock_torch_empty_cache,
mock_torch_reset_peak_memory_stats,
mock_memory_profiling,
):
"""Test determine_available_memory with significant non-torch memory allocation"""
from vllm_ascend.worker.worker import NPUWorker
# Mock memory_profiling context manager with large non-torch allocation
mock_profile_result = MagicMock()
mock_profile_result.non_torch_increase = 4000
mock_profile_result.torch_peak_increase = 1500
mock_profile_result.weights_memory = 500
mock_profile_result.before_profile = MagicMock()
mock_profile_result.before_profile.torch_peak = 0
mock_profile_result.after_profile = MagicMock()
mock_profile_result.after_profile.free_memory = 4000
mock_context = MagicMock()
mock_context.__enter__ = MagicMock(return_value=mock_profile_result)
mock_context.__exit__ = MagicMock(return_value=False)
mock_memory_profiling.return_value = mock_context
# Mock init_snapshot
mock_init_snapshot = MagicMock()
mock_init_snapshot.free_memory = 8500
mock_init_snapshot.total_memory = 10000
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.init_snapshot = mock_init_snapshot
worker.requested_memory = 10000 * 0.9
worker.model_runner = MagicMock()
worker.model_runner.model_memory_usage = 500
worker.cache_config = MagicMock()
worker.cache_config.gpu_memory_utilization = 0.9
worker.cache_config.kv_cache_memory_bytes = None
worker.device = torch.device("npu:0")
mock_torch_memory_stats.return_value = {"allocated_bytes.all.peak": 1500}
result = worker.determine_available_memory()
# non_kv_cache_memory = non_torch_increase(4000) + torch_peak_increase(1500-0) + weights_memory(500) = 6000
# result = requested_memory(9000) - non_kv_cache_memory(6000) = 3000
expected_result = int(10000 * 0.9 - 6000)
self.assertEqual(result, expected_result)
@patch("vllm_ascend.worker.worker.memory_profiling")
@patch("torch.npu.mem_get_info")
@patch("torch.npu.reset_peak_memory_stats")
@patch("torch.npu.empty_cache")
def test_determine_available_memory_memory_profiling_error(
self, mock_torch_empty_cache, mock_torch_reset_peak_memory_stats, mock_torch_mem_get_info, mock_memory_profiling
):
"""Test determine_available_memory throws exception on memory profiling error"""
from vllm_ascend.worker.worker import NPUWorker
# Mock memory_profiling where free memory after profile > init free memory (error case)
mock_profile_result = MagicMock()
mock_profile_result.non_kv_cache_memory = 2000
mock_profile_result.after_profile = MagicMock()
mock_profile_result.after_profile.free_memory = 9000 # More free than init!
mock_profile_result.non_torch_increase = 0
mock_profile_result.torch_peak_increase = 0
mock_profile_result.weights_memory = 0
mock_context = MagicMock()
mock_context.__enter__ = MagicMock(return_value=mock_profile_result)
mock_context.__exit__ = MagicMock(return_value=False)
mock_memory_profiling.return_value = mock_context
mock_init_snapshot = MagicMock()
mock_init_snapshot.free_memory = 8500 # Less than after_profile free (9000)
mock_init_snapshot.total_memory = 10000
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.init_snapshot = mock_init_snapshot
worker.requested_memory = 10000 * 0.8
worker.model_runner = MagicMock()
worker.cache_config = MagicMock()
worker.cache_config.gpu_memory_utilization = 0.8
worker.cache_config.kv_cache_memory_bytes = None
worker.device = torch.device("npu:0")
# Test should throw assertion error
with self.assertRaises(AssertionError) as cm:
worker.determine_available_memory()
self.assertIn("Error in memory profiling", str(cm.exception))
@patch("vllm_ascend.worker.worker.memory_profiling")
@patch("torch.npu.reset_peak_memory_stats")
@patch("torch.npu.empty_cache")
@patch("torch_npu.npu.memory_stats")
@patch("torch_npu.npu.mem_get_info")
def test_determine_available_memory_negative_result(
self,
mock_torch_mem_get_info,
mock_torch_memory_stats,
mock_torch_empty_cache,
mock_torch_reset_peak_memory_stats,
mock_memory_profiling,
):
"""Test determine_available_memory returns 0 when result is negative"""
from vllm_ascend.worker.worker import NPUWorker
# Mock memory_profiling where non_kv_cache_memory > requested_memory
mock_profile_result = MagicMock()
mock_profile_result.non_torch_increase = 1000
mock_profile_result.torch_peak_increase = 9000
mock_profile_result.weights_memory = 500
mock_profile_result.before_profile = MagicMock()
mock_profile_result.before_profile.torch_peak = 0
mock_profile_result.after_profile = MagicMock()
mock_profile_result.after_profile.free_memory = 2000
mock_context = MagicMock()
mock_context.__enter__ = MagicMock(return_value=mock_profile_result)
mock_context.__exit__ = MagicMock(return_value=False)
mock_memory_profiling.return_value = mock_context
# Mock init_snapshot
mock_init_snapshot = MagicMock()
mock_init_snapshot.free_memory = 8500
mock_init_snapshot.total_memory = 10000
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.init_snapshot = mock_init_snapshot
worker.requested_memory = 10000 * 0.8
worker.model_runner = MagicMock()
worker.model_runner.model_memory_usage = 500
worker.cache_config = MagicMock()
worker.cache_config.gpu_memory_utilization = 0.8
worker.cache_config.kv_cache_memory_bytes = None
worker.device = torch.device("npu:0")
mock_torch_memory_stats.return_value = {"allocated_bytes.all.peak": 9000}
result = worker.determine_available_memory()
# non_kv_cache_memory = 1000 + 9000 + 500 = 10500
# available = requested(8000) - non_kv_cache(10500) = -2500
# upstream no longer clamps to 0, returns int(negative)
self.assertEqual(result, int(8000 - 10500))
def test_execute_model_first_rank(self):
"""Test execute_model method - first rank case"""
from vllm.v1.outputs import ModelRunnerOutput
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with (
patch.object(NPUWorker, "__init__", lambda x, **kwargs: None),
patch("vllm_ascend.worker.worker.get_pp_group") as mock_get_pp_group,
patch("vllm_ascend.worker.worker.get_ascend_config") as mock_get_ascend_config,
):
mock_ascend_config = MagicMock()
mock_ascend_config.msmonitor_use_daemon = False
mock_get_ascend_config.return_value = mock_ascend_config
worker = NPUWorker()
worker.model_runner = MagicMock()
worker.vllm_config = MagicMock()
worker.vllm_config.parallel_config = MagicMock()
worker.vllm_config.parallel_config.distributed_executor_backend = "ray"
worker.profiler = None
worker._pp_send_work = []
# Set as first rank
mock_pp_group = MagicMock()
mock_pp_group.is_first_rank = True
mock_pp_group.is_last_rank = True
mock_get_pp_group.return_value = mock_pp_group
# Mock scheduler_output and return result
mock_scheduler_output = MagicMock()
mock_scheduler_output.total_num_scheduled_tokens = 1
mock_model_output = MagicMock(spec=ModelRunnerOutput)
worker.model_runner.execute_model.return_value = mock_model_output
# Test execute_model
result = worker.execute_model(mock_scheduler_output)
# Verify call
worker.model_runner.execute_model.assert_called_once_with(mock_scheduler_output, None)
self.assertEqual(result, mock_model_output)
def test_execute_model_calls_profiler_step_when_enabled(self):
"""Test execute_model steps the profiler before model execution."""
from vllm.v1.outputs import ModelRunnerOutput
from vllm_ascend.worker.worker import NPUWorker
call_order = []
# Create worker mock
with (
patch.object(NPUWorker, "__init__", lambda x, **kwargs: None),
patch("vllm_ascend.worker.worker.get_pp_group") as mock_get_pp_group,
patch("vllm_ascend.worker.worker.get_ascend_config") as mock_get_ascend_config,
):
mock_ascend_config = MagicMock()
mock_ascend_config.msmonitor_use_daemon = False
mock_get_ascend_config.return_value = mock_ascend_config
worker = NPUWorker()
worker.model_runner = MagicMock()
worker.vllm_config = MagicMock()
worker.vllm_config.parallel_config = MagicMock()
worker.vllm_config.parallel_config.distributed_executor_backend = "ray"
worker.profiler = MagicMock()
worker.profiler.step.side_effect = lambda: call_order.append("step")
worker._pp_send_work = []
mock_pp_group = MagicMock()
mock_pp_group.is_first_rank = True
mock_pp_group.is_last_rank = True
mock_get_pp_group.return_value = mock_pp_group
mock_scheduler_output = MagicMock()
mock_scheduler_output.total_num_scheduled_tokens = 1
mock_model_output = MagicMock(spec=ModelRunnerOutput)
def execute_model(*args):
call_order.append("execute")
return mock_model_output
worker.model_runner.execute_model.side_effect = execute_model
result = worker.execute_model(mock_scheduler_output)
worker.profiler.step.assert_called_once()
worker.model_runner.execute_model.assert_called_once_with(mock_scheduler_output, None)
self.assertEqual(call_order, ["step", "execute"])
self.assertEqual(result, mock_model_output)
@patch("vllm_ascend.worker.worker.get_ascend_config")
@patch("vllm_ascend.worker.worker.enable_sp", return_value=False)
@patch("vllm_ascend.worker.worker.get_pp_group")
@patch("vllm_ascend.worker.worker.get_tp_group")
def test_execute_model_middle_rank(
self, mock_get_tp_group, mock_get_pp_group, mock_enable_sp, mock_get_ascend_config
):
"""Test execute_model method - middle rank case"""
from vllm.sequence import IntermediateTensors
mock_ascend_config = MagicMock()
mock_ascend_config.msmonitor_use_daemon = False
mock_get_ascend_config.return_value = mock_ascend_config
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.model_runner = MagicMock()
worker.vllm_config = MagicMock()
worker.vllm_config.parallel_config = MagicMock()
worker.vllm_config.parallel_config.distributed_executor_backend = "ray"
worker.profiler = None
worker._pp_send_work = []
# Set as middle rank (not first, not last)
mock_pp_group = MagicMock()
mock_pp_group.is_first_rank = False
mock_pp_group.is_last_rank = False
mock_get_pp_group.return_value = mock_pp_group
# Setup tensor reception data
mock_pp_group.irecv_tensor_dict.return_value = ({"tensor": "data"}, None, None)
mock_pp_group.isend_tensor_dict.return_value = []
# Mock return IntermediateTensors - use real type
mock_intermediate_output = MagicMock(spec=IntermediateTensors)
mock_intermediate_output.tensors = {"output_tensor": "data"}
mock_intermediate_output.kv_connector_output = None # Set to None to trigger return None
worker.model_runner.execute_model.return_value = mock_intermediate_output
mock_scheduler_output = MagicMock()
mock_scheduler_output.total_num_scheduled_tokens = 1
# Test execute_model
result = worker.execute_model(mock_scheduler_output)
# Verify tensor reception
mock_pp_group.irecv_tensor_dict.assert_called_once()
# Verify model execution with intermediate_tensors
# Second parameter should be AsyncIntermediateTensors instance
worker.model_runner.execute_model.assert_called_once()
args, kwargs = worker.model_runner.execute_model.call_args
self.assertEqual(args[0], mock_scheduler_output)
# Verify tensor sending
mock_pp_group.isend_tensor_dict.assert_called_once()
# Middle rank without kv_transfer_group should return None
self.assertIsNone(result)
def test_execute_model_external_launcher(self):
"""Test execute_model method - external_launcher mode"""
from vllm.v1.outputs import ModelRunnerOutput
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with (
patch.object(NPUWorker, "__init__", lambda x, **kwargs: None),
patch("vllm_ascend.worker.worker.get_pp_group") as mock_get_pp_group,
patch("vllm_ascend.worker.worker.get_ascend_config") as mock_get_ascend_config,
):
mock_ascend_config = MagicMock()
mock_ascend_config.msmonitor_use_daemon = False
mock_get_ascend_config.return_value = mock_ascend_config
worker = NPUWorker()
worker.model_runner = MagicMock()
worker.vllm_config = MagicMock()
worker.vllm_config.parallel_config = MagicMock()
worker.vllm_config.parallel_config.distributed_executor_backend = "external_launcher"
worker.profiler = None
worker._pp_send_work = []
# Set as non-last rank
mock_pp_group = MagicMock()
mock_pp_group.is_first_rank = True
mock_pp_group.is_last_rank = False
mock_get_pp_group.return_value = mock_pp_group
# Mock return result
mock_scheduler_output = MagicMock()
mock_scheduler_output.total_num_scheduled_tokens = 1
mock_model_output = MagicMock(spec=ModelRunnerOutput)
worker.model_runner.execute_model.return_value = mock_model_output
# Test execute_model
result = worker.execute_model(mock_scheduler_output)
# In external_launcher mode, it doesn't enter middle processing logic, returns result directly
self.assertEqual(result, mock_model_output)
@patch("vllm_ascend.worker.worker.CaMemAllocator")
def test_load_model_with_sleep_mode(self, mock_allocator_class):
"""Test load_model method - with sleep mode enabled"""
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.model_runner = MagicMock()
worker.vllm_config = MagicMock()
worker.vllm_config.model_config = MagicMock()
worker.vllm_config.model_config.enable_sleep_mode = True
worker.vllm_config.weight_transfer_config = None
worker.vllm_config.kv_transfer_config = None
# Setup allocator mock
mock_allocator = MagicMock()
mock_allocator.get_current_usage.return_value = 0
mock_context = MagicMock()
mock_allocator.use_memory_pool.return_value = mock_context
mock_allocator_class.get_instance.return_value = mock_allocator
# Test load_model
worker.load_model()
# Verify calls
mock_allocator_class.get_instance.assert_called_once()
mock_allocator.get_current_usage.assert_called_once()
mock_allocator.use_memory_pool.assert_called_once_with(tag="weights")
worker.model_runner.load_model.assert_called_once()
def test_load_model_without_sleep_mode(self):
"""Test load_model method - without sleep mode enabled"""
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.model_runner = MagicMock()
worker.vllm_config = MagicMock()
worker.vllm_config.model_config = MagicMock()
worker.vllm_config.model_config.enable_sleep_mode = False
worker.vllm_config.weight_transfer_config = None
# Test load_model
worker.load_model()
# Verify calls
worker.model_runner.load_model.assert_called_once()
@patch("vllm_ascend.worker.worker.CaMemAllocator")
def test_load_model_sleep_mode_assertion_error(self, mock_allocator_class):
"""Test load_model method - assertion error in sleep mode"""
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.model_runner = MagicMock()
worker.vllm_config = MagicMock()
worker.vllm_config.model_config = MagicMock()
worker.vllm_config.model_config.enable_sleep_mode = True
# Setup allocator mock - current usage is not 0
mock_allocator = MagicMock()
mock_allocator.get_current_usage.return_value = 100 # Non-zero value
mock_allocator_class.get_instance.return_value = mock_allocator
# Test should throw assertion error
with self.assertRaises(AssertionError) as cm:
worker.load_model()
self.assertIn("Sleep mode can only be", str(cm.exception))
@patch("vllm_ascend.worker.worker.set_random_seed")
@patch("vllm_ascend.worker.worker.get_ascend_device_type")
@patch("vllm_ascend.worker.worker.AscendDeviceType")
@patch("vllm_ascend.worker.worker.get_ascend_config")
@patch("vllm_ascend.worker.worker.logger")
@patch("vllm_ascend.worker.worker.NPUWorker._warm_up_atb")
def test_compile_or_warm_up_model_with_eager_mode(
self,
mock_warm_up_atb,
mock_logger,
mock_get_ascend_config,
mock_ascend_device_type,
mock_get_ascend_device_type,
mock_set_random_seed,
):
"""Test compile_or_warm_up_model method - eager mode"""
mock_ascend_config = MagicMock()
mock_ascend_config.ascend_compilation_config = MagicMock()
mock_ascend_config.ascend_compilation_config.enable_npugraph_ex = False
mock_ascend_config.enable_cpu_binding = False
mock_get_ascend_config.return_value = mock_ascend_config
mock_get_ascend_device_type.return_value = mock_ascend_device_type.A9B
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.model_runner = MagicMock()
worker.vllm_config = MagicMock()
worker.model_config = MagicMock()
worker.model_config.enforce_eager = True
worker.model_config.seed = 12345
worker.cache_config = MagicMock()
worker.cache_config.kv_cache_memory_bytes = 1024
# Setup compilation config
worker.vllm_config.compilation_config = MagicMock()
worker.vllm_config.compilation_config.compile_sizes = [1, 4, 8, 16]
worker.vllm_config.compilation_config.cudagraph_capture_sizes = [4, 8]
# Test compile_or_warm_up_model
worker.compile_or_warm_up_model()
# Verify _dummy_run call count and order (by size descending)
expected_calls = [
unittest.mock.call(16),
unittest.mock.call(8),
unittest.mock.call(4),
unittest.mock.call(1),
]
worker.model_runner._dummy_run.assert_has_calls(expected_calls)
# Should not call capture_model in eager mode
worker.model_runner.capture_model.assert_not_called()
# Verify log output
self.assertEqual(mock_logger.info.call_count, 4)
# Verify atb warm up
mock_warm_up_atb.assert_called_once()
@patch("vllm_ascend.worker.worker.set_random_seed")
@patch("vllm_ascend.worker.worker.get_ascend_device_type")
@patch("vllm_ascend.worker.worker.AscendDeviceType")
@patch("vllm_ascend.worker.worker.CUDAGraphMode")
@patch("vllm_ascend.worker.worker.get_ascend_config")
@patch("vllm_ascend.worker.worker.logger")
@patch("vllm_ascend.worker.worker.NPUWorker._warm_up_atb")
def test_compile_or_warm_up_model_with_graph_capture(
self,
mock_warm_up_atb,
mock_logger,
mock_get_ascend_config,
mock_cudagraph_mode,
mock_ascend_device_type,
mock_get_ascend_device_type,
mock_set_random_seed,
):
"""Test compile_or_warm_up_model method - with graph capture enabled"""
mock_ascend_config = MagicMock()
mock_ascend_config.ascend_compilation_config = MagicMock()
mock_ascend_config.ascend_compilation_config.enable_npugraph_ex = False
mock_ascend_config.enable_cpu_binding = False
mock_get_ascend_config.return_value = mock_ascend_config
mock_get_ascend_device_type.return_value = mock_ascend_device_type.A9B
mock_cudagraph_mode.NONE = mock_cudagraph_mode.NONE
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.model_runner = MagicMock()
worker.vllm_config = MagicMock()
worker.model_config = MagicMock()
worker.model_config.enforce_eager = False # Enable graph capture
worker.model_config.seed = 67890
worker.cache_config = MagicMock()
worker.cache_config.kv_cache_memory_bytes = 1024
# Setup compilation config
worker.vllm_config.compilation_config = MagicMock()
worker.vllm_config.compilation_config.compile_sizes = [1, 4, 8, 16]
worker.vllm_config.compilation_config.cudagraph_capture_sizes = [4, 8]
worker.vllm_config.compilation_config.cudagraph_mode = mock_cudagraph_mode.FULL
worker.vllm_config.compilation_config.get_compile_ranges.return_value = []
# Test compile_or_warm_up_model
worker.compile_or_warm_up_model()
# Verify only call _dummy_run for sizes not in cudagraph_capture_sizes
expected_calls = [unittest.mock.call(16), unittest.mock.call(1)]
worker.model_runner._dummy_run.assert_has_calls(expected_calls)
# Should call capture_model in non-eager mode
worker.model_runner.capture_model.assert_called_once()
# Verify atb warm up
mock_warm_up_atb.assert_called_once()
@patch("vllm_ascend.worker.worker.ensure_kv_transfer_initialized")
@patch("vllm_ascend.worker.worker.CaMemAllocator")
def test_initialize_from_config_with_sleep_mode(self, mock_allocator_class, mock_ensure_kv_transfer):
"""Test initialize_from_config method - with sleep mode enabled"""
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with (
patch.object(NPUWorker, "__init__", lambda x, **kwargs: None),
patch("vllm_ascend.worker.worker.ensure_kv_transfer_initialized"),
):
worker = NPUWorker()
worker.model_runner = MagicMock()
worker.vllm_config = MagicMock()
worker.vllm_config.speculative_config = None
worker.vllm_config.model_config = MagicMock()
worker.vllm_config.model_config.enable_sleep_mode = True
worker.vllm_config.kv_transfer_config = None
# Setup allocator mock
mock_allocator = MagicMock()
mock_context = MagicMock()
mock_allocator.use_memory_pool.return_value = mock_context
mock_allocator_class.get_instance.return_value = mock_allocator
# Create mock kv_cache_config
mock_kv_cache_config = MagicMock()
# Test initialize_from_config
worker.initialize_from_config(mock_kv_cache_config)
# Verify calls
mock_allocator_class.get_instance.assert_called_once()
mock_allocator.use_memory_pool.assert_called_once_with(tag="kv_cache")
worker.model_runner.initialize_kv_cache.assert_called_once_with(mock_kv_cache_config)
def test_acl_graph_sleep_wakeup_manager_sleep_resets_acl_graph_state(self):
from vllm_ascend.device_allocator.sleep_mem_optimized import AclGraphSleepWakeupManager
model_runner = MagicMock()
model_runner.use_aclgraph = True
graph_manager = MagicMock()
graph_manager.graphs = MagicMock()
graph_manager.pool = None
model_runner.cudagraph_manager = graph_manager
saver = AclGraphSleepWakeupManager(MagicMock(), lambda: model_runner)
with (
patch(
"vllm_ascend.device_allocator.sleep_mem_optimized.AclGraphSleepWakeupManager"
".clear_all_attention_workspaces"
) as mock_clear,
patch(
"vllm_ascend.device_allocator.sleep_mem_optimized.AclGraphSleepWakeupManager.reset_all_graph_params"
) as mock_reset,
):
saver.sleep()
mock_clear.assert_called_once()
mock_reset.assert_called_once()
graph_manager.graphs.clear.assert_called_once()
def test_hccl_sleep_wakeup_manager_sleep_waits_and_destroys(self):
from vllm_ascend.device_allocator.sleep_mem_optimized import HcclSleepWakeupManager
worker = MagicMock()
handle = MagicMock()
worker._pp_send_work = [handle]
saver = HcclSleepWakeupManager(MagicMock(), worker)
saver._destroyed = False
with (
patch("vllm_ascend.device_allocator.sleep_mem_optimized.torch.distributed.is_available", return_value=True),
patch(
"vllm_ascend.device_allocator.sleep_mem_optimized.torch.distributed.is_initialized",
return_value=True,
),
patch("vllm_ascend.device_allocator.sleep_mem_optimized.torch.npu.synchronize") as mock_synchronize,
patch(
"vllm_ascend.device_allocator.sleep_mem_optimized.HcclSleepWakeupManager.destroy_hccl",
return_value=2,
) as mock_destroy,
):
saver.sleep()
handle.wait.assert_called_once()
self.assertEqual(worker._pp_send_work, [])
mock_synchronize.assert_called_once()
mock_destroy.assert_called_once()
@patch("vllm_ascend.worker.worker.ensure_kv_transfer_initialized")
def test_initialize_from_config_without_sleep_mode(self, mock_ensure_kv_transfer):
"""Test initialize_from_config method - without sleep mode enabled"""
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with (
patch.object(NPUWorker, "__init__", lambda x, **kwargs: None),
patch("vllm_ascend.worker.worker.ensure_kv_transfer_initialized"),
):
worker = NPUWorker()
worker.model_runner = MagicMock()
worker.vllm_config = MagicMock()
worker.vllm_config.speculative_config = None
worker.vllm_config.model_config = MagicMock()
worker.vllm_config.model_config.enable_sleep_mode = False
worker.vllm_config.kv_transfer_config = None
# Create mock kv_cache_config
mock_kv_cache_config = MagicMock()
# Test initialize_from_config
worker.initialize_from_config(mock_kv_cache_config)
# Verify calls
worker.model_runner.initialize_kv_cache.assert_called_once_with(mock_kv_cache_config)
@patch("vllm_ascend.worker.worker.get_ascend_config")
@patch("vllm_ascend.worker.worker.enable_sp", return_value=False)
@patch("vllm_ascend.worker.worker.get_pp_group")
@patch("vllm_ascend.worker.worker.get_tp_group")
@patch("vllm_ascend.worker.worker.EMPTY_MODEL_RUNNER_OUTPUT")
def test_execute_model_kv_connector_not_finished(
self, mock_empty_output, mock_get_tp_group, mock_get_pp_group, mock_enable_sp, mock_get_ascend_config
):
"""Test execute_model method - kv_connector_output not finished sending/recving case"""
from vllm.sequence import IntermediateTensors
mock_ascend_config = MagicMock()
mock_ascend_config.msmonitor_use_daemon = False
mock_get_ascend_config.return_value = mock_ascend_config
from vllm_ascend.worker.worker import NPUWorker
# Create worker mock
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.model_runner = MagicMock()
worker.vllm_config = MagicMock()
worker.vllm_config.parallel_config = MagicMock()
worker.vllm_config.parallel_config.distributed_executor_backend = "ray"
worker.profiler = None
worker._pp_send_work = []
# Set as middle rank (not first, not last)
mock_pp_group = MagicMock()
mock_pp_group.is_first_rank = False
mock_pp_group.is_last_rank = False
mock_get_pp_group.return_value = mock_pp_group
# Setup tensor reception data
mock_pp_group.irecv_tensor_dict.return_value = ({"tensor": "data"}, None, None)
mock_pp_group.isend_tensor_dict.return_value = []
# Create mock kv_connector_output - both finished_sending and finished_recving are False
mock_kv_connector_output = MagicMock()
mock_kv_connector_output.finished_sending = False
mock_kv_connector_output.finished_recving = False
# Mock return IntermediateTensors with kv_connector_output
mock_intermediate_output = MagicMock(spec=IntermediateTensors)
mock_intermediate_output.tensors = {"output_tensor": "data"}
mock_intermediate_output.kv_connector_output = mock_kv_connector_output
worker.model_runner.execute_model.return_value = mock_intermediate_output
mock_scheduler_output = MagicMock()
mock_scheduler_output.total_num_scheduled_tokens = 1
# Test execute_model
result = worker.execute_model(mock_scheduler_output)
# Verify tensor reception and sending
mock_pp_group.irecv_tensor_dict.assert_called_once()
mock_pp_group.isend_tensor_dict.assert_called_once()
# When both flags are False, return EMPTY_MODEL_RUNNER_OUTPUT directly.
self.assertEqual(result, mock_empty_output)
class TestNPUWorkerWeightUpdate(TestBase):
def _make_worker(self, engine=None):
from vllm_ascend.worker.worker import NPUWorker
with patch.object(NPUWorker, "__init__", lambda x, **kwargs: None):
worker = NPUWorker()
worker.weight_transfer_engine = engine
worker._weight_update_active = False
worker._is_checkpoint_format = True
worker.device = torch.device("cpu")
worker.model_runner = MagicMock()
worker.model_runner.model = MagicMock()
worker.model_config = MagicMock()
return worker
def test_check_engine_raises_when_unconfigured(self):
worker = self._make_worker(engine=None)
with self.assertRaises(RuntimeError):
worker.init_weight_transfer_engine({})
with self.assertRaises(RuntimeError):
worker.start_weight_update()
with self.assertRaises(RuntimeError):
worker.update_weights({})
with self.assertRaises(RuntimeError):
worker.finish_weight_update()
def test_init_weight_transfer_engine_dispatches_to_engine(self):
engine = MagicMock()
engine.parse_init_info.return_value = "typed_init"
worker = self._make_worker(engine=engine)
init_info = {"master_address": "127.0.0.1", "master_port": 12345}
worker.init_weight_transfer_engine(init_info)
engine.parse_init_info.assert_called_once_with(init_info)
engine.init_transfer_engine.assert_called_once_with("typed_init")
@patch("vllm.model_executor.model_loader.reload.initialize_layerwise_reload")
@patch.dict("os.environ", {"VLLM_ASCEND_ENABLE_NZ": "0"})
def test_start_weight_update_checkpoint_format(self, mock_init_reload):
engine = MagicMock()
worker = self._make_worker(engine=engine)
worker.start_weight_update(is_checkpoint_format=True)
mock_init_reload.assert_called_once_with(worker.model_runner.model)
self.assertTrue(worker._weight_update_active)
self.assertTrue(worker._is_checkpoint_format)
@patch("vllm.model_executor.model_loader.reload.initialize_layerwise_reload")
@patch.dict("os.environ", {"VLLM_ASCEND_ENABLE_NZ": "0"})
def test_start_weight_update_kernel_format(self, mock_init_reload):
engine = MagicMock()
worker = self._make_worker(engine=engine)
worker.start_weight_update(is_checkpoint_format=False)
mock_init_reload.assert_not_called()
self.assertTrue(worker._weight_update_active)
self.assertFalse(worker._is_checkpoint_format)
@patch.dict("os.environ", {"VLLM_ASCEND_ENABLE_NZ": "0"})
def test_start_weight_update_rejects_reentry(self):
engine = MagicMock()
worker = self._make_worker(engine=engine)
worker._weight_update_active = True
with self.assertRaises(RuntimeError):
worker.start_weight_update()
@patch.dict("os.environ", {"VLLM_ASCEND_ENABLE_NZ": "1"})
def test_start_weight_update_rejects_nz(self):
engine = MagicMock()
worker = self._make_worker(engine=engine)
with self.assertRaises(ValueError):
worker.start_weight_update()
def test_update_weights_requires_start(self):
engine = MagicMock()
worker = self._make_worker(engine=engine)
with self.assertRaises(RuntimeError):
worker.update_weights({"names": [], "dtype_names": [], "shapes": []})
@patch("torch.npu.synchronize", create=True)
@patch("vllm.model_executor.model_loader.reload.finalize_layerwise_reload")
@patch("vllm.model_executor.model_loader.reload.initialize_layerwise_reload")
@patch.dict("os.environ", {"VLLM_ASCEND_ENABLE_NZ": "0"})
def test_update_weights_checkpoint_format(self, mock_init_reload, mock_finalize_reload, mock_sync):
engine = MagicMock()
worker = self._make_worker(engine=engine)
engine.parse_update_info.return_value = "typed_update"
worker._weight_update_active = True
worker._is_checkpoint_format = True
worker.update_weights({"foo": "bar"})
engine.parse_update_info.assert_called_once_with({"foo": "bar"})
engine.receive_weights.assert_called_once()
_, kwargs = engine.receive_weights.call_args
self.assertIs(kwargs["load_weights"], worker.model_runner.model.load_weights)
mock_sync.assert_called_once()
# reload lifecycle is split across start_weight_update / finish_weight_update
mock_init_reload.assert_not_called()
mock_finalize_reload.assert_not_called()
@patch("torch.npu.synchronize", create=True)
@patch.dict("os.environ", {"VLLM_ASCEND_ENABLE_NZ": "0"})
def test_update_weights_kernel_format(self, mock_sync):
engine = MagicMock()
def fake_receive(update_info, load_weights):
load_weights([("layer.weight", torch.zeros(2))])
engine.receive_weights.side_effect = fake_receive
worker = self._make_worker(engine=engine)
param = torch.nn.Parameter(torch.ones(2), requires_grad=True)
worker.model_runner.model.get_parameter.return_value = param
engine.parse_update_info.return_value = "typed_update"
worker._weight_update_active = True
worker._is_checkpoint_format = False
worker.update_weights({"foo": "bar"})
worker.model_runner.model.get_parameter.assert_called_once_with("layer.weight")
torch.testing.assert_close(param.detach(), torch.zeros(2))
self.assertTrue(param.requires_grad)
@patch("vllm.model_executor.model_loader.reload.finalize_layerwise_reload")
def test_finish_weight_update_resets_state(self, mock_finalize_reload):
engine = MagicMock()
worker = self._make_worker(engine=engine)
worker._weight_update_active = True
worker._is_checkpoint_format = True
worker.finish_weight_update()
mock_finalize_reload.assert_called_once_with(worker.model_runner.model, worker.model_config)
self.assertFalse(worker._weight_update_active)
self.assertTrue(worker._is_checkpoint_format)
def test_finish_without_start_raises(self):
engine = MagicMock()
worker = self._make_worker(engine=engine)
with self.assertRaises(RuntimeError):
worker.finish_weight_update()
def test_double_finish_raises(self):
engine = MagicMock()
worker = self._make_worker(engine=engine)
worker._weight_update_active = True
worker._is_checkpoint_format = False
worker.finish_weight_update()
with self.assertRaises(RuntimeError):
worker.finish_weight_update()
@patch("torch.npu.synchronize", create=True)
def test_update_after_finish_requires_restart(self, _mock_sync):
engine = MagicMock()
engine.parse_update_info.return_value = "typed"
worker = self._make_worker(engine=engine)
worker._weight_update_active = True
worker._is_checkpoint_format = False
worker.finish_weight_update()
with self.assertRaises(RuntimeError):
worker.update_weights({"names": [], "dtype_names": [], "shapes": []})
@patch("vllm.distributed.kv_transfer.ensure_kv_transfer_shutdown", create=True)
def test_shutdown_releases_engine(self, _mock_kv_shutdown):
engine = MagicMock()
worker = self._make_worker(engine=engine)
worker.profiler = None
worker.shutdown()
engine.shutdown.assert_called_once()