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

Make better use of space in task detail screen #523

Open
hds opened this issue Feb 14, 2024 · 1 comment
Open

Make better use of space in task detail screen #523

hds opened this issue Feb 14, 2024 · 1 comment
Assignees
Labels
C-console Crate: console. E-easy Effort: easy. Good for newcomers S-feature Severity: feature. This is adding a new feature.

Comments

@hds
Copy link
Collaborator

hds commented Feb 14, 2024

What problem are you trying to solve?

In the task detail screen, there are two panels which split the width of the screen in half. The Task panel and the Waker panel.

The task panel is 7 or 8 lines high (depending on whether the task has a name defined). The Waker panel is just 2 lines high. Additionally, the location of the task can sometimes overflow the width of the Task panel, causing the beginning of the location to not be visible.

See the screenshot below which illustrates how the location can't be seen yet we have plenty of space elsewhere:

tokio-console-cant_see_location

Additionally, if the task doesn't have a name, we don't list the name line at all, which results in an empty line at the bottom of the Task panel:

tokio-console-empty_line

How should the problem be solved?

The space on that panel should be better optimised.

The Waker panel could be split onto more lines. So instead of looking like this:

╭Waker─────────────────────────────────────────────────────────────────────────╮
│Current wakers: 1 (clones: 10461, drops: 10460)                               │
│Woken: 5230 times, last woken: 75.831727ms ago                                │
│                                                                              │
│                                                                              │
│                                                                              │
│                                                                              │
│                                                                              │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯

It could be split onto multiple lines:

╭Waker─────────────────────────────────────────────────────────────────────────╮
│Current wakers: 1                                                             |
|  Clones: 10461                                                               |
|  Drops: 10460                                                                │
│Woken: 5230 times,                                                            │
│Last woken: 75.831727ms ago                                                   │
│                                                                              │
│                                                                              │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯

This would free up more horizontal space. Then the Task panel could be made wider and the Waker panel narrower.

Additionally, the hight should depend on how many lines are actually needed. If the task has no name, then we can make the Task and Waker panels one line shorter.

For bonus points, the Location field in the Task panel could be split onto multiple lines (up to some reasonable maximum like 2 or 3) in case it still doesn't fit into the space provided. If done, it would make sense to submit this change as a separate PR.

This could end up with the two panels looking like this:

╭Task─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮╭Waker──────────────────────╮
│ID: 22 ⏸                                                                                                                         ││Current wakers: 1          |
│Name: my favorite task                                                                                                           │|  Clones: 10461            |
│Target: tokio::task                                                                                                              │|  Drops: 10460             │
│Location: src/tokio-with-the-console/src/a_very_long_module_name/yet_another_very_long_module_name/finally_one_more_long_module_n││Woken: 5230 times,         │
|          ame.rs:6:10                                                                                                            ││Last woken: 75.831727ms ago│
│Total Time: 15m22s                                                                                                               ││                           |
│Busy: 5.76s (0.63%)                                                                                                              ││                           │
│Scheduled: 497.29ms (0.05%)                                                                                                      ││                           │
│Idle: 15m15s (99.32%)                                                                                                            ││                           │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯╰───────────────────────────╯

However, if the location isn't so long, we should probably not squash the Waker panel up any more than necessary:

╭Task──────────────────────────────────────────────────────────────────────────╮╭Waker─────────────────────────────────────────────────────────────────────────╮
│ID: 22 ⏸                                                                      ││Current wakers: 1                                                             |
│Name: my favorite task                                                        │|  Clones: 10461                                                               |
│Target: tokio::task                                                           │|  Drops: 10460                                                                │
│Location: src/main.rs:21:11                                                   ││Woken: 5230 times,                                                            │
│Total Time: 15m22s                                                            ││Last woken: 75.831727ms ago                                                   │
│Busy: 5.76s (0.63%)                                                           ││                                                                              │
│Scheduled: 497.29ms (0.05%)                                                   ││                                                                              │
│Idle: 15m15s (99.32%)                                                         ││                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯╰──────────────────────────────────────────────────────────────────────────────╯

