1 use docopt::Docopt;
2 use std::io;
3 use std::process;
4 
5 const USAGE: &str = "
6 Usage: cpu_monitor [options] <scenario>
7        cpu_monitor --help
8 
9 A test for monitoring how much CPU usage Rayon consumes under various
10 scenarios. This test is intended to be executed interactively, like so:
11 
12     cargo run --example cpu_monitor -- tasks_ended
13 
14 The list of scenarios you can try are as follows:
15 
16 - tasks_ended: after all tasks have finished, go to sleep
17 - task_stall_root: a root task stalls for a very long time
18 - task_stall_scope: a task in a scope stalls for a very long time
19 
20 Options:
21     -h, --help                   Show this message.
22     -d N, --depth N              Control how hard the dummy task works [default: 27]
23 ";
24 
25 #[derive(serde::Deserialize)]
26 pub struct Args {
27     arg_scenario: String,
28     flag_depth: usize,
29 }
30 
main()31 fn main() {
32     let args: &Args = &Docopt::new(USAGE)
33         .and_then(|d| d.deserialize())
34         .unwrap_or_else(|e| e.exit());
35 
36     match &args.arg_scenario[..] {
37         "tasks_ended" => tasks_ended(args),
38         "task_stall_root" => task_stall_root(args),
39         "task_stall_scope" => task_stall_scope(args),
40         _ => {
41             println!("unknown scenario: `{}`", args.arg_scenario);
42             println!("try --help");
43             process::exit(1);
44         }
45     }
46 }
47 
wait_for_user()48 fn wait_for_user() {
49     let mut input = String::new();
50     io::stdin().read_line(&mut input).unwrap();
51 }
52 
task(args: &Args)53 fn task(args: &Args) {
54     fn join_recursively(n: usize) {
55         if n == 0 {
56             return;
57         }
58         rayon::join(|| join_recursively(n - 1), || join_recursively(n - 1));
59     }
60 
61     println!("Starting heavy work at depth {}...wait.", args.flag_depth);
62     join_recursively(args.flag_depth);
63     println!("Heavy work done; check top. You should see CPU usage drop to zero soon.");
64     println!("Press <enter> to quit...");
65 }
66 
tasks_ended(args: &Args)67 fn tasks_ended(args: &Args) {
68     task(args);
69     wait_for_user();
70 }
71 
task_stall_root(args: &Args)72 fn task_stall_root(args: &Args) {
73     rayon::join(|| task(args), wait_for_user);
74 }
75 
task_stall_scope(args: &Args)76 fn task_stall_scope(args: &Args) {
77     rayon::scope(|scope| {
78         scope.spawn(move |_| task(args));
79         scope.spawn(move |_| wait_for_user());
80     });
81 }
82