SM737's picture
Upload folder using huggingface_hub (part 4)
a358495 verified
Raw
History Blame Contribute Delete
3.16 kB
from __future__ import annotations
import gc
import time
from collections import OrderedDict
from contextlib import contextmanager
from threading import RLock
from typing import Any, Callable, Iterator
class ModelRuntimeManager:
"""Lazy, bounded runtime for a single accelerator or CPU-only deployment."""
def __init__(self, max_resident: int = 2, device: str = "auto") -> None:
self.max_resident = max(1, int(max_resident))
self.device = self._select_device(device)
self._models: OrderedDict[str, Any] = OrderedDict()
self._health: dict[str, dict[str, Any]] = {}
self._lock = RLock()
@staticmethod
def _select_device(requested: str) -> str:
if requested not in {"auto", "cuda", "cpu"}:
raise ValueError(f"Unsupported device: {requested}")
if requested == "cpu":
return "cpu"
try:
import torch
return "cuda" if torch.cuda.is_available() else "cpu"
except ImportError:
return "cpu"
@contextmanager
def acquire(self, model_id: str, loader: Callable[[], Any]) -> Iterator[Any]:
started = time.perf_counter()
with self._lock:
try:
if model_id not in self._models:
while len(self._models) >= self.max_resident:
oldest, _ = self._models.popitem(last=False)
self._health.setdefault(oldest, {})["resident"] = False
self._cleanup_device()
self._models[model_id] = loader()
self._models.move_to_end(model_id)
self._health[model_id] = {
"status": "READY",
"resident": True,
"device": self.device,
"load_ms": round((time.perf_counter() - started) * 1000, 2),
}
yield self._models[model_id]
except Exception as exc:
self._models.pop(model_id, None)
self._health[model_id] = {"status": "LOAD_FAILED", "resident": False, "reason": str(exc)}
self._cleanup_device()
raise
def unload(self, model_id: str) -> None:
with self._lock:
self._models.pop(model_id, None)
self._health.setdefault(model_id, {})["resident"] = False
self._cleanup_device()
@staticmethod
def _cleanup_device() -> None:
gc.collect()
try:
import torch
if torch.cuda.is_available():
torch.cuda.empty_cache()
except ImportError:
pass
def snapshot(self) -> dict[str, Any]:
allocated = 0
try:
import torch
if torch.cuda.is_available():
allocated = int(torch.cuda.memory_allocated())
except ImportError:
pass
return {
"device": self.device,
"max_resident": self.max_resident,
"resident_models": list(self._models),
"allocated_vram_bytes": allocated,
"models": dict(self._health),
}