sparkle/mlx_streaming/core/mem.py
fiser_jun 4745f264b2
2026-08-04 14:34:00 +08:00

76 lines
2.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""内存度量统一口径。macOS 上 ru_maxrss 单位是字节。"""
import resource
from dataclasses import dataclass
import mlx.core as mx
def rss_bytes() -> int:
# macOS: ru_maxrss 已是字节Linux 是 KB本项目目标是 macOS
return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
def _call(name: str) -> int:
fn = getattr(mx, name, None)
if fn is None:
fn = getattr(getattr(mx, "metal", object()), name, None)
try:
return int(fn()) if fn else 0
except Exception:
return 0
@dataclass
class MemSnapshot:
rss_bytes: int
mlx_active_bytes: int
mlx_peak_bytes: int
def snapshot() -> MemSnapshot:
return MemSnapshot(
rss_bytes=rss_bytes(),
mlx_active_bytes=_call("get_active_memory"),
mlx_peak_bytes=_call("get_peak_memory"),
)
def clear_cache() -> None:
fn = getattr(mx, "clear_cache", None) or getattr(getattr(mx, "metal", object()), "clear_cache", None)
if fn:
fn()
def reset_peak() -> None:
fn = getattr(mx, "reset_peak_memory", None) or getattr(getattr(mx, "metal", object()), "reset_peak_memory", None)
if fn:
fn()
def _set_limit(name: str, nbytes: int) -> bool:
"""调用 mx.set_*_limit(字节);存在且成功返回 True。"""
fn = getattr(mx, name, None) or getattr(getattr(mx, "metal", object()), name, None)
if fn is None:
return False
try:
fn(int(nbytes))
return True
except Exception:
return False
def setup_memory_hygiene(cache_gb: float = 2.0, wired_gb: float = 0.0) -> dict:
"""长期运行的内存防御:bound MLX 缓冲缓存 + 可选 wire 工作集防 macOS 压缩器。
- cache_gb>0:set_cache_limit,封顶 MLX 可回收缓冲,防长会话里缓存膨胀把常驻推过墙。
- wired_gb>0:set_wired_limit,把这么多 GB 的 GPU 缓冲钉为常驻(wired),macOS 不再
压缩/换出这些页 → 长跑延迟稳定。务必 < 系统建议工作集(本机 26.8GB),否则饿死系统。
返回实际生效项,便于启动日志记录。
"""
applied = {}
if cache_gb and cache_gb > 0:
applied["cache_limit_gb"] = cache_gb if _set_limit("set_cache_limit", cache_gb * 1e9) else None
if wired_gb and wired_gb > 0:
applied["wired_limit_gb"] = wired_gb if _set_limit("set_wired_limit", wired_gb * 1e9) else None
return applied