Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3e09105

Browse files
committed
New table view for explain
1 parent f60a28b commit 3e09105

11 files changed

Lines changed: 376 additions & 192 deletions

File tree

crates/hyperqueue/src/client/output/cli.rs

Lines changed: 200 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ use crate::common::arraydef::IntArray;
4040
use crate::common::utils::str::{pluralize, select_plural, truncate_middle};
4141
use crate::worker::start::WORKER_EXTRA_PROCESS_PID;
4242
use anyhow::Error;
43-
use colored::Color as Colorization;
4443
use colored::Colorize;
44+
use colored::{Color as Colorization, ColoredString};
4545
use std::collections::BTreeSet;
4646
use std::fs::File;
4747
use tako::gateway::{
@@ -281,7 +281,7 @@ impl Output for CliOutput {
281281

282282
let manager_info = configuration.get_manager_info();
283283
let mut rows = vec![
284-
vec!["Worker ID".cell().bold(true), id.cell()],
284+
vec!["Worker".cell().bold(true), id.cell()],
285285
vec!["State".cell().bold(true), state],
286286
vec!["Hostname".cell().bold(true), configuration.hostname.cell()],
287287
vec!["Started".cell().bold(true), format_datetime(started).cell()],
@@ -1046,97 +1046,176 @@ impl Output for CliOutput {
10461046
);
10471047
}
10481048

1049-
fn print_explanation(
1050-
&self,
1051-
task_id: TaskId,
1052-
worker_id: WorkerId,
1053-
explanation: &TaskExplanation,
1054-
) {
1055-
let all = explanation.variants.len();
1056-
let count: usize = explanation
1057-
.variants
1058-
.iter()
1059-
.map(|e| if e.is_empty() { 1 } else { 0 })
1060-
.sum();
1061-
if count > 0 {
1062-
if all == 1 {
1063-
println!(
1064-
"Task {task_id} {} on worker {worker_id}.",
1065-
"can run".color(colored::Color::Green)
1066-
);
1067-
} else {
1068-
println!(
1069-
"Task {task_id} {} on worker {worker_id}, ({count}/{all} variants)",
1070-
"can run".color(colored::Color::Green)
1071-
);
1072-
}
1073-
if explanation.n_task_deps == 0 {
1074-
println!("Task is directly executable because it does not have any dependencies.",);
1075-
} else if explanation.n_waiting_deps == explanation.n_task_deps {
1076-
println!(
1077-
"Task is directly executable because all dependencies ({}) are already finished.",
1078-
explanation.n_task_deps
1079-
);
1080-
} else {
1081-
println!(
1082-
"Task is not directly executable because {} dependencies are not yet finished.",
1083-
format!("{}/{}", explanation.n_waiting_deps, explanation.n_task_deps)
1084-
.color(colored::Color::Red)
1085-
);
1086-
}
1087-
} else if all == 1 {
1049+
fn print_explanation(&self, task_id: TaskId, explanation: &TaskExplanation) {
1050+
if explanation.n_task_deps == 0 {
10881051
println!(
1089-
"Task {task_id} {} on worker {worker_id}.",
1090-
"cannot run".color(colored::Color::Red)
1091-
);
1052+
"Task {} is {} to run because it has no dependencies.",
1053+
task_id.to_string().color(colored::Color::Cyan),
1054+
"ready".color(colored::Color::Yellow),
1055+
)
1056+
} else if explanation.n_waiting_deps == explanation.n_task_deps {
1057+
println!(
1058+
"Task {} is {} to run because its all {} dependencies are finished.",
1059+
task_id.to_string().color(colored::Color::Cyan),
1060+
"ready".color(colored::Color::Yellow),
1061+
explanation
1062+
.n_task_deps
1063+
.to_string()
1064+
.color(colored::Color::Cyan),
1065+
)
10921066
} else {
10931067
println!(
1094-
"Task {task_id} {} on worker {worker_id}, none of {all} variants.",
1095-
"cannot run".color(colored::Color::Red)
1096-
);
1068+
"Task {} is {} to run, because {} dependencies are not finished.",
1069+
task_id.to_string().color(colored::Color::Cyan),
1070+
"not ready".color(colored::Color::Green),
1071+
format!("{}/{}", explanation.n_waiting_deps, explanation.n_task_deps)
1072+
.to_string()
1073+
.color(colored::Color::Red)
1074+
)
10971075
}
1098-
for (i, explanations) in explanation.variants.iter().enumerate() {
1099-
if all > 1 && !explanations.is_empty() {
1100-
println!("Resource variant {i}:")
1101-
}
1102-
for expl in explanations {
1103-
match expl {
1104-
TaskExplainItem::Time {
1105-
min_time,
1106-
remaining_time,
1107-
} => {
1108-
println!(
1109-
"* Task requests at least {} of running time, but worker remaining time is: {}.",
1110-
human_duration(chrono::Duration::from_std(*min_time).unwrap())
1111-
.color(colored::Color::Cyan),
1112-
human_duration(chrono::Duration::from_std(*remaining_time).unwrap())
1113-
.color(colored::Color::Red),
1114-
)
1115-
}
1116-
TaskExplainItem::Resources {
1117-
resource,
1118-
request_amount,
1119-
worker_amount,
1120-
} => {
1121-
println!(
1122-
"* Task requests at least {}, but worker provides {}.",
1123-
format!("{} {}", request_amount, resource).color(colored::Color::Cyan),
1124-
format!("{} {}", worker_amount, resource).color(colored::Color::Red),
1125-
)
1126-
}
1127-
TaskExplainItem::WorkerGroup {
1128-
n_nodes,
1129-
group_size,
1130-
} => {
1131-
println!(
1132-
"* Task requests at least {} nodes, but worker is in group of size {}.",
1133-
format!("{}", n_nodes).color(colored::Color::Cyan),
1134-
format!("{}", group_size).color(colored::Color::Red),
1135-
)
1076+
let mut rows = Vec::new();
1077+
for w in &explanation.workers {
1078+
let all_varints = w.variants.len();
1079+
let runnable_variants: usize = w
1080+
.variants
1081+
.iter()
1082+
.map(|e| if e.is_empty() { 1 } else { 0 })
1083+
.sum();
1084+
let can_run = if runnable_variants == 0 {
1085+
"No".cell().foreground_color(Some(Color::Red))
1086+
} else if all_varints == 1 {
1087+
"Yes".cell().foreground_color(Some(Color::Green))
1088+
} else {
1089+
format!(
1090+
"{} ({}/{})",
1091+
"Yes".color(colored::Color::Green),
1092+
runnable_variants.to_string().color(colored::Color::Green),
1093+
all_varints
1094+
)
1095+
.cell()
1096+
};
1097+
let mut header = vec![w.worker_id.cell(), can_run];
1098+
for (i, variant) in w.variants.iter().enumerate() {
1099+
if !variant.is_empty() {
1100+
let (mut rtype, mut provs, mut rqs) = (Vec::new(), Vec::new(), Vec::new());
1101+
variant.iter().for_each(|v| {
1102+
let (rt, rq, pr) = explanation_item_to_strings(v);
1103+
rtype.push(rt.to_string());
1104+
provs.push(rq.to_string());
1105+
rqs.push(pr.to_string());
1106+
});
1107+
if header.is_empty() {
1108+
header.push("".cell());
1109+
header.push("".cell());
11361110
}
1111+
header.push(i.cell());
1112+
header.push(rtype.join("\n").cell());
1113+
header.push(provs.join("\n").cell());
1114+
header.push(rqs.join("\n").cell());
1115+
rows.push(std::mem::take(&mut header));
1116+
}
1117+
}
1118+
if !header.is_empty() {
1119+
for _ in 0..5 {
1120+
header.push("".cell());
11371121
}
1122+
rows.push(header);
11381123
}
11391124
}
1125+
let header = vec![
1126+
"Worker Id".cell(),
1127+
"Runnable".cell(),
1128+
"Variant".cell(),
1129+
"Type".cell(),
1130+
"Provides".cell(),
1131+
"Request".cell(),
1132+
];
1133+
self.print_horizontal_table(rows, header);
1134+
// let all = explanation.variants.len();
1135+
// let count: usize = explanation
1136+
// .variants
1137+
// .iter()
1138+
// .map(|e| if e.is_empty() { 1 } else { 0 })
1139+
// .sum();
1140+
// if count > 0 {
1141+
// if all == 1 {
1142+
// println!(
1143+
// "Task {task_id} {} on worker {worker_id}.",
1144+
// "can run".color(colored::Color::Green)
1145+
// );
1146+
// } else {
1147+
// println!(
1148+
// "Task {task_id} {} on worker {worker_id}, ({count}/{all} variants)",
1149+
// "can run".color(colored::Color::Green)
1150+
// );
1151+
// }
1152+
// if explanation.n_task_deps == 0 {
1153+
// println!("Task is directly executable because it does not have any dependencies.",);
1154+
// } else if explanation.n_waiting_deps == explanation.n_task_deps {
1155+
// println!(
1156+
// "Task is directly executable because all dependencies ({}) are already finished.",
1157+
// explanation.n_task_deps
1158+
// );
1159+
// } else {
1160+
// println!(
1161+
// "Task is not directly executable because {} dependencies are not yet finished.",
1162+
// format!("{}/{}", explanation.n_waiting_deps, explanation.n_task_deps)
1163+
// .color(colored::Color::Red)
1164+
// );
1165+
// }
1166+
// } else if all == 1 {
1167+
// println!(
1168+
// "Task {task_id} {} on worker {worker_id}.",
1169+
// "cannot run".color(colored::Color::Red)
1170+
// );
1171+
// } else {
1172+
// println!(
1173+
// "Task {task_id} {} on worker {worker_id}, none of {all} variants.",
1174+
// "cannot run".color(colored::Color::Red)
1175+
// );
1176+
// }
1177+
// for (i, explanations) in explanation.variants.iter().enumerate() {
1178+
// if all > 1 && !explanations.is_empty() {
1179+
// println!("Resource variant {i}:")
1180+
// }
1181+
// for expl in explanations {
1182+
// match expl {
1183+
// TaskExplainItem::Time {
1184+
// min_time,
1185+
// remaining_time,
1186+
// } => {
1187+
// println!(
1188+
// "* Task requests at least {} of running time, but worker remaining time is: {}.",
1189+
// human_duration(chrono::Duration::from_std(*min_time).unwrap())
1190+
// .color(colored::Color::Cyan),
1191+
// human_duration(chrono::Duration::from_std(*remaining_time).unwrap())
1192+
// .color(colored::Color::Red),
1193+
// )
1194+
// }
1195+
// TaskExplainItem::Resources {
1196+
// resource,
1197+
// request_amount,
1198+
// worker_amount,
1199+
// } => {
1200+
// println!(
1201+
// "* Task requests at least {}, but worker provides {}.",
1202+
// format!("{} {}", request_amount, resource).color(colored::Color::Cyan),
1203+
// format!("{} {}", worker_amount, resource).color(colored::Color::Red),
1204+
// )
1205+
// }
1206+
// TaskExplainItem::WorkerGroup {
1207+
// n_nodes,
1208+
// group_size,
1209+
// } => {
1210+
// println!(
1211+
// "* Task requests at least {} nodes, but worker is in group of size {}.",
1212+
// format!("{}", n_nodes).color(colored::Color::Cyan),
1213+
// format!("{}", group_size).color(colored::Color::Red),
1214+
// )
1215+
// }
1216+
// }
1217+
// }
1218+
// }
11401219
}
11411220
}
11421221

@@ -1651,6 +1730,42 @@ fn resources_summary(resources: &ResourceDescriptor, multiline: bool) -> String
16511730
result
16521731
}
16531732

1733+
fn explanation_item_to_strings(
1734+
item: &TaskExplainItem,
1735+
) -> (ColoredString, ColoredString, ColoredString) {
1736+
match item {
1737+
TaskExplainItem::Time {
1738+
min_time,
1739+
remaining_time,
1740+
} => (
1741+
"time".color(colored::Color::Magenta),
1742+
human_duration(chrono::Duration::from_std(*remaining_time).unwrap())
1743+
.to_string()
1744+
.color(colored::Color::Yellow),
1745+
human_duration(chrono::Duration::from_std(*min_time).unwrap())
1746+
.to_string()
1747+
.color(colored::Color::Red),
1748+
),
1749+
TaskExplainItem::Resources {
1750+
resource,
1751+
request_amount,
1752+
worker_amount,
1753+
} => (
1754+
resource.color(colored::Color::Cyan),
1755+
format!("{}", worker_amount).color(colored::Color::Yellow),
1756+
format!("{}", request_amount).color(colored::Color::Red),
1757+
),
1758+
TaskExplainItem::WorkerGroup {
1759+
n_nodes,
1760+
group_size,
1761+
} => (
1762+
"nodes".color(colored::Color::Magenta),
1763+
format!("group size {}", group_size).color(colored::Color::Yellow),
1764+
format!("{}", n_nodes).color(colored::Color::Red),
1765+
),
1766+
}
1767+
}
1768+
16541769
#[cfg(test)]
16551770
mod tests {
16561771
use crate::client::output::cli::{resources_full_describe, resources_summary};

crates/hyperqueue/src/client/output/json.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use tako::gateway::{CrashLimit, ResourceRequest};
1212
use tako::program::{ProgramDefinition, StdioDef};
1313
use tako::resources::{ResourceDescriptor, ResourceDescriptorItem, ResourceDescriptorKind};
1414
use tako::worker::WorkerConfiguration;
15-
use tako::{Map, TaskId, WorkerId};
15+
use tako::{Map, TaskId};
1616

1717
use crate::client::job::WorkerMap;
1818
use crate::client::output::Verbosity;
@@ -253,13 +253,8 @@ impl Output for JsonOutput {
253253
self.print(json!({ "error": format!("{error:?}") }))
254254
}
255255

256-
fn print_explanation(
257-
&self,
258-
task_id: TaskId,
259-
worker_id: WorkerId,
260-
explanation: &TaskExplanation,
261-
) {
262-
self.print(json!({ "task_id": task_id, "task_id": worker_id, "explanation": explanation }));
256+
fn print_explanation(&self, task_id: TaskId, explanation: &TaskExplanation) {
257+
self.print(json!({ "task_id": task_id, "explanation": explanation }));
263258
}
264259
}
265260

crates/hyperqueue/src/client/output/outputs.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::server::job::JobTaskInfo;
1414
use core::time::Duration;
1515
use tako::resources::ResourceDescriptor;
1616
use tako::server::TaskExplanation;
17-
use tako::{JobId, JobTaskId, TaskId, WorkerId};
17+
use tako::{JobId, JobTaskId, TaskId};
1818

1919
pub const MAX_DISPLAYED_WORKERS: usize = 2;
2020

@@ -93,10 +93,5 @@ pub trait Output {
9393

9494
fn print_error(&self, error: anyhow::Error);
9595

96-
fn print_explanation(
97-
&self,
98-
task_id: TaskId,
99-
worker_id: WorkerId,
100-
explanation: &TaskExplanation,
101-
);
96+
fn print_explanation(&self, task_id: TaskId, explanation: &TaskExplanation);
10297
}

crates/hyperqueue/src/client/output/quiet.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::transfer::messages::{
2222
WorkerInfo,
2323
};
2424
use tako::server::TaskExplanation;
25-
use tako::{JobId, JobTaskId, TaskId, WorkerId};
25+
use tako::{JobId, JobTaskId, TaskId};
2626

2727
#[derive(Default)]
2828
pub struct Quiet;
@@ -153,13 +153,7 @@ impl Output for Quiet {
153153
eprintln!("{error:?}");
154154
}
155155

156-
fn print_explanation(
157-
&self,
158-
_task_id: TaskId,
159-
_worker_id: WorkerId,
160-
_explanation: &TaskExplanation,
161-
) {
162-
}
156+
fn print_explanation(&self, _task_id: TaskId, _explanation: &TaskExplanation) {}
163157
}
164158

165159
fn format_status(status: &Status) -> &str {

0 commit comments

Comments
 (0)