[XPU] refine memory release for sleep mode (#61158)

Signed-off-by: Yan Ma <yan.ma@intel.com>
This commit is contained in:
Yan Ma
2026-10-12 16:59:38 +08:00
committed by GitHub
parent 99b44c7a42
commit e05201aa2e
2 changed files with 12 additions and 21 deletions
+11 -15
View File
@@ -146,6 +146,7 @@ class XpuMemAllocator:
self.pointer_to_data: dict[int, AllocationData] = {}
self.current_tag: str = XpuMemAllocator.default_tag
self.allocator_and_pools: dict[str, list[Any]] = {}
self._pending_allocators: list[Any] = []
self.python_malloc_callback = self._python_malloc_callback
self.python_free_callback = self._python_free_callback
@@ -291,24 +292,17 @@ class XpuMemAllocator:
data.cpu_backup_tensor = None
def release_pools(self) -> None:
"""Drop Python references to MemPool/pluggable allocators eagerly.
This prevents pool destruction from being deferred to interpreter
finalization, which can happen after parts of XPU runtime are already
torn down.
"""
if not self.allocator_and_pools:
"""Release pools, retaining allocators until their allocations are freed."""
if not self.allocator_and_pools and not self._pending_allocators:
return
# Note: keep allocators alive while MemPool objects are destroyed.
# MemPool teardown may invoke allocator virtual methods (e.g. raw_delete)
# when releasing cached blocks. If allocator wrappers are dropped first,
# C++ can hit "pure virtual method called" during shutdown.
pool_entries = [e for es in self.allocator_and_pools.values() for e in es]
self.allocator_and_pools.clear()
mem_pools = [entry[0] for entry in pool_entries]
allocators = [entry[1] for entry in pool_entries]
# Live tensors can outlast their MemPool wrappers. Keep allocators alive
# across calls so deferred frees cannot invoke a destroyed allocator.
self._pending_allocators.extend(entry[1] for entry in pool_entries)
pool_entries.clear()
xpu_sync = getattr(torch.xpu, "synchronize", None)
@@ -318,12 +312,14 @@ class XpuMemAllocator:
except Exception:
logger.debug("torch.xpu.synchronize() failed during release_pools")
# Phase 1: drop MemPool refs while allocators are still strongly held.
mem_pools.clear()
gc.collect()
torch.xpu.empty_cache()
# Phase 2: now it is safe to release allocator wrappers.
allocators.clear()
# Free callbacks remove allocation records, including cached blocks.
# If any remain, a later release_pools() call must retry this cleanup.
if not self.pointer_to_data:
self._pending_allocators.clear()
@contextmanager
def use_memory_pool(self, tag: str | None = None):
@@ -211,12 +211,7 @@ class ShardedStateLoader(BaseModelLoader):
# TODO: support un-sharded checkpoints too
raise ValueError(
f"Could not find checkpoint files "
f"'{
os.path.join(
local_model_path,
rendered_pattern,
)
}', "
f"'{os.path.join(local_model_path, rendered_pattern)}', "
f"only pre-sharded checkpoints are currently supported!"
)
state_dict = self._filter_subtensors(model.state_dict())