Increase TinyGo's stack size from 14752 -> 16384 - #95
Conversation
|
14752 comes from WASM4. It reserves 6560 bytes of RAM at the start for WASM4-specific data with fixed pointers (frame buffer, inputs, etc) and then 8192 bytes of actual stack: https://github.com/aduros/wasm4/blob/main/cli/assets/templates/rust/.cargo/config.toml It's not applicable to Firefly since the wasm app memory is fully owned by the app. We don't have direct memory manipulation, only proper wasm host function calls. Probably, 448 bytes is a bit too much for the stack? What are you allocating? |
Yes, that's a lot. But I have this one function that load all of my assets, and so it's a ton of local variables as I'm doing a lot of image sub slicing, so lots of It's this function: https://codeberg.org/applejag/digdug/src/commit/74d246387dd941086a5bd8123b19db5ea0aadd37/assets/assets.go#L90-L178 I could probably also split up the function into smaller chunks, as TinyGo or LLVM will inline that code anyways. This stack size limit feels like quite a arbitrary limit. |
|
Oh ok, correction: so it's not the function stack that it's checking. It's actual object sizes. (I misunderstood the error message) It's this part here: https://codeberg.org/applejag/digdug/src/commit/74d246387dd941086a5bd8123b19db5ea0aadd37/assets/assets.go#L131-L136 Players = [4]PlayerSprites{
playerSprites,
loader.PlayerSpritesWithColor(&playerSprites, firefly.ColorDarkGreen),
loader.PlayerSpritesWithColor(&playerSprites, firefly.ColorPurple),
loader.PlayerSpritesWithColor(&playerSprites, firefly.ColorYellow),
}each type PlayerSprites struct {
Right [2]firefly.SubImage
Left [2]firefly.SubImage
}I added a small test to show the sizes: func TestSizes(t *testing.T) {
subimage := reflect.TypeFor[firefly.SubImage]()
t.Logf("firefly.SubImage: align=%d, size=%d", subimage.Align(), subimage.Size())
sprites := reflect.TypeFor[PlayerSprites]()
t.Logf("PlayerSprites: align=%d, size=%d", sprites.Align(), sprites.Size())
array := reflect.TypeFor[[4]PlayerSprites]()
t.Logf("[4]PlayerSprites: align=%d, size=%d", array.Align(), array.Size())
}checking the size (on 32-bit): $ GOARCH=386 go test ./assets/ -v -run TestSize
=== RUN TestSizes
assets_test.go:77: firefly.SubImage: align=4, size=28
assets_test.go:79: PlayerSprites: align=4, size=112
assets_test.go:81: [4]PlayerSprites: align=4, size=448
--- PASS: TestSizes (0.00s)
PASS
ok codeberg.org/applejag/digdug/assets 0.005sSo that's what's happening. I just had a huge struct. So instead of using Players[0] = playerSprites
Players[1] = loader.PlayerSpritesWithColorInto(&playerSprites, firefly.ColorDarkGreen)
Players[2] = loader.PlayerSpritesWithColorInto(&playerSprites, firefly.ColorPurple)
Players[3] = loader.PlayerSpritesWithColorInto(&playerSprites, firefly.ColorYellow)Diff: https://codeberg.org/applejag/digdug/commit/2b6cb50e3dce17e06a0c3d7c09c510867ea42164 With that in mind, yes now I can avoid allocations even without the changes from this PR, in this case. But it could still be nice to add the changes from this PR so if there's other devs that do weird stuff like me, then they have a little more headroom to work with |
|
Yeah, it's fine. While it's better to not have much on the stack, I don't mind having it a few kilobytes bigger. Thank you for digging into it. |
|
Stack size is now configurable: #96 |
I have been coding my app to not do any allocations, but I still got all the allocator functions (
runtime.alloc,runtime.scanConservative, etc) in the final build.After some debugging with
tinygo -print-allocsI found that it was because of this:MaxStackAlloc&StackSizedefinition: https://github.com/tinygo-org/tinygo/blob/d8908249a05f7b8fe45797f833dd5a4e38dfa14e/compileopts/config.go#L254-L270compileopts.Options.StackSizeset by-stack-sizeflag andcompileopts.TargetSpec.DefaultStackSizeis set by"default-stack-size"JSON field-zstack-size=14752from theldflags. Instead you have to tell TinyGo the stack size separatelyIncreasing the maximum stack size from 256 to 1024 by adding either
-stack-size=16384Bflag totinygo buildor adding"default-stack-size": 16384totarget.jsonsolved the issue for me. Shaving off 7598 bytes from my build:Now this is where my knowledge ends. I know that adding this config upped the limit on function stacks, and got TinyGo to skip adding the allocation code. But I don't know why you set
14752limit before to begin with. And I don't know the full consequences of increasing it to16384(+1632)