Mind Your Memory! A Tiny Bevy Performance Investigation Story.

2024-04-17

I've spent the last couple of days trying to track down some performance problems with Wee Boats. It hasn't been a lot of fun but I have learnt some things and I want to write them down so I don't forget. Maybe I'm a thick eejit for not knowing this, and my conclusions are probably wrong in many ways but sure look, what can ya do.

For a little context, we are making Wee Boats using Rust and the Bevy Game Engine.

Main Learning

Files take up much more space when they are loaded into RAM than when they are on disk. An example is a jpg can expand to about 10 to 12 times its size when loaded into memory. :O

The Initial Situation

We want everything to load as fast as possible in Wee Boats. The easiest way to do this is to load all our assets into the game on startup and then everything is ready to go. Super! Our assets folder with images and music is currently around 200MB so my assumption was that we would be dropping about 200MB into RAM, and I was ok with that! I generally test on my desktop with far too much RAM for its own good so I didn't see any problems.

Ah shite, there's a problem?

It was only when moving to my laptop with 8GB RAM that I would notice the game really struggling on startup. I thought this was just the game being a bit slow to read from disk. My initial thought for solving this was just to pause running the actual game until we finish this loading process.

For the craic, I went to check the system monitor to see if it showed anything interesting and then I saw that the game would suddenly want to hog about 3GB of RAM, all in one munch. And then the stalling of the game was the laptop running out of RAM and needing to turn to slower SWAP memory.

3GB of RAM?

How is that even possible? That's a load and this is only a lil game.

My initial hunch was wondering if I was loading images several times into memory for every time it was spawned into the world. Turns out this wasn't the case as the asset_server.load() function in Bevy keeps track if the asset has already been loaded and returns back an id of the asset to you. Alright, I've learned something there.

I headed desperately to the Discord for help where I was told that files like .jpgs and .pngs are actually compressed on disk and expand by about 10 to 12 times their size when loaded into memory. Ah bugger, I didn't know that! I suppose that's a new thing learnt.

Change in Plan!

Well now I need to re think my "load everything on startup" strategy. I can't be at that any more. Knowing this, I now see the worst offender images and am in the middle of implementing a lazy loading system. For our logbook sketches, we will load in the images for the nearest pages that you're on and load and unload as you page through the logbook. Its a bit more of a hassle to implement but we now use about 600MB of RAM. I can defo still improve on that but we have the back broken in this now!

Profiling Troubles with Bevy

I find profiling with Bevy difficult. I have tried using Tracy but firstly its tricky to get running. I can't get it running on Linux for love nor money and then have to go to Windows where they have an easier to run binary. The time I did get it running, I couldn't understand what was going on with my readings. It was hard to parse the data at all to find actionable areas of improvements. This friction is enough for me to fall off from using these tools at all with Bevy which is a big loss. It would be class if Bevy made it easy to get into the details of how my game runs and where the problem areas are!