성능 튜닝¶
mlxcel은 보수적인 kernel launch와 attention 정책을 자동 선택합니다. 실제 prompt 길이, batch size, 모델, cache mode, device를 대표하는 부하를 측정한 뒤에만 튜닝하십시오. 한 GPU나 context shape에서 측정한 값은 이식 가능한 기본값이 아닙니다.
커널 자동 튜닝¶
mlxcel tune은 지원하는 launch 후보를 profile하고 승자를 ${MLXCEL_CACHE_DIR:-$HOME/.cache/mlxcel}/autotune에 저장합니다. Cache를 쓰는 것만으로 추론 동작은 바뀌지 않으며 MLXCEL_AUTOTUNE을 켜야 적용됩니다.
# Profile 없이 행렬만 출력
mlxcel tune --dry-run
# 현재 backend가 지원하는 모든 operation 튜닝
mlxcel tune
# 체크포인트의 head geometry로 paged decode 튜닝
mlxcel tune --op paged-decode-splits -m ./models/qwen3-4b-4bit
# 저장된 승자만 사용
MLXCEL_AUTOTUNE=cache mlxcel serve -m ./models/qwen3-4b-4bit
# 저장된 승자를 사용하고 처음 보는 shape은 첫 실행 시 튜닝
MLXCEL_AUTOTUNE=1 mlxcel serve -m ./models/qwen3-4b-4bit
지원 operation은 Metal·CUDA의 paged-decode-splits와 현재 검증되지 않은 CUDA 전용 qmm-tile, qmv-multirow sweep입니다. 기본 행렬은 batch size 1,2,4,8과 context length 1024,4096,16384를 다룹니다. --model 또는 --head-dim, --q-heads, --kv-heads, --block-size를 명시해 프로덕션 geometry와 맞추십시오. Profiler는 warmup, adaptive sampling, median scoring, 기본 2% minimum improvement를 사용해 noise가 안정적인 기본값을 대체하지 않게 합니다.
Attention dispatch¶
서버의 기본값 --decode-storage-backend auto는 검증된 모델군에만 paged decode를 선택하고 나머지는 dense storage로 돌아갑니다. 같은 부하의 통제된 비교로 다른 선택이 더 낫다고 확인하기 전에는 auto를 유지하십시오. 현재 자동 paged set에는 Llama, Qwen 3, Qwen 3.5 text, Gemma 3 text, Llama 4 worker가 포함됩니다. Internal-cache 및 hybrid 모델군은 model-owned paged dispatch를 제공할 때까지 dense를 유지합니다.
고급 경로도 정책 gate를 거칩니다.
| 경로 | 범위 | 기본 동작 | 주요 제어 |
|---|---|---|---|
| Absorbed MLA decode | DeepSeek 등 MLA 모델군 | 지원하는 모델군에서 compressed latent KV 표현을 사용합니다 | 노출된 MLXCEL_MLA_* 진단·kill switch는 --help와 환경 변수 레퍼런스를 참조하십시오 |
| Cascade attention | 긴 공통 prefix를 가진 paged decode | 유용한 2-level prefix group을 감지하고 작거나 이익이 없는 group은 거부합니다 | 반복 prefix serving 부하를 profile할 때가 아니면 자동 정책을 유지하십시오 |
| Fused sparse paged decode | MiniMax-M3 sparse decode | 선택 row가 kernel floor를 넘고 context/selection sparsity가 8 이상일 때만 dispatch합니다 | MLXCEL_SPARSE_PAGED_*. Dump mode는 디버깅 전용입니다 |
| TurboQuant KV | 긴 context의 dense 모델 | quantized cache mode를 고르지 않으면 fp16입니다 | TurboQuant KV 캐시 참조 |
주요 sparse-paged 제어는 MLXCEL_SPARSE_PAGED_ATTENTION과 MLXCEL_SPARSE_PAGED_MIN_SPARSITY입니다. 구현된 MiniMax-M3 경로의 sparse paged decode는 token-exact입니다. DeepSeek Sparse Attention은 positional score에 현재 v2 kernel이 받지 않는 추가 K stream이 필요하므로 이 kernel로 라우팅하지 않습니다. 일부 고급 kernel의 CUDA 구현은 아직 검증되지 않았습니다. Metal 결과만으로 CUDA 지원을 추론하지 마십시오.
Host와 command-buffer 제어¶
MLX_MAX_OPS_PER_BUFFER는 M5 이전 Apple Silicon(M1-M4)에서 자동으로 1000을 사용하고 M5 또는 비-Apple target에서는 MLX 기본값을 유지합니다. 같은 M5 이전 호스트에서 MLXCEL_DECODE_MB_PER_BUFFER는 파이프라인 decode 단계에서만 Metal command-buffer 입력 예산을 1000으로 올립니다. op 상한을 올리면 입력 예산이 실제로 걸리는 한계가 되며, MLX 기본값에서는 decode 토큰 하나가 한두 계층마다 buffer를 commit합니다. 더 큰 예산은 긴 프롬프트에서 peak memory를 대략 두 배로 늘리므로 prefill은 장치 기본값을 유지합니다. MLX_MAX_MB_PER_BUFFER를 직접 설정하면 두 단계에 한 값을 고정하고 decode 전용 상향을 끕니다.
CUDA에서는 장시간 실행하는 shape-diverse 서빙의 cache thrashing을 피하기 위해 MLX_CUDA_GRAPH_CACHE_SIZE와 MLX_CUDA_SDPA_CACHE_SIZE가 2000을 기본값으로 씁니다. compute capability 12.1(GB10)에서는 MLX의 graph capture 예산이 표에서 가장 빡빡하며, mlxcel은 측정한 모든 워크로드에서 이득을 본 모델 계열에만 이 예산을 올립니다(MLX_MAX_OPS_PER_BUFFER=100, MLX_MAX_MB_PER_BUFFER=1000). 현재는 laguna가 해당하며, 다른 계열은 워크로드에 따라 이득과 손해가 갈렸습니다. mlxcel generate는 적용한 예산을 compute capability 줄 옆에 출력하고 mlxcel-server는 로그로 남깁니다. 명시한 환경 변수 값이 항상 우선합니다.
모델 로드는 생성 모델의 체크포인트 텐서를 읽고 업로드한 뒤에 Model loaded를 보고하므로, 첫 토큰에서 가중치 I/O가 발생하지 않고 보고된 로드 시간에 가중치가 메모리에 올라오는 시간이 포함됩니다. 비전·오디오 타워의 텐서는 요청이 해당 모달리티를 쓸 때까지 lazy 상태로 남습니다. MLXCEL_WEIGHT_MATERIALIZATION=lazy를 주면 각 텐서를 처음 쓸 때 구체화합니다. CUDA에서는 재사용하는 64 MiB 고정(pinned) 호스트 버퍼 4개로 텐서를 스테이징하며, MLXCEL_CUDA_PINNED_LOAD=0은 pageable 경로를 강제합니다. MLXCEL_PROFILE_TTFT는 [TTFT] 줄에 업로드 카운터를 추가합니다.
M1과 M2에서는 2~6행 dense 곱셈이 GEMV 커널에서 실행되어 작은 배치 크기의 배치 디코드가 빨라집니다. MLXCEL_DENSE_GEMV_ROWS=0은 upstream dense dispatch로 되돌립니다. CUDA에서 MLXCEL_SDPA_DETERMINISTIC=1은 실행 간 출력이 같아야 하는 비교를 위해 재현 가능한 디코드 SDPA 경로를 선택합니다.
디코드는 배치 네이티브 엔진 하나에서 실행됩니다. 시퀀스 하나는 크기 1인 배치이고, mlxcel run, mlxcel generate, 서버가 같은 샘플링 및 종료 단계를 공유합니다. 대부분의 모델 계열은 배치로 네이티브 디코드하며, 서버는 시작할 때 모델별로 decode path: native batched forward를 로그에 남깁니다.
M1 Ultra에서는 배치 디코드에 측정된 격차가 남아 있습니다. 일부 체크포인트에서 B=1 디코드가 배치 디코드 작업 이전보다 3~6% 낮고, Mixtral은 prompt cache가 warm일 때 B=8에서 B=1 속도에 미치지 못합니다(#2817). --max-batch-size를 올리기 전에 실제로 서비스할 배치 크기에서 사용하는 체크포인트를 직접 측정하십시오.
서버 throughput을 위해 --n-parallel, --max-batch-size, --prefill-chunk-size, --prefill-grant-interval, --batch-size, --ubatch-size를 함께 조정하십시오. Concurrency를 높여도 모델, KV cache, temporary tensor가 메모리에 맞을 때만 throughput이 증가합니다. Load time만 보지 말고 메모리 추정, /metrics, steady-state load test를 사용하십시오.
측정 체크리스트¶
- 정확한 mlxcel version, checkpoint revision, device, cache mode, prompt 길이 분포, output 길이, concurrency를 기록합니다.
- Sample 수집 전에 모델과 kernel cache를 warm up합니다.
- Prefill tokens/s, decode tokens/s, time to first token, tail latency, memory high-water mark, request failure를 비교합니다.
- 한 번에 하나만 바꾸고 thermal 및 background-load noise를 이길 만큼 반복합니다.
- Kill switch 또는
autobaseline을 유지합니다. 고급 경로가 fallback을 보고했다면 그 실행을 해당 경로의 성능이라고 주장하지 마십시오.