Redraw only the spinner when nothing else has changed#5571
Conversation
88c40e0 to
84a9210
Compare
84a9210 to
7270d5a
Compare
|
Went in a rabbit hole so it'll take some time to wrap up a working solution, my original approach introduced a bug where the full redraw event could be lost while the spinner was shown. I'll let you know when I am done! |
7270d5a to
050ff91
Compare
|
Alright so the problem was that some processes that update the layout do not themselves request a redraw and assumed it would be done through the ticker loop, adding a single full redraw after the ticker has completed (aka whatever job it was doing is done) fixed my issue. |
stefanhaller
left a comment
There was a problem hiding this comment.
Great work!
This only fixes it for the bottom line status view; there's also the inline status that is used e.g. for fast-forwarding a branch, would be nice if this could be improved too. The code is in InlineStatusHelper.renderContext; it seems safe to call OnUIThreadContentOnly there, too. When I quickly tested it though, it didn't make as much of a difference as I would have expected, so maybe there's something else going on in that case. (Found it: it ends up calling Gui.render further down the call chain which undoes the optimization.) I'd be ok with solving this in a followup.
One quirk: if a user sets their gui.spinner.frames to a bunch of strings of unequal lengths, this used to push the rest of the status line over as necessary with every frame, and now it no longer does because we skip the layout. We could ignore this since it's unlikely that users do this, but we could also not let them; I pushed a commit (8a7e1fe) that rejects configs that try this.
8a7e1fe to
47c0e94
Compare
47c0e94 to
b0b690b
Compare
|
Also, were you planning on looking into the WithWaitingStatusSync issue? (either as part of this PR, or as a followup) |
f1d70cf to
6b846f7
Compare
|
I have now added it to sync events too, this one takes the views as parameters otherwise some of the UI would update before the task is actually done. For example if moving a commit down, the UI would show the commit moved down at the same time as the spinner starts to spin, but the highlight and control would only be given back to the user when truly done. I added a commit which should probably be another PR, let me know if that's the case and I will happily do so. |
Ah, good, but that's actually not what I meant. I mistyped in my last comment, I meant WithInlineStatus, not WithWaitingStatusSync, sorry. The WithInlineStatus change needs to happen in Also, for this change the commit structure doesn't work. You can't make an API-breaking change in one commit and then adapt callers in a later commit. In this case I'd suggest to leave the commits as you had them before (59766d3 and e9a4650), and then add a new commit after that for changing
But it called Layout with every redraw, so it should still make a difference.
That's fine, happy to include that here. |
|
Ah that makes more sense, might as well make the changes in this PR for the in-line spinner. |
6b846f7 to
b3f6e49
Compare
|
I took a conservative approach with the in-line spinner, I did not want to change the PS: Thank you for taking the time with the code reviews, it is very much appreciated :) |
1c88afa to
0a3ab7e
Compare
0a3ab7e to
22f542e
Compare
I don't think it's so bad to extend Context; it has only two implementations really, SimpleContext and ListContextTrait. I pushed dfc3593 that adds I'm still not super happy with it, because there's an asymmetry: HandleRender takes care of calling Apart from that, I pushed two more trivial fixups. Now the only remaining problem is that the commit "Support to request a content-only UI refresh" still doesn't compile. |
|
Wait, none of this HandleContentOnlyRender stuff makes any sense; I didn't think. Currently the only difference between HandleRender and HandleContentOnlyRender is that the former calls Gui.render. We should totally move this out to the call sites (many of which don't actually need it even, as far as I can see), then we don't need two different methods on Context. Since this is a bigger change and requires careful examination of each call site, I suggest we do this in a followup and simply drop the inline status commit (and my fixups) from this branch. |
efcd664 to
8b69e1e
Compare
|
Done, I also ensured all commits can be built and tests pass for each. |
stefanhaller
left a comment
There was a problem hiding this comment.
Looks good, thanks. There's one more little style thing that I pushed a fixup for, but I'm happy with this state now.
I will open another PR to discuss the in-line changes.
I'm not really sure this will save me time. Reviewing such a PR will probably take as much time as making the change myself, so I think I'd prefer to do that in this case.
|
For some reason Github swallowed my inline comment for why I made that last fixup. I'm too lazy to type that again, let me know if you want to discuss any of that. |
This didn't cause a bug so far because switching repos always happens from within an OnWaitingStatus, so the spinner would take care of calling layout and draw. However, later in this branch we are going to optimize the spinner so that it no longer calls layout, at which point this would break, so make sure we rerender at the point where it's needed.
This skips the whole-UI layout calculations, and lets tcell's dirty cell handling redraw only changed cells.
The spinner looks weird if they don't. While we're at it, validate that frames must not be empty, which would have crashed with a division by zero.
47477a4 to
706f1d0
Compare
Sounds good!
I can see how making the argument explicit have benefits and is less ambiguous to callers, all good. |
Instead of redrawing the two views on each tick, only redraw the spinner
706f1d0 to
b7edcba
Compare
|
@AntoineGS Here's the followup-PR for the inline spinner: #5592. Code review would be appreciated, but especially testing; I feel this is a bit of a risky change, there might be redraw glitches where a layout is missing now. |
As a followup to #5571, improve performance for inline spinners too. This requires a bit of preparation; in particular, we change ListContextTrait.HandleRender to no longer force a UI layout/redraw, so callers need to take care of this themselves where needed. This requires careful testing to see that we didn't miss any situation where redrawing only worked by accident; see the first commit of the branch for an example.
PR Description
This fixes #4734, where lazygit would use a lot of CPU when the spinner was shown due to redrawing the entire screen every time the spinner needed a redraw.
The change adds the ability to request a UI redraw without invalidating the full UI, thus only redrawing the spinner, re-routing the spinner to this new flow.
CPU usage on a chromebook went from 60% to 5% when the spinner is shown.
Changing the refresh rate of the spinner from 50ms to 200ms brings it down from 5% to 1% if ever we would like to change the default, personally I prefer the slower moving spinner, but that's subjective.
Please check if the PR fulfills these requirements
go generate ./...)