Five orders of magnitude on one chart
I keep a small repository around that computes the same thing (the Mandelbrot set, the escape-time algorithm every fractal renderer runs) as many different ways as I can stand to write. Same image every time: 1400×800 pixels, 256 iterations per pixel, one Apple M4 Max. Same math. The only variable is how the computation is expressed: pure SQL, plain Python, NumPy, native code, a GPU shader. Then I put every result on one chart with a log scale, where each gridline is 10× the one below it.
The chart is five gridlines tall. The slowest thing I wrote took the better part of four minutes; the fastest returns in 0.30 milliseconds (a third of a millisecond). Same fractal. Same laptop. A hundred-thousand-fold spread, and not one line of it is a trick.
The ladder
Read top (slow) to bottom (fast):
- SQLite, recursive CTE: ~45 s. Yes, you can compute a fractal in pure SQL. A
WITH RECURSIVEwalks the iteration count for every pixel, no host language in the loop at all. My first naive pass ran closer to four minutes; tightening the CTE got it to around 45 seconds. Still the top rung of the chart, and honestly astonishing that it runs at all. A database engine was never built to iteratez = z² + c. That it finishes in under a minute is the surprise. - Plain Python. A nested loop over every pixel, interpreted, one complex-number operation at a time. Faster than making a query planner do it, slower than everything below.
- NumPy. The same loop, but vectorized: the per-pixel work happens inside compiled C over whole arrays at once, and the entire grid advances one iteration in a single call. This is the first big drop on the chart, and it's a drop you get by deleting the Python loop, not optimizing it.
- Native code. Tight and compiled, no interpreter overhead per pixel. Another rung down.
- Metal GPU shader: 0.30 ms. The escape-time algorithm is embarrassingly parallel: every pixel is independent, so you hand one pixel to one thread and let a few thousand of them run at once. This is what the bottom of the chart is made of.
The jumps are the whole story
What the log scale makes obvious, and a bar chart would hide, is this: the distance between rungs dwarfs anything you could do within a rung. You could spend a week micro-optimizing the Python version (better complex-number handling, loop unrolling, a faster inner test) and claw back maybe 2×. NumPy hands you 10× or more for free, by changing how the work is represented, not how hard you tune it. The GPU hands you another few orders on top, for the same reason: a completely different shape of computation.
Five orders of magnitude is a representation decision, not a micro-optimization. You don't tune your way across this chart — you jump, and every jump is a change in what runs the loop, not how tightly the loop is written.
Why this sits on a blog about AI tooling
Because it's the exact same lever, wearing different clothes. The entire argument this site keeps making about cost (that the biggest win is routing, not squeezing, that you pick the cheapest tier that clears the bar and stop) is this chart in another domain. Fussing with a prompt to shave 15% off one model's token bill is loop-unrolling the Python version. Moving 80% of your traffic to a cheaper model that clears the same bar is the jump from Python to NumPy. The gains that matter live between the tiers, and people spend most of their effort optimizing within one because that's the effort that feels like work.
What the chart doesn't say
Honesty, because a 100,000× headline invites the wrong conclusion. This is single-run wall-clock, one machine, one specific workload, and a log axis flatters the fast end. The visual drama is partly the scale doing its job. It does not say "always use the GPU." For a one-off 1400×800 render, 0.30 ms versus 45 seconds is a distinction without a difference; you'll spend longer typing the command than either one runs. The spread only matters when the computation sits in a hot loop, or scales to millions of images. The right rung is the cheapest one that clears your actual bar, which is the same discipline as everywhere else on this site and the same reason the frontier model isn't automatically the right one.
The Mandelbrot set is just a convenient excuse. Pick anything you compute more than once, ask what's actually running the inner loop, and the odds are the biggest speedup available to you is a different rung entirely, not a better version of what you already have.