Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions afd_plugin/compat/npu/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ def apply_afd_ascend_patches_if_needed() -> None:
apply_afd_ascend_dbo_config_patch,
)

apply_afd_ascend_dbo_config_patch()
_PATCHES_APPLIED = True
if apply_afd_ascend_dbo_config_patch():
_PATCHES_APPLIED = True


__all__ = [
Expand Down
100 changes: 52 additions & 48 deletions afd_plugin/compat/patches/config_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,74 +49,78 @@ def create_engine_config(
"""Create the VllmConfig."""

assert _original_create_engine_config is not None
if not _should_relax_engine_args_backend(self):
return _original_create_engine_config(
self,
usage_context,
headless,
)
# ### PATCH START: AFD automatic worker selection
worker_cls_was_auto = _uses_auto_worker_value(self.worker_cls)
# ### PATCH END: AFD automatic worker selection
# ### PATCH START: AFD Ascend config patch ordering
if parse_optional_afd_config(self.additional_config) is not None:
from vllm.platforms import current_platform

# ### PATCH START: AFD ubatching all2all backend validation
# vLLM validates native ubatching against DeepEP backends. AFD ubatching
# uses plugin connectors, so temporarily present a supported backend only
# while upstream builds and validates VllmConfig.
original_backend = self.all2all_backend
self.all2all_backend = _AFD_TEMP_BACKEND
try:
if current_platform.device_type == "npu":
from afd_plugin.compat.npu import apply_afd_ascend_patches_if_needed

apply_afd_ascend_patches_if_needed()
# ### PATCH END: AFD Ascend config patch ordering
if not _should_relax_engine_args_backend(self):
config = _original_create_engine_config(
self,
usage_context,
headless,
)
finally:
self.all2all_backend = original_backend
config.parallel_config.all2all_backend = original_backend
# ### PATCH END: AFD ubatching all2all backend validation
else:
# ### PATCH START: AFD ubatching all2all backend validation
# vLLM validates native ubatching against DeepEP backends. AFD ubatching
# uses plugin connectors, so temporarily present a supported backend while
# upstream builds and validates VllmConfig. The Ascend platform wrapper
# preserves this temporary value across its default-worker normalization.
original_backend = self.all2all_backend
self.all2all_backend = _AFD_TEMP_BACKEND
try:
config = _original_create_engine_config(
self,
usage_context,
headless,
)
finally:
self.all2all_backend = original_backend
config.parallel_config.all2all_backend = original_backend
# ### PATCH END: AFD ubatching all2all backend validation

# ### PATCH START: AFD automatic worker selection
if worker_cls_was_auto:
_select_afd_worker_for_auto(config)
# ### PATCH END: AFD automatic worker selection
return config


# Patch reason: VllmConfig validation can rerun the native ubatching all2all
# backend assertion after EngineArgs construction, and upstream auto-selects a
# platform worker that does not contain AFD role behavior.
# Patch functionality: temporarily relaxes the backend assertion for AFD
# configs, restores the real backend, then replaces an auto-selected platform
# worker with the platform- and role-specific AFD worker.
# Patch reason: EngineCore handshakes explicitly rerun VllmConfig.__post_init__
# after the config's actual AFD all2all backend has been restored.
# Patch functionality: temporarily presents a validation-safe backend during
# explicit AFD ubatching revalidation, then restores the actual backend.
# Expansion exception: upstream VllmConfig.__post_init__ is a large validation
# pipeline; keep a narrow original-function delegation so this patch only owns
# AFD validation and worker normalization.
# pipeline; keep narrow original-function delegation so this patch only owns
# the AFD backend validation bypass.
# Signature: matches upstream; no added parameters.
def __post_init__(self: VllmConfig):
"""Verify configs are valid & consistent with each other."""

assert _original_vllm_config_post_init is not None
# ### PATCH START: AFD automatic worker selection
worker_cls_was_auto = _uses_auto_worker(self)
# ### PATCH END: AFD automatic worker selection
if not _should_relax_vllm_config_backend(self):
result = _original_vllm_config_post_init(self)
else:
# ### PATCH START: AFD ubatching all2all backend validation
# Repeated VllmConfig validation can run after EngineArgs construction.
# Keep AFD's real all2all backend on the config, but use a temporary DeepEP
# value while upstream performs its native ubatching assertion.
parallel_config = self.parallel_config
original_backend = parallel_config.all2all_backend
parallel_config.all2all_backend = _AFD_TEMP_BACKEND
try:
result = _original_vllm_config_post_init(self)
finally:
parallel_config.all2all_backend = original_backend
# ### PATCH END: AFD ubatching all2all backend validation
return _original_vllm_config_post_init(self)

# ### PATCH START: AFD automatic worker selection
if worker_cls_was_auto:
_select_afd_worker_for_auto(self)
# ### PATCH END: AFD automatic worker selection
# ### PATCH START: AFD repeated ubatching backend validation
parallel_config = self.parallel_config
original_backend = parallel_config.all2all_backend
parallel_config.all2all_backend = _AFD_TEMP_BACKEND
try:
result = _original_vllm_config_post_init(self)
finally:
parallel_config.all2all_backend = original_backend
# ### PATCH END: AFD repeated ubatching backend validation
return result


def _uses_auto_worker(vllm_config: VllmConfig) -> bool:
worker_cls = vllm_config.parallel_config.worker_cls
def _uses_auto_worker_value(worker_cls: str | type[Any]) -> bool:
return isinstance(worker_cls, str) and worker_cls.strip() == "auto"


Expand Down
85 changes: 49 additions & 36 deletions afd_plugin/compat/patches/npu/ascend_platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
# SPDX-FileCopyrightText: Copyright contributors to the AFD plugin project
"""Patch vLLM-Ascend platform config normalization for AFD-owned DBO.

Upstream source: ``vllm_ascend/platform.py``.
Upstream source: ``vllm_ascend/platform.py`` at tag ``v0.19.1rc1``.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any
from dataclasses import dataclass
from typing import TYPE_CHECKING

from afd_plugin.config import parse_optional_afd_config

Expand All @@ -17,83 +18,95 @@
_ASCEND_PLATFORM_PATCH_ATTR = "_afd_plugin_ascend_platform_patch_state"


def apply_afd_ascend_dbo_config_patch() -> None:
@dataclass(frozen=True)
class _AFDDBOConfigSnapshot:
enable_dbo: bool
ubatch_size: int
all2all_backend: str


def apply_afd_ascend_dbo_config_patch() -> bool:
"""Preserve AFD-owned DBO settings during vLLM-Ascend config normalization.

vLLM-Ascend's platform compatibility pass disables DBO/ubatching fields for
ordinary NPU runs. AFD owns its NPU ubatching path, so this patch snapshots
those fields for AFD-enabled configs, lets upstream normalization run, then
restores the AFD DBO values. The patch is a no-op when vLLM-Ascend is not
importable or when this process has already installed the wrapper.
importable. Returns whether this process has installed the wrapper (or had
already installed it), so callers do not cache a failed early import during
plugin initialization.
"""

try:
from vllm_ascend.platform import NPUPlatform
except Exception:
return
except ImportError:
return False

if hasattr(NPUPlatform, _ASCEND_PLATFORM_PATCH_ATTR):
return
return True

original_fix_incompatible_config = NPUPlatform._fix_incompatible_config
original_check_and_update_config = NPUPlatform.check_and_update_config

# Patch reason: vLLM-Ascend resets DBO fields inside NPUPlatform config
# normalization, while AFD now owns the Ascend DBO/ubatching path.
# Patch reason: vLLM-Ascend v0.19.1rc1 resets DBO fields in
# _fix_incompatible_config and later rewrites all2all_backend in
# check_and_update_config, while AFD owns the Ascend DBO/ubatching path and
# temporarily supplies a validation-safe backend.
# Patch functionality: preserves upstream normalization for non-AFD configs and
# restores AFD DBO fields after upstream normalization for AFD-enabled configs.
# Expansion exception: upstream _fix_incompatible_config is platform-owned
# restores AFD DBO fields plus the temporary ubatching backend after upstream
# normalization for AFD-enabled configs.
# Expansion exception: upstream check_and_update_config is platform-owned
# normalization; keep narrow original-function delegation so this patch only
# owns the AFD DBO preservation.
# Signature: matches upstream; no added parameters.
def _fix_incompatible_config(vllm_config: VllmConfig) -> Any:
def check_and_update_config(cls, vllm_config: VllmConfig) -> None:
del cls
# ### PATCH START: AFD DBO config preservation
saved = _snapshot_afd_dbo_config(vllm_config)
try:
original_check_and_update_config(vllm_config)
finally:
if saved is not None:
_restore_afd_dbo_config(vllm_config, saved)
# ### PATCH END: AFD DBO config preservation
result = original_fix_incompatible_config(vllm_config)
# ### PATCH START: AFD DBO config preservation
if saved is not None:
_restore_afd_dbo_config(vllm_config, saved)
# ### PATCH END: AFD DBO config preservation
return result

NPUPlatform._fix_incompatible_config = staticmethod(_fix_incompatible_config)
NPUPlatform.check_and_update_config = classmethod(check_and_update_config)
setattr(
NPUPlatform,
_ASCEND_PLATFORM_PATCH_ATTR,
original_fix_incompatible_config,
original_check_and_update_config,
)
return True


def _snapshot_afd_dbo_config(vllm_config: VllmConfig) -> dict[str, bool | int] | None:
def _snapshot_afd_dbo_config(
vllm_config: VllmConfig,
) -> _AFDDBOConfigSnapshot | None:
if not _has_valid_afd_config(vllm_config):
return None
parallel_config = vllm_config.parallel_config
return {
"enable_dbo": parallel_config.enable_dbo,
"use_ubatching": parallel_config.use_ubatching,
"ubatch_size": parallel_config.ubatch_size,
}
return _AFDDBOConfigSnapshot(
enable_dbo=parallel_config.enable_dbo,
ubatch_size=parallel_config.ubatch_size,
all2all_backend=parallel_config.all2all_backend,
)


def _restore_afd_dbo_config(
vllm_config: VllmConfig,
saved: dict[str, bool | int],
saved: _AFDDBOConfigSnapshot,
) -> None:
parallel_config = vllm_config.parallel_config
if not (
saved["enable_dbo"]
or saved["use_ubatching"]
or int(saved["ubatch_size"] or 0) != 0
):
if not saved.enable_dbo and saved.ubatch_size == 0:
return
parallel_config.enable_dbo = saved["enable_dbo"]
parallel_config.ubatch_size = saved["ubatch_size"]
parallel_config.enable_dbo = saved.enable_dbo
parallel_config.ubatch_size = saved.ubatch_size
parallel_config.all2all_backend = saved.all2all_backend


def _has_valid_afd_config(vllm_config: VllmConfig) -> bool:
try:
return parse_optional_afd_config(vllm_config, validate=True) is not None
except Exception:
except (TypeError, ValueError):
return False


Expand Down
Loading