Apple Silicon Mac Local Model Benchmark: Fixed Tasks, Quantization, Context & Speed
Measured prompt eval and token generation speeds across Q4_K_M, Q5_K_M, and Q8_0 on unified memory—showing exactly when raising num_ctx triggers SSD swap degradation.
MacBook Pro 14" (M3 Pro · 18GB & 36GB Unified Memory tested) · macOS 15.3
Verified with Wi-Fi disabled (`networksetup -setairportpower en0 off`); zero outbound telemetry from ollama serve.
- Model file size != runtime memory: Qwen2.5-14B Q4_K_M is 9.0 GB on disk, but at num_ctx=32768 (FP16 KV cache) total footprint reaches 16.4 GB, causing heavy swap on 16GB/18GB Macs.
- Docker Desktop on macOS runs a Linux VM without Metal GPU passthrough; running Ollama inside Docker on Mac drops speed by 75%+.
1. Why Weight File Size Misleads Local AI Planners
2. Fixed-Task Results Across Quantizations & Context Sizes
| Model & Quant | Context (KV Precision) | Disk Weight | Resident Memory | Eval Speed |
|---|---|---|---|---|
| qwen2.5:7b-instruct-q4_K_M | 8192 (f16) | 4.7 GB | 5.5 GB (100% GPU) | 54.2 tok/s |
| qwen2.5:14b-instruct-q4_K_M | 8192 (f16) | 9.0 GB | 10.8 GB (100% GPU) | 31.6 tok/s |
| qwen2.5:14b-instruct-q4_K_M (18GB Mac) | 32768 (f16) | 9.0 GB | 16.4 GB (SSD Swap!) | 6.8 tok/s |
| qwen2.5:14b-instruct-q4_K_M (18GB Mac) | 32768 (q8_0 KV) | 9.0 GB | 12.9 GB (100% GPU) | 27.1 tok/s |
| qwen2.5:14b-instruct-q8_0 (36GB Mac) | 16384 (f16) | 15.7 GB | 18.9 GB (100% GPU) | 19.4 tok/s |
# Enable Flash Attention + Q8_0 KV Cache before starting Ollama on Mac launchctl setenv OLLAMA_FLASH_ATTENTION 1 launchctl setenv OLLAMA_KV_CACHE_TYPE q8_0 # Inspect exact resident memory and Metal offload percentage ollama ps
3. Tuning macOS Wired Memory Ceiling & Keep-Alive Policy
Frequently Asked Questions & Edge Cases
Q: Why does running Ollama inside Docker Desktop on Mac drop speed by 75%?
Docker Desktop on macOS runs containers inside a lightweight Linux virtual machine that does not support Apple Metal GPU passthrough. Run Ollama natively on macOS host and let containerized apps (Open WebUI, n8n) connect via host.docker.internal:11434.
Q: Does Q8_0 KV Cache quantization hurt coding or JSON accuracy?
In our deterministic 420-token JSON extraction benchmark across 50 runs, Q8_0 KV cache produced 100% identical schema compliance to FP16 while cutting KV cache memory in half. Avoid Q4_0 KV cache for strict code/math tasks.
Apple Silicon Mac Fixed-Task Speed & Context Benchmark Script
Measures prompt eval rate, token generation speed (tok/s), and peak unified memory footprint under a fixed deterministic task.
#!/usr/bin/env bash
# Tinker AI — Reproducible Mac Local LLM Benchmark (Guide #1)
set -euo pipefail
MODEL="qwen2.5:14b-instruct-q4_K_M"
CTX="8192"
API="http://127.0.0.1:11434/api/generate"
echo "=== [1/3] Hardware & Version Snapshot ==="
uname -a
ollama --version || true
echo "=== [2/3] Running Fixed Deterministic Task (seed=42, num_ctx=$CTX) ==="
RESPONSE=$(curl -sS "$API" -d "{
\"model\": \"$MODEL\",
\"prompt\": \"Extract three technical risks of running local LLMs with large context windows in strict JSON format with keys: risk, cause, mitigation.\",
\"stream\": false,
\"options\": {
\"num_ctx\": $CTX,
\"temperature\": 0,
\"seed\": 42
}
}")
echo "$RESPONSE" | python3 -c '
import sys, json
data = json.load(sys.stdin)
eval_count = data.get("eval_count", 0)
eval_dur = data.get("eval_duration", 1) / 1e9
prompt_count = data.get("prompt_eval_count", 0)
prompt_dur = data.get("prompt_eval_duration", 1) / 1e9
print(f"Prompt Eval : {prompt_count} tokens ({prompt_count/prompt_dur:.2f} tok/s)")
print(f"Generation : {eval_count} tokens ({eval_count/eval_dur:.2f} tok/s)")
'
echo "=== [3/3] Active Metal / Unified Memory Footprint ==="
ollama ps