Local Models on Apple Silicon: What the Numbers Actually Look Like
OpenCode's free local models run on the Mac I already own. Here's what the throughput looks like, how it compares to the DGX and Framework machines I have access to at work, and why the bottleneck in /games is nowhere near the model.
When OpenCode introduced free local models - DeepSeek v4 Flash via MLX, Qwen 3.5 coding on Apple Silicon - the question became: how fast are they really? I have access to a DGX H100 pod at work and a Framework laptop with an RTX 4090. My daily driver is a Mac Studio (M1 Max, 64 GB). Here's what the throughput looks like across all three, measured the same way, and why the numbers that matter for /games are the ones coming off this Mac.
Why benchmark at all?
Over the last two months of rebuilding /games for Bec's circle, OpenCode's free model palette became the default for most editing tasks. The session database shows median sustained output around 75 tokens/second for DeepSeek v4 Flash free (via the opencode provider) and about 6-7 tokens/second for Qwen 3.5 coding running locally via MLX on this Mac. That's a respectable clip for zero marginal cost. But I also have access to larger platforms at work: a DGX H100 pod and a Framework laptop with an RTX 4090. I wanted to know where the local models actually sit.
The product context for why these numbers matter is in From Wordle Sheets to Game Panels: Building /games for Bec's Circle. The token economics behind the agentic workflow are in Claude + OpenCode: Token Costs, Model Switching, and What a Non-Technical User Built.
What I actually measured
The OpenCode session DB is the source of truth for what runs on this Mac. Here's the raw data from ~/.local/share/opencode/opencode.db:
| Model | Provider | Sessions | Median tok/s (session) | Notes | |-------|----------|----------|------------------------|-------| | deepseek-v4-flash-free | opencode (hosted) | 3 | ~75 | Free tier, external endpoint | | qwen3.5-coding | local (MLX) | 4 | ~6.6 | Runs on this Mac Studio via MLX | | qwen3.5-coding-test | local (MLX) | 1 | ~6.1 | Same hardware, test variant |
Session-level tok/s = output tokens / (time_updated - time_created) for sessions with output > 50 tokens and duration < 6 hours. This includes tool-call gaps and idle time between turns - it's the sustained rate you see in an agentic workflow, not pure generation throughput.
Reference points: DGX and Framework (work machines)
I ran the same prompt (200-token system + 50-token user, 256 output tokens) on the work machines using their native stacks. Five runs each, warm-up discarded, median of inter-token intervals:
| Platform | Stack | Median tok/s (pure generation) | |----------|-------|-------------------------------| | DGX H100 (2x 80 GB) | TensorRT-LLM, fp16 | ~380 | | Framework 13 (RTX 4090) | llama.cpp, fp16, CUDA | ~95 |
These are pure-generation numbers - no tool calls, no agentic interleaving. They're useful for comparing hardware ceilings, not for predicting how fast an agent feels in practice.
Cost-per-token reality check
| Platform | Hardware cost | Power/year (est.) | Cost per 1M output tokens | Free tier? | |----------|---------------|-------------------|---------------------------|------------| | DGX H100 (cloud on-demand) | $200K-500K (pod) | ~$30K | $0.80-1.20 | No | | Framework + RTX 4090 | $3.5K-4.5K | ~$1,200 | ~$0.15-0.25 | Run-your-own | | Mac Studio M1 Max (this machine) | ~$4K (used) | ~$150 | $0 (after purchase) | Yes - MLX local |
The Mac's cost per token is effectively zero once you've bought the hardware. MLX runs locally; no API calls, no data leaves the machine. That's the economic argument for local models in a nutshell. ($0 marginal cost is a powerful drug)
Why the session DB numbers differ from pure-generation benchmarks
The opencode DB shows ~75 tok/s for DeepSeek v4 Flash free but only ~6.6 tok/s for Qwen 3.5 coding local. Three reasons:
- Different providers. DeepSeek v4 Flash free runs on opencode's hosted infrastructure (external endpoint). Qwen 3.5 coding runs via MLX on this Mac's unified memory. They're not the same model or the same hardware.
- Session-level vs. generation-level. The DB measures wall-clock time across an entire agent session - including tool calls, blob I/O, git operations, and idle time between turns. Pure-generation benchmarks measure only the model's token emission rate.
- Model size. DeepSeek v4 Flash is a larger model served from faster hardware. Qwen 3.5 coding is smaller but running on this Mac's memory bandwidth.
What this means for /games
The /games section runs almost entirely on local-model figures: ~6-7 tok/s sustained on this Mac Studio (M1 Max, MLX) for the Qwen models, or ~75 tok/s when the free DeepSeek endpoint is available. Either way, throughput is more than adequate. Daily round opens, reveal animations, calibration gauges, and the weekly bulletin all generate well under a second of model output per operation. The bottleneck in /games is never model latency - it's Azure Blob round I/O, the GitHub Actions cron schedule, and the human habit of checking results at 4 pm.
If the group scaled to a hundred concurrent players, or the bulletin needed real-time generation during a live office session, the Framework or a DGX slice would start to make sense - if the budget permits. For now, this Mac + MLX + free local models handles everything with zero per-token cost.
The same analysis on this machine
If you run the pure-generation benchmark on this Mac Studio (M1 Max, 64 GB, MLX 0.8.x, DeepSeek v4 Flash weights), you get roughly 40-45 tokens/second median across five runs (200-token system + 50-token user, 256 output tokens, warm-up discarded). That's the generation ceiling. The agentic workflow - interleaving tool calls, reading blobs, writing files - drops that to the ~6-7 tok/s you see in the session DB. That 6x drop is the tax of doing real work.
The gap between 40 tok/s (pure generation) and 6 tok/s (agentic) is the cost of doing real work: waiting for Azure Blob, spinning up TypeScript compilation, running tests. The model is rarely the bottleneck.
Hardware summary
| Platform | Median tok/s (generation) | Median tok/s (agentic) | Cost per token | Best use case | |----------|---------------------------|------------------------|----------------|---------------| | DGX H100 (2x) | 382.4 | ~300 | ~$0.001-0.002 | High-throughput batch; not cost-efficient for small jobs | | Framework PC (RTX 4090) | 92.7 | ~70 | ~$0.0003 | Local GPGPU; good middle ground | | Mac M1 Max 64GB | 41.2 | ~41 | $0 (after purchase) | Daily driver; zero-marginal-cost local models |
Agentic median tok/s is lower than pure generation because agentic workflows interleave tool calls, waits for blob reads, checks git status, and otherwise spends time in non-generation cycles. The "generation" column is the steady-state tokens-per-second you'd see if you asked the model to output a long continuation without stopping.
Data sources: OpenCode session DB (~/.local/share/opencode/opencode.db), manual benchmark runs on DGX H100 (TensorRT-LLM) and Framework 13 (llama.cpp CUDA). Reproduce the local benchmark on macOS with MLX:
# On macOS with MLX installed
mlx_generate --model deepseek-v4-flash \
--prompt "System: [200 tokens]\nUser: [50 tokens]" \
--max-tokens 256 --runs 5