diff options
| author | bors <bors@rust-lang.org> | 2014-02-13 20:36:55 -0800 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-02-13 20:36:55 -0800 |
| commit | 22c34f3c4cddea33b916eb92f8d7286b02b865a7 (patch) | |
| tree | dd36da3994499e5bac9aba767edc126f36d54f67 /src/libstd/rt | |
| parent | 68129d299b54806b6aa4ec9f3a0755854db7b491 (diff) | |
| parent | 301ff0c2df3d26a5b287ab61d80f5ca7845e827b (diff) | |
| download | rust-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.rs | 15 | ||||
| -rw-r--r-- | src/libstd/rt/task.rs | 16 |
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 => {} } } |
