From f57760c609d636d2e4698a26848f5c990d417265 Mon Sep 17 00:00:00 2001 From: Ben Blum Date: Fri, 3 Aug 2012 19:26:25 -0400 Subject: [PATCH] Add task-perf-linked-failure.rs --- .../bench/task-perf-jargon-metal-smoke.rs | 4 +- src/test/bench/task-perf-linked-failure.rs | 67 +++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 src/test/bench/task-perf-linked-failure.rs diff --git a/src/test/bench/task-perf-jargon-metal-smoke.rs b/src/test/bench/task-perf-jargon-metal-smoke.rs index c2e25c5e5e33a..0542204bf99c5 100644 --- a/src/test/bench/task-perf-jargon-metal-smoke.rs +++ b/src/test/bench/task-perf-jargon-metal-smoke.rs @@ -3,12 +3,12 @@ // Each child task has to enlist as a descendant in each of its ancestor // groups, but that shouldn't have to happen for already-dead groups. // -// The filename is a reference; google it in quotes. +// The filename is a song reference; google it in quotes. fn child_generation(gens_left: uint) { // This used to be O(n^2) in the number of generations that ever existed. // With this code, only as many generations are alive at a time as tasks - // alive at a time, + // alive at a time, do task::spawn_supervised { if gens_left & 1 == 1 { task::yield(); // shake things up a bit diff --git a/src/test/bench/task-perf-linked-failure.rs b/src/test/bench/task-perf-linked-failure.rs new file mode 100644 index 0000000000000..a806950d0f758 --- /dev/null +++ b/src/test/bench/task-perf-linked-failure.rs @@ -0,0 +1,67 @@ +/** + * Test performance of killing many tasks in a taskgroup. + * Along the way, tests various edge cases of ancestor group management. + * In particular, this tries to get each grandchild task to hit the + * "nobe_is_dead" case in each_ancestor only during task exit, but not during + * task spawn. This makes sure that defunct ancestor groups are handled correctly + * w.r.t. possibly leaving stale *rust_tasks lying around. + */ + +// Creates in the background 'num_tasks' tasks, all blocked forever. +// Doesn't return until all such tasks are ready, but doesn't block forever itself. +fn grandchild_group(num_tasks: uint) { + let po = comm::port(); + let ch = comm::chan(po); + + for num_tasks.times { + do task::spawn { // linked + comm::send(ch, ()); + comm::recv(comm::port::<()>()); // block forever + } + } + #error["Grandchild group getting started"]; + for num_tasks.times { + // Make sure all above children are fully spawned; i.e., enlisted in + // their ancestor groups. + comm::recv(po); + } + #error["Grandchild group ready to go."]; + // Master grandchild task exits early. +} + +fn spawn_supervised_blocking(myname: &str, +f: fn~()) { + let mut res = none; + task::task().future_result(|-r| res = some(r)).supervised().spawn(f); + #error["%s group waiting", myname]; + let x = future::get(option::unwrap(res)); + assert x == task::success; +} + +fn main(args: ~[~str]) { + let args = if os::getenv(~"RUST_BENCH").is_some() { + ~[~"", ~"100000"] + } else if args.len() <= 1u { + ~[~"", ~"100"] + } else { + copy args + }; + + let num_tasks = uint::from_str(args[1]).get(); + + // Main group #0 waits for unsupervised group #1. + // Grandparent group #1 waits for middle group #2, then fails, killing #3. + // Middle group #2 creates grandchild_group #3, waits for it to be ready, exits. + let x: result::result<(),()> = do task::try { // unlinked + do spawn_supervised_blocking("grandparent") { + do spawn_supervised_blocking("middle") { + grandchild_group(num_tasks); + } + // When grandchild group is ready to go, make the middle group exit. + #error["Middle group wakes up and exits"]; + } + // Grandparent group waits for middle group to be gone, then fails + #error["Grandparent group wakes up and fails"]; + fail; + }; + assert x.is_err(); +}