Implementation hints

Currently we hard code the height of the Task and Waker panels here in two places depending on whether there is an active warning for the task being viewed. That happens here:

layout::Constraint::Length(10),

and here:
layout::Constraint::Length(10),

We could make that height dependent on the real height of those panels.

The Task and Waker panel contents are created inline in the render function. This is done after the constraints have already been calculated. Instead of that, the creation of each panel could be factored out into separate functions (or actual widget implementations). If the creation of each panel contents also returns the minimum area that it needs (width and height), then the "chunking" of the total area could be performed a bit more dynamically.

Task panel:

let mut overview = Vec::with_capacity(8);
overview.push(Spans::from(vec![
bold("ID: "),
Span::raw(format!("{} ", task.id_str())),
task.state().render(styles),
]));
if let Some(name) = task.name() {
overview.push(Spans::from(vec![bold("Name: "), Span::raw(name)]));
}
overview.push(Spans::from(vec![
bold("Target: "),
Span::raw(task.target()),
]));
let title = "Location: ";
let location_max_width = stats_area[0].width as usize - 2 - title.len(); // NOTE: -2 for the border
let location = if task.location().len() > location_max_width {
let ellipsis = styles.if_utf8("\u{2026}", "...");
let start = task.location().len() - location_max_width + ellipsis.chars().count();
format!("{}{}", ellipsis, &task.location()[start..])
} else {
task.location().to_string()
};
overview.push(Spans::from(vec![bold(title), Span::raw(location)]));
let total = task.total(now);
let dur_percent = |name: &'static str, amt: Duration| -> Spans {
let percent = amt.as_secs_f64().percent_of(total.as_secs_f64());
Spans::from(vec![
bold(name),
styles.time_units(amt, view::DUR_LIST_PRECISION, None),
Span::from(format!(" ({:.2}%)", percent)),
])
};
overview.push(Spans::from(vec![
bold("Total Time: "),
styles.time_units(total, view::DUR_LIST_PRECISION, None),
]));
overview.push(dur_percent("Busy: ", task.busy(now)));
overview.push(dur_percent("Scheduled: ", task.scheduled(now)));
overview.push(dur_percent("Idle: ", task.idle(now)));

Waker panel:

let mut waker_stats = vec![Spans::from(vec![
bold("Current wakers: "),
Span::from(format!("{} (", task.waker_count())),
bold("clones: "),
Span::from(format!("{}, ", task.waker_clones())),
bold("drops: "),
Span::from(format!("{})", task.waker_drops())),
])];
let mut wakeups = vec![
bold("Woken: "),
Span::from(format!("{} times", task.wakes())),
];
// If the task has been woken, add the time since wake to its stats as well.
if let Some(since) = task.since_wake(now) {
wakeups.reserve(3);
wakeups.push(Span::raw(", "));
wakeups.push(bold("last woken:"));
wakeups.push(Span::from(format!(" {:?} ago", since)));
}
waker_stats.push(Spans::from(wakeups));
if task.self_wakes() > 0 {
waker_stats.push(Spans::from(vec![
bold("Self Wakes: "),
Span::from(format!(
"{} times ({}%)",
task.self_wakes(),
task.self_wake_percent()
)),
]));
}

Keep in mind that the self wakes count is optional, the waker panel will have a different minimum height if it is present!

if task.self_wakes() > 0 {

Any alternatives you've considered?

We could only split the Location field onto multiple lines, and leave the rest of the layout where it is.

@hds hds added S-feature Severity: feature. This is adding a new feature. E-easy Effort: easy. Good for newcomers C-console Crate: console. labels Feb 14, 2024
@devanbenz
Copy link
Contributor

lol whoops! meant to have this one assigned @hds 😅 I was mobile when I commented on the other issue 😆

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-console Crate: console. E-easy Effort: easy. Good for newcomers S-feature Severity: feature. This is adding a new feature.
Projects
None yet
Development

No branches or pull requests

2 participants