Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Odd Clear Behavior in yarnish and multi example #451

Closed
mitsuhiko opened this issue Jul 30, 2022 · 19 comments
Closed

Odd Clear Behavior in yarnish and multi example #451

mitsuhiko opened this issue Jul 30, 2022 · 19 comments
Assignees

Comments

@mitsuhiko
Copy link
Collaborator

mitsuhiko commented Jul 30, 2022

This seems like a regression from what I remember. The yarnish example has 4 virtual concurrent build spinners and once they are done, three print out waiting... and one is cleared resulting in this:

[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 📃  Building fresh packages...
[1/?]   waiting...
[2/?]   waiting...
[3/?]   waiting...
✨  Done in 13 seconds

I expected either none of them to show up or all 4.

Likewise I think there is a bug in the multi example where one retains the bar:

starting!
pb1 is done!
[00:00:02] ########################################     128/128     done
pb3 is done!
pb2 is done!

Tested on 39ebd5f. Both of those examples use the multi bar clear function.

@mitsuhiko
Copy link
Collaborator Author

mitsuhiko commented Jul 31, 2022

I bisected it down on the yarnish example. First run claimed 1d47e1d to be the regression but clearly some flakiness caused the bisect to isolate the wrong one.

A few reruns showed 0f33289 (fix for #426) to be the issue. The commit before that seems to work fine still.

@mitsuhiko
Copy link
Collaborator Author

I think that belongs to #438 but I'm not entirely sure. There is no clear merge commit mentioning the PR.

@djc
Copy link
Collaborator

djc commented Jul 31, 2022

Yes, it's #438.

@chris-laplante
Copy link
Collaborator

I'll take a look.

@chris-laplante chris-laplante self-assigned this Aug 2, 2022
@chris-laplante
Copy link
Collaborator

chris-laplante commented Aug 2, 2022

What's strange is that if you add a call to drop(pb) after the call to finish_with_message, after:

pb.finish_with_message("waiting...");

then it works as expected. I would have thought that pb would automatically get dropped when scope/closure the thread is executing is done, right? So I don't understand why the drop makes a difference.

@mitsuhiko
Copy link
Collaborator Author

I cannot reproduce that it works as expected. This is fundamentally some sort of race condition so every once in a while it works when you run it. Potentially you just had a few lucky runs.

@chris-laplante
Copy link
Collaborator

Hah, sure enough I re-ran it and you're right :/.

@chris-laplante
Copy link
Collaborator

chris-laplante commented Aug 2, 2022

The issue here is that the zombie pruning code I added changed the semantics of MultiProgress. Previously, MultiProgress never forgot about progress bars (unless you MultiProgress::removed them). That's true even if you call finish (or friends) on the ProgressBars. Zombie pruning taught MultiProgress to forget about progress bars that don't exist anymore (because they got dropped). Because of this, clear no longer clears those dropped ProgressBars.

The yarnish example is acting non-deterministically because the order in which those 4 pbs are dropped is random. Zombie pruning (and adjustment of last_line_count) happens in MultiState::draw, but MultiState::clear doesn't use draw. I haven't traced through exactly what is happening, but I don't think I'll bother because I have a proposition.

I now see that zombie pruning changes the behavior of MultiProgress in unintended ways. I'd like to propose turning off zombie handling by default, and making it an option you can set on MultiProgress. For example, MultiProgress:set_reap_zombies(True). If zombie reaping is enabled, I'd also propose making MultiProgress::clear an illegal operation. It doesn't make sense to call clear on a MultiProgress that can't necessarily clear everything it was responsible for drawing. If a user utilizing MultiProgress in zombie reap mode needs to clear pbs, then they are responsible for not letting those pbs becomes zombies in the first place.

(Here's how you could write the yarnish example using zombie reaping by the way: chris-laplante@98478c6#diff-23742e02d3318a218c4777f365fd16cd606fb46a7770c9433a4a9ec46d98f655)

What do you think?

@djc
Copy link
Collaborator

djc commented Aug 2, 2022

To restate the reason for introducing zombie reaping in the first place (from #426):

Since we never call MultiProgress::remove on ProgressBars that are dropped/finished (see #419), bars are always redrawn even when they don't need to be. When the number of bars (n) becomes greater than terminal lines (m), on each draw MultiProgress will clear the last m lines but write n lines, leaving m - n lines in the scrollback history.

So could we get the terminal height from console and only reap once we run out of lines instead of requiring extra configuration/setup from the user?

@mitsuhiko
Copy link
Collaborator Author

To me it seems at least that this keeping track in to_clear and manually invoking finish_and_clear is something that the MultiProgress could do automatically itself?

@chris-laplante
Copy link
Collaborator

So could we get the terminal height from console and only reap once we run out of lines instead of requiring extra configuration/setup from the user?

Personally I'd rather not deal with console height if we don't have to, since the user can resize the terminal whenever they want and mess us up. I think even if we did something based on height, it still wouldn't fix clear. Once a pb has been reaped MultiProgress has lost track of it. Regardless of when that happens, clear won't be able to touch it.

@chris-laplante
Copy link
Collaborator

chris-laplante commented Aug 3, 2022

To me it seems at least that this keeping track in to_clear and manually invoking finish_and_clear is something that the MultiProgress could do automatically itself?

I think this is on the right track. MultiProgress should keep track of previously-reaped progress bars. The last number of lines that were printed is enough. Then clear just has to also clear that number in addition to whatever is being displayed by the currently active set.

One wrinkle: calling MultiProgress::println should reset the reaped line counter to 0, since clear can't erase lines above the printed message without also erasing the message itself. We should do it for MultiProgress::suspend too - making the assumption that the user wrote something to the terminal during the suspend.

@chris-laplante
Copy link
Collaborator

I did some more digging on this today. I think I can fix the zombie reaping so that MultiProgress::clear works well, with a caveat. Previously you could do a draw operation after a clear (e.g. just a tick on some pb that's part of the MultiProgress) and it would be able to reconstitute everything, including stuff that had been dropped. Now that zombie reaping is a thing, that re-draw will only be able to re-draw what hasn't been reaped.

Also, I think I can more clearly characterize the interaction between reaping and MultiProgress::println. println will be able to print lines above anything that hasn't been reaped. I don't foresee this as an issue because MultiProgress::println is new for 0.17.0 anyway. What do you think? Are these limitations ok?

@chris-laplante
Copy link
Collaborator

@djc @mitsuhiko thoughts on above?

@mitsuhiko
Copy link
Collaborator Author

I think it makes sense.

@djc
Copy link
Collaborator

djc commented Aug 9, 2022

I did some more digging on this today. I think I can fix the zombie reaping so that MultiProgress::clear works well, with a caveat. Previously you could do a draw operation after a clear (e.g. just a tick on some pb that's part of the MultiProgress) and it would be able to reconstitute everything, including stuff that had been dropped. Now that zombie reaping is a thing, that re-draw will only be able to re-draw what hasn't been reaped.

This seems to make sense -- remind me what the criteria for getting reaped again? Does it even make sense to tick something in a state where it can be reaped?

Also, I think I can more clearly characterize the interaction between reaping and MultiProgress::println. println will be able to print lines above anything that hasn't been reaped. I don't foresee this as an issue because MultiProgress::println is new for 0.17.0 anyway. What do you think? Are these limitations ok?

Seems fine!

@chris-laplante
Copy link
Collaborator

This seems to make sense -- remind me what the criteria for getting reaped again? Does it even make sense to tick something in a state where it can be reaped?

A progress bar becomes a zombie when it is droped. So you will never be able to tick it after that, no.

chris-laplante added a commit to chris-laplante/indicatif that referenced this issue Aug 12, 2022
Fixes console-rs#464 and console-rs#451

Possibly fixes console-rs#411 (if not already fixed?)
chris-laplante added a commit to chris-laplante/indicatif that referenced this issue Aug 13, 2022
Fixes console-rs#464 and console-rs#451

Possibly fixes console-rs#411 (if not already fixed?)
chris-laplante added a commit to chris-laplante/indicatif that referenced this issue Aug 17, 2022
Fixes console-rs#464 and console-rs#451

Possibly fixes console-rs#411 (if not already fixed?)
chris-laplante added a commit to chris-laplante/indicatif that referenced this issue Aug 17, 2022
Fixes console-rs#464 and console-rs#451

Possibly fixes console-rs#411 (if not already fixed?)
chris-laplante added a commit to chris-laplante/indicatif that referenced this issue Sep 8, 2022
Fixes console-rs#464 and console-rs#451

Possibly fixes console-rs#411 (if not already fixed?)
chris-laplante added a commit to chris-laplante/indicatif that referenced this issue Sep 8, 2022
Fixes console-rs#464 and console-rs#451

Possibly fixes console-rs#411 (if not already fixed?)
chris-laplante added a commit to chris-laplante/indicatif that referenced this issue Sep 8, 2022
Fixes console-rs#464 and console-rs#451

Possibly fixes console-rs#411 (if not already fixed?)
djc pushed a commit that referenced this issue Sep 13, 2022
Fixes #464 and #451

Possibly fixes #411 (if not already fixed?)
@chris-laplante
Copy link
Collaborator

Hi @mitsuhiko - when you get a chance, can you please re-test with main?

@mitsuhiko
Copy link
Collaborator Author

This seems to be resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants