How to debug flickering in my app?

Folks,

I’m working on an app to monitor GPU stats and I’m facing some flickering when I start using Gauge or BarChart to report engine utilization. When I just use Table, Text, Blocks, etc, there’s no flickering even at the rate I’m redrawing, but when Gauge/BarChart are used it flickers every couple of seconds. Are there any pointers on how to start debuggin this? Thanks in advance, and ratatui is pretty cool!

– Ulisses

I’m using ratatui and crossterm 0.28.1 on Linux, forgot to mention that.

What terminal are you using? I haven’t had issues using those widgets, but I have had an issue where a cross-platform terminal I would use would have a flicker effect. The cause was the way the screen was drawn and it was the reason I stopped using it. You could try using a different terminal and see if that fixes the issue.

Without looking at your code, I’d guess the most common problem would be that you’re calculating something that’s momentarily inconsistent between frames and rendering that. This might be a layout calculation, a data inconsistency, something that is render size or position related, …

Flickering probably means that you’re drawing something that’s not the content and then drawing the content. There’s a few things that could cause that, and I can only really think of things that you’d be doing in your app. Clearing the screen between frames, drawing an incomplete frame, drawing multiple different frames, etc.

Re: debugging, insert a pause (std::thread::sleep) after your drawing code for some meaningful amount of time that would allow you to see the flicker as actual frames. This will allow you to understand if it’s happening during the terminal::draw() call (it shouldn’t be, barring some weird bug) or between draws (this is more likely). Add a timestamp somewhere on the display and log when drawing related things happen to a file. Record a screencast of this happening and correlate events with your logs.

The only non-deterministic part of Ratatui that I know of is Layout calculations, which we have a cache specifically setup to make sure that it gets the same result in between frames. You can hit non-determinism if the number of layout calls goes beyond the default amount. We arbitrarily set that to 500 (two layouts call for every row and every column of a 200x50 terminal), but you can bump that up with a call to Layout::init_cache(). It’s unlikely to be this in most situations though.

Show a recording and link some code for more ideas.

1 Like

Thanks, @AceofSpades5757, I may try that after I do some more debugging with crossterm.

@joshka , thanks for the tips, I’ll do that!! I’m confident it’s my bug and not ratatui’s or crossterm’s.

@joshka , the sleep tip worked out. I had my model come up empty when it shouldn’t which led to most of screen going black for a frame and then back. That was a good tip, thanks so much.

Great to hear you found the problem.

There’s something else you (or someone else facing a similar problem) could also have done there to diagnose things. If your app has a view model (or any similar concept where there’s some state that gets translated into a view), then logging the debug representation of the model each time it’s rendered might have highlighted the problem here. You can also log the diff between two states to help notice when there’s an oddity like this. In this instance this would have shown a large diff for each flicker rather than a small one that you might anticipate on each frame.

1 Like