about summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-02-13 20:36:55 -0800
committerbors <bors@rust-lang.org>2014-02-13 20:36:55 -0800
commit22c34f3c4cddea33b916eb92f8d7286b02b865a7 (patch)
treedd36da3994499e5bac9aba767edc126f36d54f67 /src/libstd/rt
parent68129d299b54806b6aa4ec9f3a0755854db7b491 (diff)
parent301ff0c2df3d26a5b287ab61d80f5ca7845e827b (diff)
downloadrust-22c34f3c4cddea33b916eb92f8d7286b02b865a7.tar.gz
rust-22c34f3c4cddea33b916eb92f8d7286b02b865a7.zip
auto merge of #12172 : alexcrichton/rust/green-improvements, r=brson
These commits pick off some low-hanging fruit which were slowing down spawning green threads. The major speedup comes from fixing a bug in stack caching where we never used any cached stacks!

The program I used to benchmark is at the end. It was compiled with `rustc --opt-level=3 bench.rs --test` and run as `RUST_THREADS=1 ./bench --bench`. I chose to use `RUST_THREADS=1` due to #11730 as the profiles I was getting interfered too much when all the schedulers were in play (and shouldn't be after #11730 is fixed). All of the units below are in ns/iter as reported by `--bench` (lower is better).

|               | green | native | raw    |
| ------------- | ----- | ------ | ------ |
| osx before    | 12699 | 24030  | 19734  |
| linux before  | 10223 | 125983 | 122647 |
| osx after     |  3847 | 25771  | 20835  |
| linux after   |  2631 | 135398 | 122765 |

Note that this is *not* a benchmark of spawning green tasks vs native tasks. I put in the native numbers just to get a ballpark of where green tasks are. This is benchmark is *clearly* benefiting from stack caching. Also, OSX is clearly not 5x faster than linux, I think my VM is just much slower.

All in all, this ended up being a nice 4x speedup for spawning a green task when you're using a cached stack.

```rust
extern mod extra;
extern mod native;
use std::rt::thread::Thread;

#[bench]
fn green(bh: &mut extra::test::BenchHarness) {
    let (p, c) = SharedChan::new();
    bh.iter(|| {
        let c = c.clone();
        spawn(proc() {
            c.send(());
        });
        p.recv();
    });
}

#[bench]
fn native(bh: &mut extra::test::BenchHarness) {
    let (p, c) = SharedChan::new();
    bh.iter(|| {
        let c = c.clone();
        native::task::spawn(proc() {
            c.send(());
        });
        p.recv();
    });
}

#[bench]
fn raw(bh: &mut extra::test::BenchHarness) {
    bh.iter(|| {
        Thread::start(proc() {}).join()
    });
}
```
Diffstat (limited to 'src/libstd/rt')
-rw-r--r--src/libstd/rt/local_heap.rs15
-rw-r--r--src/libstd/rt/task.rs16
2 files changed, 20 insertions, 11 deletions
diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs
index 023f712d3a0..7acce2ecb5b 100644
--- a/src/libstd/rt/local_heap.rs
+++ b/src/libstd/rt/local_heap.rs
@@ -23,6 +23,7 @@ use rt::local::Local;
 use rt::task::Task;
 use unstable::raw;
 use vec::ImmutableVector;
+use vec_ng::Vec;
 
 // This has no meaning with out rtdebug also turned on.
 #[cfg(rtdebug)]
@@ -33,7 +34,7 @@ static MAGIC: u32 = 0xbadc0ffe;
 pub type Box = raw::Box<()>;
 
 pub struct MemoryRegion {
-    priv allocations: ~[*AllocHeader],
+    priv allocations: Vec<*AllocHeader>,
     priv live_allocations: uint,
 }
 
@@ -48,7 +49,7 @@ impl LocalHeap {
     #[inline]
     pub fn new() -> LocalHeap {
         let region = MemoryRegion {
-            allocations: ~[],
+            allocations: Vec::new(),
             live_allocations: 0,
         };
         LocalHeap {
@@ -248,8 +249,8 @@ impl MemoryRegion {
     fn release(&mut self, alloc: &AllocHeader) {
         alloc.assert_sane();
         if TRACK_ALLOCATIONS > 1 {
-            rtassert!(self.allocations[alloc.index] == alloc as *AllocHeader);
-            self.allocations[alloc.index] = ptr::null();
+            rtassert!(self.allocations.as_slice()[alloc.index] == alloc as *AllocHeader);
+            self.allocations.as_mut_slice()[alloc.index] = ptr::null();
         }
     }
     #[cfg(not(rtdebug))]
@@ -260,8 +261,8 @@ impl MemoryRegion {
     fn update(&mut self, alloc: &mut AllocHeader, orig: *AllocHeader) {
         alloc.assert_sane();
         if TRACK_ALLOCATIONS > 1 {
-            rtassert!(self.allocations[alloc.index] == orig);
-            self.allocations[alloc.index] = &*alloc as *AllocHeader;
+            rtassert!(self.allocations.as_slice()[alloc.index] == orig);
+            self.allocations.as_mut_slice()[alloc.index] = &*alloc as *AllocHeader;
         }
     }
     #[cfg(not(rtdebug))]
@@ -274,7 +275,7 @@ impl Drop for MemoryRegion {
         if self.live_allocations != 0 {
             rtabort!("leaked managed memory ({} objects)", self.live_allocations);
         }
-        rtassert!(self.allocations.iter().all(|s| s.is_null()));
+        rtassert!(self.allocations.as_slice().iter().all(|s| s.is_null()));
     }
 }
 
diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs
index e2b94e655e8..0719523af77 100644
--- a/src/libstd/rt/task.rs
+++ b/src/libstd/rt/task.rs
@@ -17,6 +17,7 @@ use any::AnyOwnExt;
 use cast;
 use cleanup;
 use clone::Clone;
+use comm::Chan;
 use io::Writer;
 use iter::{Iterator, Take};
 use local_data;
@@ -67,11 +68,17 @@ pub enum BlockedTask {
     Shared(UnsafeArc<AtomicUint>),
 }
 
+pub enum DeathAction {
+    /// Action to be done with the exit code. If set, also makes the task wait
+    /// until all its watched children exit before collecting the status.
+    Execute(proc(TaskResult)),
+    /// A channel to send the result of the task on when the task exits
+    SendMessage(Chan<TaskResult>),
+}
+
 /// Per-task state related to task death, killing, failure, etc.
 pub struct Death {
-    // Action to be done with the exit code. If set, also makes the task wait
-    // until all its watched children exit before collecting the status.
-    on_exit: Option<proc(TaskResult)>,
+    on_exit: Option<DeathAction>,
 }
 
 pub struct BlockedTasks {
@@ -381,7 +388,8 @@ impl Death {
     /// Collect failure exit codes from children and propagate them to a parent.
     pub fn collect_failure(&mut self, result: TaskResult) {
         match self.on_exit.take() {
-            Some(f) => f(result),
+            Some(Execute(f)) => f(result),
+            Some(SendMessage(ch)) => { ch.try_send(result); }
             None => {}
         }
     }