macOS 메모리 가드레일¶
통합 메모리를 거의 다 쓰는 모델은 이산 GPU에서와 달리 Mac에서 다르게 동작합니다. 이 페이지는 mlxcel이 보고하는 수치, macOS에 남겨 두는 예약분, 그 둘에 작용하는 스위치를 설명합니다.
전체 RAM이 틀린 수치인 이유¶
버퍼의 GPU wiring은 마지막 command buffer가 끝나고 몇 초 뒤에 풀립니다. 서버가 idle인 사이 다른 프로세스가 메모리를 원하면 macOS가 모델 메모리를 압축하거나 swap할 수 있고, 다음 요청이 그 비용을 치릅니다. 전체 RAM과 Metal 권장 working set은 기계가 담을 수 있는 양이며, 지금 당장 내줄 수 있는 양이 아닙니다.
지금 사용 가능한 양과 예약분¶
mlxcel inspect와 --estimate-memory는 macOS에서 다음 줄을 출력합니다.
| 항목 | 의미 |
|---|---|
| 전체 RAM | hw.memsize |
| Metal working set | Metal 권장 working set |
| 지금 사용 가능 | host_statistics64의 free + purgeable + min(inactive + speculative, file-backed) page입니다. free에서 speculative page는 뺍니다(커널의 free_count는 이를 포함합니다). 다른 프로그램의 inactive anonymous 메모리는 macOS가 압축하거나 swap해야만 회수하므로 제외합니다. |
| macOS 예약분 | max(7 GiB, RAM의 15%) |
| 이번 로드 | weight + KV cache + activation |
로드가 "지금 사용 가능"에서 예약분을 뺀 값보다 크면 WARNING: memory available now로 시작하는 줄이 수치를 보여 줍니다. 이 경고는 로드를 거부하지 않고 FITS 판정도 바꾸지 않습니다.
수치와 예약분은 mlxcel_core::host_memory의 host_memory_status, HostMemoryStatus, AvailabilityGate로 노출되며, 요청에 따라 늘어나는 store라면 어디든 같은 값을 씁니다.
Footprint 보고¶
로드가 끝나면 서버가 Process footprint after load를 로그에 남깁니다. --metrics를 켜면 macOS의 /metrics에 다음 gauge가 추가됩니다.
| 지표 | 의미 |
|---|---|
mlxcel_process_phys_footprint_bytes | 프로세스의 phys_footprint |
mlxcel_process_compressed_bytes | compressor나 swap에 들어간 프로세스 메모리입니다. idle인데 이 값이 늘면 idle 압축이 일어난 것입니다. |
mlxcel_mlx_active_bytes, mlxcel_mlx_cache_bytes | MLX allocator counter |
mlxcel_weights_wired_bytes | 마지막 로드에서 MLXCEL_WIRE_WEIGHTS가 wire한 byte |
스위치¶
MLXCEL_WIRED_LIMIT의 기본값은 max 그대로입니다.
MLXCEL_WIRE_WEIGHTS=1은 macOS에서만, 로드 뒤 평가된 weight를 mlock으로 wire하며 기본값은 off입니다. weight는 1 GiB 단위로 wire합니다. 첫 chunk 전과 chunk마다 시스템 wired 총량을 RAM에서 예약분을 뺀 값과 비교하고, 이를 넘는 chunk는 unwire한 뒤 멈춥니다. 결과와 실패는 로그에 남깁니다. 기본값인 eager MLXCEL_WEIGHT_MATERIALIZATION이 필요합니다. 멀티모달 tower는 wire하지 않고, 첫 토큰에서 실행되는 repack(expert stacking, dtype 변환)은 wired source를 unwired 결과로 바꿉니다.
늘어나는 store¶
qwen4_exp의 외부 PLE row cache는 64 MiB씩 늘리기 전에 사용 가능량을 확인합니다. 예약분 아래로 내려가야 하면 늘리지 않고 축출합니다. 확인은 250 ms 동안 같은 query를 재사용합니다.
프롬프트 캐시 snapshot store도 같은 방식을 씁니다. byte 예산 아래에 있는 동안에는 상주 크기를 늘리는 snapshot 삽입마다 예약분 대비 사용 가능량을 다시 확인하고, 호스트가 감당할 수 없으면 저장하지 않고 건너뜁니다. 예산에 도달한 store는 항목을 교체만 하므로 거부되지 않습니다. KV 프롬프트 캐시 store에는 이 검사를 걸지 않습니다. 항목의 배열은 삽입 시점에 이미 존재하고 store 자체가 byte 예산으로 제한되므로, 거부할 성장 단계가 없습니다.
측정 현황¶
이 가드레일로 soak를 돌린 적이 없으므로 측정을 근거로 기본값을 바꾼 항목은 없습니다. MLXCEL_WIRE_WEIGHTS는 off, MLXCEL_WIRED_LIMIT은 max, 로드 거부는 없음 그대로입니다. 스위치는 조용한 기계에서 측정을 돌리기 위해 있으며, 값의 정확한 목록은 MLXCEL 환경 변수에 있습니다.