콘텐츠로 이동

성능 튜닝

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를 사용하십시오.

측정 체크리스트

  1. 정확한 mlxcel version, checkpoint revision, device, cache mode, prompt 길이 분포, output 길이, concurrency를 기록합니다.
  2. Sample 수집 전에 모델과 kernel cache를 warm up합니다.
  3. Prefill tokens/s, decode tokens/s, time to first token, tail latency, memory high-water mark, request failure를 비교합니다.
  4. 한 번에 하나만 바꾸고 thermal 및 background-load noise를 이길 만큼 반복합니다.
  5. Kill switch 또는 auto baseline을 유지합니다. 고급 경로가 fallback을 보고했다면 그 실행을 해당 경로의 성능이라고 주장하지 마십시오.