from __future__ import annotations
import logging
import os
import uuid
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, ClassVar
import torch
import torch.nn as nn
from ..nixl_transfer import is_nixl_available
from ..tensor_utils import log_tensor_summary
from ..metadata.publish import publish_metadata_and_ready
from .context import LoadContext, LoadResult
if TYPE_CHECKING:
from ..nixl_transfer import NixlTransferManager
logger = logging.getLogger("modelexpress.load_strategy")
class SourceTransferError(Exception):
class LoadStrategy(ABC):
name: str
requires: ClassVar[tuple] = ()
def is_available(self, ctx: LoadContext) -> bool:
if not self.requires:
return True
if ctx.adapter is None:
return False
cls = type(ctx.adapter)
return all(getattr(cls, m.__name__) is not m for m in self.requires)
@abstractmethod
def load(self, result: LoadResult, ctx: LoadContext) -> LoadResult:
def rollback(self, ctx: LoadContext) -> None:
return None
def _init_nixl_manager(
global_rank: int, device_id: int, role: str, listen_port: int = 0,
) -> NixlTransferManager:
from ..nixl_transfer import NixlTransferManager
agent_name = f"mx-{role}-worker{global_rank}-{uuid.uuid4().hex[:8]}"
logger.debug(f"[Worker {global_rank}] Initializing NIXL manager with agent_name={agent_name}")
manager = NixlTransferManager(
agent_name=agent_name,
device_id=device_id,
listen_port=listen_port,
)
manager.initialize()
logger.debug(f"[Worker {global_rank}] NIXL manager initialized")
return manager
def _as_load_result(result_or_model: LoadResult | nn.Module) -> LoadResult:
if isinstance(result_or_model, LoadResult):
return result_or_model
return LoadResult(value=result_or_model, model=result_or_model)
def _metadata_publication_configured(ctx: LoadContext) -> bool:
server_addr = os.environ.get("MODEL_EXPRESS_URL") or os.environ.get("MX_SERVER_ADDRESS")
if server_addr:
return True
return getattr(ctx.mx_client, "REQUIRES_P2P_METADATA", False) is True
def register_tensors(
result_or_model: LoadResult | nn.Module,
ctx: LoadContext,
*,
reuse_discovered: bool = False,
) -> None:
if not _metadata_publication_configured(ctx):
logger.info(
f"[Worker {ctx.global_rank}] No MX metadata path configured, "
"skipping NIXL registration"
)
return
if not is_nixl_available():
logger.warning(f"[Worker {ctx.global_rank}] NIXL not available, skipping registration")
return
if ctx.adapter is None:
raise RuntimeError("NIXL registration requires an engine adapter")
try:
if reuse_discovered and ctx.tensors:
logger.info(
f"[Worker {ctx.global_rank}] Re-registering "
f"{len(ctx.tensors)} previously-discovered tensors "
f"(skipping model walk)"
)
else:
result = _as_load_result(result_or_model)
if result.model is None:
logger.info(
f"[Worker {ctx.global_rank}] No model available, skipping NIXL registration"
)
return
ctx.tensors = ctx.adapter.discover_tensors(result)
log_tensor_summary(ctx.tensors, ctx.global_rank, "Registering tensors")
if ctx.nixl_manager is None:
base_port = int(os.environ.get("MX_METADATA_PORT", "5555"))
listen_port = base_port + ctx.device_id
ctx.nixl_manager = _init_nixl_manager(
ctx.global_rank, ctx.device_id, "auto", listen_port
)
if not ctx.nixl_manager.tensor_descriptors:
if ctx.vmm_arena is not None:
logger.debug(
f"[Worker {ctx.global_rank}] Registering arena with NIXL "
"(single MR via dmabuf)..."
)
ctx.nixl_manager.register_arena(ctx.vmm_arena, ctx.tensors)
else:
logger.debug(f"[Worker {ctx.global_rank}] Registering tensors with NIXL...")
ctx.nixl_manager.register_tensors(ctx.tensors)
logger.debug(f"[Worker {ctx.global_rank}] Tensors registered with NIXL")
except Exception as e:
logger.warning(
f"[Worker {ctx.global_rank}] NIXL registration failed, "
f"worker will continue without P2P serving: {e}"
)
def publish_metadata(ctx: LoadContext) -> None:
if ctx.nixl_manager is None:
logger.info(
f"[Worker {ctx.global_rank}] No NIXL manager, skipping metadata publish"
)
return
if not _metadata_publication_configured(ctx):
logger.info(
f"[Worker {ctx.global_rank}] No MX server configured, skipping metadata publish"
)
return
try:
publish_metadata_and_ready(
ctx.mx_client, ctx.nixl_manager, ctx.tensors,
ctx.worker_rank, ctx.device_id, ctx.identity, ctx.worker_id,
)
except Exception as e:
logger.warning(
f"[Worker {ctx.global_rank}] Failed to publish metadata, "
f"worker will continue without P2P serving: {e}"
)
def publish_source_if_supported(result: LoadResult, ctx: LoadContext) -> None:
if result.model_for_publish is None:
return
publish_metadata(ctx)
def unpublish_metadata(ctx: LoadContext) -> None:
from ..metadata.publish import _heartbeat_threads, _worker_servers
hb = _heartbeat_threads.pop(ctx.worker_rank, None)
if hb is not None:
try:
hb.stop() logger.info(f"[Worker {ctx.global_rank}] Heartbeat stopped")
except Exception as e:
logger.warning(
f"[Worker {ctx.global_rank}] Failed to stop heartbeat cleanly: {e}"
)
ws = _worker_servers.pop(ctx.device_id, None)
if ws is not None:
try:
ws.stop()
logger.info(f"[Worker {ctx.global_rank}] Worker gRPC server stopped")
except Exception as e:
logger.warning(
f"[Worker {ctx.global_rank}] Failed to stop worker gRPC server cleanly: {e}"
)