# Zaggle: optimizing Mandelbrot

**URL:** <https://ziggit.dev/t/zaggle-optimizing-mandelbrot/18142>\
**Category:** Showcase\
**Created:** [October 29, 2026, 4:10pm UTC](https://ziggit.dev/t/zaggle-optimizing-mandelbrot/18142 "2026-10-29T16:10:50Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![SuXYIO](https://ziggit.dev/user_avatar/ziggit.dev/suxyio/32/10366_2.png) [@SuXYIO](https://ziggit.dev/u/SuXYIO)\
**Post date:** [October 29, 2026, 4:10pm UTC](https://ziggit.dev/t/zaggle-optimizing-mandelbrot/18142/1 "2026-10-29T16:10:50Z")

</div>

So i was taking my [waggle](https://codeberg.org/suxyio/waggle) project (a tiny graphics lib that depends on MiniFB only, didn’t go too far) [to Zig (zaggle)](https://codeberg.org/suxyio/zaggle)

I had a Mandelbrot example, thought’d be a great thing to optimize.

The underlying implementations are not really changed, so performance should be similar.  
But what I got when benchmarking was this:

 ![Figure_1](https://ziggit.dev/uploads/default/original/2X/2/2c721f1c5f7c9d0d521b6522d8239c9844e25be0.png)  
(data from waggle are labled with `c_`, while zaggle is not labeled;  
`baseline` for naively iterating, `4thrd` for tiling 4 thread implementation, `4async` for tiling 4 `std.Io.async` implementation;  
C version built with `-O3`, Zig version built with `-Doptimize=fast`)

You can see that the Zig baseline outperforms the C baseline, even close to 4 threaded C.

I heard that Zig might be faster than C, that it can do more optimization tricks, but didn’t expect this much tbh

Also, here’s the mandelbrot code for both, 'd be grateful if anyone points out any wrong places / gives optimization stratagies.  
[suxyio/zaggle `examples/src/mandelbrot_perf_log.zig`](https://codeberg.org/SuXYIO/zaggle/src/branch/main/examples/src/mandelbrot_perf_log.zig)  
[suxyio/waggle `examples/mandelbrot.c`](https://codeberg.org/SuXYIO/waggle/src/branch/main/examples/mandelbrot.c)

---

<div class="post-metadata">

**Author:** ![floooh](https://ziggit.dev/user_avatar/ziggit.dev/floooh/32/2989_2.png) [@floooh](https://ziggit.dev/u/floooh)\
**Post date:** [October 29, 2026, 4:37pm UTC](https://ziggit.dev/t/zaggle-optimizing-mandelbrot/18142/2 "2026-10-29T16:37:15Z")

</div>

Did you compile the C code with Zig, and/or `-march=native`? And if your C code is spread across multiple source files, are you building with `-flto` to enable optimization across compilation units?

AFAIK these are the two main differences between C and Zig’s build models. Another smaller issue might be more aggressive optimizations around pointer aliasing in Zig vs C.

But in general, giving the same memory access patterns (e.g. same code structure and data types) and giving the C compiler the same aggressive compilation options that Zig uses by default, I would except nearly byte-by-byte identical output (assuming both compilers are LLVM based) - and that should be true for _all_ compiled languages btw, not just Zig vs C.

Or maybe when on x86 you’re lucky and you hit a sweet spot in Zig’s non-LLVM backend 🙂

PS: looking at the code, this may already be the culprit:

[https://codeberg.org/SuXYIO/waggle/src/commit/b2856d5e23a59560697148b8b922fdfaa5726066/examples/mandelbrot.c#L71](https://codeberg.org/SuXYIO/waggle/src/commit/b2856d5e23a59560697148b8b922fdfaa5726066/examples/mandelbrot.c#L71)

… it looks like you’re calling a callback for each pixel from within `equa_draw_4thrd`, and I guess that function lives in another C source file.

In Zig the per-pixel callback function body will almost certainly be inlined into the caller because Zig builds the entire program as a single compilation unit, while in C it definitely won’t be inlined unless you build with `-flto` (and even then it’s not guaranteed)… and this inlining may in turn unlock more optimizations (like loop unrolling or vectorization)…
