Any tips to reach 30 FPS in Lua?

Hello! I’m making a port of Celeste Classic from PICO-8 to Playdate. And I’m struggling to reach a stable 30 FPS on device. I initially tried to stay close the PICO-8 Lua structure (global all the things!). I then tried to apply the usual Lua/Playdate tips (local and sprites all the things!). The game usually runs around 28 FPS with ups and downs (between 25 to 30). I'd like to make it a solid and stable 30 FPS.

What would be a good process to do that? I've tried the C and Lua Sampler on device as well as the Device Info Screen. But I'm not even sure what to do and what to look for there.

Device Info screen


My source code is available here: GitHub - hteumeuleu/celeste: An unofficial port of Celeste Classic to Playdate

1 Like

There's a known performance problem with the current firmware. The next version of the firmware should be better.

Until then can test on recovery firmware (hold lock + menu + A + B for a while and follow the prompts) to get more of an idea about how your game runs.

2 Likes

I was already at around 25-30 FPS before update 1.13. But that update did drop the framerate of about 5 FPS (so around 20-25 FPS). I did some more optimizations after that to gain more FPS. So it's good news if the next firmware improves things. Still, I'd love to get directions on how to improve things in general. (And what should I look for in the Sampler or Device Info windows?)

I'll take a look at your source soon.

How does it run on 1.11.1 recovery firmware?

So... your problem appears to be garbage collection.

  • spikes and frame drops are due to garbage collection, you can try to manage it yourself using collectgarbage() Lua function
  • in Sampler, choose Device > Lua and then look for spikes, drag an area over them with the mouse to show only results from that period
  • blue highlighted section of timeline shows few lines of samples, note ~15% of time spent doing GC

on latest beta

  • 1.13.3 beta ~24-30
  • 1.13.3 beta playdate.display.getRefreshRate(0) ~26-45

rebuilding with old 1.11.1 SDK

  • 1.11.1 recovery ~24-30
  • 1.11.1 recovery playdate.display.getRefreshRate(0) ~28-38

notes

  • debugging prints in a hot/frequent code path will slow down your game "game_just_restarted false" you only do this on the menu but it's worth mentioning
2 Likes

Thank you so much for your help! This is definitely pushing me on the right track.

3 Likes

There are some additional, more involved things you can do @hteumeuleu ; namely splitting data according to access patterns, as well as creating your data structures in a way that doesnt generate additional garbage (think ring buffer, as an example).

These are a bit more involved to be sure, but if you'd like help going down that route, feel free to DM me.

Edit: additional info

I found an old perf capture from my game (Gun Trails) back when it was Lua based, and these techniques were able to keep memory usage nearly static, and basically eliminate GC spikes.

Screenshot 2023-03-15 at 1.45.35 PM

3 Likes