Big vs. Small Local Models on a 32 GB Mac: Where MoE Breaks the ‘Bigger = Slower’ Rule

BLUF

On my 32 GB Mac mini (M2 Pro), going from an 8B dense model to a 14B dense model drops generation throughput from 26.1 tok/s to 14.7 tok/s — a real, felt slowdown. But two MoE models, qwen3-coder:30b and gpt-oss:20b, hit 40.0 tok/s and 32.8 tok/s respectively, both faster than the little 8B Llama — which is not what the “bigger = slower” rule would predict.

Why I ran this

The standard advice for local LLMs is: pick the biggest model your RAM can handle and accept the speed penalty. I wanted to stress-test that assumption across a range of model sizes and architectures on a single machine with fixed RAM. Specifically, I was curious whether MoE (Mixture of Experts) models — which have large total parameter counts but only activate a small subset per token — actually deliver on their theoretical throughput advantage in practice under Ollama.

Setup and method

  • Hardware: Mac mini, Apple M2 Pro, 32 GB unified memory, macOS
  • Software: Ollama 0.32.1, default quantizations for each model
  • Benchmark: Single fixed prompt, num_predict=256, temperature=0.3, thinking off
  • Reported numbers: Warm average of 2 runs per model
  • Metrics: Load time (seconds), generation throughput (tok/s), prompt eval throughput (tok/s)

Honest limitations: This is throughput-only — it says nothing about output quality, reasoning depth, or instruction-following. One machine, one prompt, two runs. Default quants vary by model, so you’re not comparing apples-to-apples weights. Don’t extrapolate to different hardware or different Ollama versions without re-testing.

Results

Generation speed (tokens/sec) — higher is betterGeneration speed (tokens/sec) — higher is betterqwen3-coder:30b (MoE ~3B active)40.0gpt-oss:20b32.8gemma4:26b (MoE ~4B active)30.1llama3.1:8b (dense 8B)26.1phi4:14b (dense 14B)14.7gemma4:31b (MoE)6.2
Measured on the machine described below — higher is better.
ModelArchitectureLoad (s)Gen (tok/s)Prompt eval (tok/s)
llama3.1:8bDense 8B7.626.11318.6
phi4:14bDense 14B11.614.7739.8
gpt-oss:20bDense(?) 20B16.932.81131.2
gemma4:26bMoE ~4B active12.930.1501.3
gemma4:31bMoE15.06.2108.3
qwen3-coder:30bMoE ~3B active20.340.01973.2

What the numbers actually show

Dense models: bigger really does mean slower

For the dense models, the pattern is exactly what you’d expect. llama3.1:8b generates at 26.1 tok/s. phi4:14b drops to 14.7 tok/s — a significant slowdown you’ll notice in conversation. Load times track parameter count too: 7.6 s for the 8B, 11.6 s for the 14B, 16.9 s for gpt-oss:20b.

What’s interesting is that gpt-oss:20b punches above its weight on throughput — 32.8 tok/s from a 20B model is faster than both dense models below it. I don’t have a confirmed explanation for this from the data alone; it could be quantization level, architecture efficiency, or something else. Worth investigating further.

MoE: the pattern fractures — sometimes spectacularly, sometimes badly

The MoE results are the most striking part of this benchmark, and they cut both ways.

qwen3-coder:30b (MoE, ~3B active parameters per token) is the fastest model in the entire test at 40.0 tok/s generation and 1973.2 tok/s prompt eval. It loads in 20.3 s — the slowest load time — but once it’s running, it outpaces every other model including the 8B dense. That’s the MoE promise delivering: 30B of total capacity, small-model inference speed.

gemma4:26b (MoE, ~4B active) also beats the 8B Llama at 30.1 tok/s. Prompt eval at 501.3 tok/s is on the lower end, but generation speed is solid.

gemma4:31b is the cautionary tale. Despite also being a MoE model, it crawls at 6.2 tok/s generation and 108.3 tok/s prompt eval — the slowest numbers in the entire table, slower than every other model including the dense 14B. Something about this particular model’s configuration — possibly larger active parameter count, higher quant size pushing memory bandwidth limits, or the full 32 GB being taxed — causes it to fall apart on this machine. MoE is not a magic speed card; it depends heavily on the specific model’s implementation and how well it fits your available memory bandwidth.

Practical takeaways for 32 GB Mac users

  • Don’t assume dense 8B is your speed floor. qwen3-coder:30b at 40.0 tok/s and gemma4:26b at 30.1 tok/s prove you can run much larger models faster.
  • phi4:14b at 14.7 tok/s is the slowest generator here — if you’re using it for interactive chat, that’s a noticeable pace.
  • MoE can fail on this hardware. gemma4:31b at 6.2 tok/s is a reminder to always benchmark before committing to a model for daily use.
  • Load time is a separate axis. qwen3-coder takes 20.3 s to load but then runs fast; llama3.1:8b loads in 7.6 s. If you’re switching models frequently, load time matters. If you keep one model resident, it doesn’t.
  • Prompt eval throughput varies wildly — from 108.3 tok/s (gemma4:31b) to 1973.2 tok/s (qwen3-coder:30b). For long-context use cases, this matters as much as generation speed.

Method reminder

All numbers come from a single fixed prompt, num_predict=256, temp=0.3, thinking off, warm average of 2 runs, default Ollama quantizations, one machine. This measures throughput only — not output quality, coherence, or task accuracy. Your numbers will differ on different hardware or with non-default quants.

Running similar benchmarks on your own machine? Drop your model, hardware, and tok/s numbers in the comments — I’d like to see how M3, M4, and non-Apple silicon compare on the same models.


Eric Woo

Written by Eric Woo

Self-Hosted AI & Automation Engineer

Eric runs his own self-hosted stack: local LLM pipelines on Ollama with dual-model VRAM scheduling on a single 32GB workstation, n8n workflows in Docker, and a TypeScript automation engine that publishes to WordPress on cron. He writes about the systems he actually operates — configs, failure modes, and GPU bills included.

Leave a Comment