Unrolling limit or build error for too large functions

Context

To learn zig, I’m making a small game for my family. I’m using raylib and target emscripten to run on the TV’s browser.

At some point, to play with comptime, I had some inline for, mostly so the compiler could hint me at what is was not know at comp time. A few weeks later, many comptime known values became variables, I increased some entity count and it started to crash only on the TV. It was troublesome to debug, because debugging facility on the TV wasn’t great (no debugger, no browser console), and I couldn’t reproduce the crash on the development computer’s browser or the desktop version.

Tonight I found out the culprit was that inline for. It was fine until 80 unrolled iterations, but crashed at 100.

Problem

Here is a degenerate example to reproduce the issue:

// call this anywhere with some variant of 
// std.debug.print("Sum = {}\n", .{sumOfZeroToThreePlusI()});

fn sumOfZeroToThreePlusI() u64 {
    const loop_count = 500;
    var sum: u64 = 0;
    inline for (0..loop_count) |i| {
        const added_value = @as(u64, @intCast(std.time.milliTimestamp())) % 4;
        sum += added_value + i;
    }
    return sum;
}

For this version, when adding inline, .wasm size goes from 959 kb to 1352 kb, small change (single line change) build time go from 6-7 seconds to 125 seconds, and it crashes at runtime.

Question

Can I get some kind of build time warning that a huge function was created, through unrolling or otherwise, because it seems to cause crashes depending on the platform, and I would rather have a build time failure that tells me it produced unusable code, rather than finding out at runtime.

The soft limit varies across different browsers. Code that works fine on some browsers may not run on a TV browser. Perhaps the most reliable method is to use wasm-opt to analyze function sizes in the compiled output and report functions that exceed the threshold. The threshold can only be determined based on the specific target browser.

2 Likes

I found out it’s not super useful to look for a precise value, because around 202k of binary bytes, when called every frame around 60 fps, it will crash after about 20 seconds. At 204k of binary size, it doesn’t execute once without crashing.

That’s checking the [binary-bytes], but there’s also [total] that seems to be a proxy for that.

I would still be happy to have a zig-side warning, or diagnostic information I can use to make my own build time failure. Basically, I want to know metrics per function about the Sema output (the AIR).