Skip to content

Commit a70f9d7

Browse files
committed
Implement a lock-free work-stealing deque
This adds an implementation of the Chase-Lev work-stealing deque to libstd under std::rt::deque. I've been unable to break the implementation of the deque itself, and it's not super highly optimized just yet (everything uses a SeqCst memory ordering). The major snag in implementing the chase-lev deque is that the buffers used to store data internally cannot get deallocated back to the OS. In the meantime, a shared buffer pool (synchronized by a normal mutex) is used to deallocate/allocate buffers from. This is done in hope of not overcommitting too much memory. It is in theory possible to eventually free the buffers, but one must be very careful in doing so. I was unable to get some good numbers from src/test/bench tests (I don't think many of them are slamming the work queue that much), but I was able to get some good numbers from one of my own tests. In a recent rewrite of select::select(), I found that my implementation was incredibly slow due to contention on the shared work queue. Upon switching to the parallel deque, I saw the contention drop to 0 and the runtime go from 1.6s to 0.9s with the most amount of time spent in libuv awakening the schedulers (plus allocations). Closes #4877
1 parent 08f4d1f commit a70f9d7

File tree

7 files changed

+723
-141
lines changed

7 files changed

+723
-141
lines changed

src/librustuv/net.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -1076,21 +1076,22 @@ mod test {
10761076
use std::rt::task::Task;
10771077
use std::rt::task::UnwindResult;
10781078
use std::rt::thread::Thread;
1079-
use std::rt::work_queue::WorkQueue;
1079+
use std::rt::deque::BufferPool;
10801080
use std::unstable::run_in_bare_thread;
10811081
use uvio::UvEventLoop;
10821082
10831083
do run_in_bare_thread {
10841084
let sleepers = SleeperList::new();
1085-
let work_queue1 = WorkQueue::new();
1086-
let work_queue2 = WorkQueue::new();
1087-
let queues = ~[work_queue1.clone(), work_queue2.clone()];
1085+
let mut pool = BufferPool::init();
1086+
let (worker1, stealer1) = pool.deque();
1087+
let (worker2, stealer2) = pool.deque();
1088+
let queues = ~[stealer1, stealer2];
10881089
10891090
let loop1 = ~UvEventLoop::new() as ~EventLoop;
1090-
let mut sched1 = ~Scheduler::new(loop1, work_queue1, queues.clone(),
1091+
let mut sched1 = ~Scheduler::new(loop1, worker1, queues.clone(),
10911092
sleepers.clone());
10921093
let loop2 = ~UvEventLoop::new() as ~EventLoop;
1093-
let mut sched2 = ~Scheduler::new(loop2, work_queue2, queues.clone(),
1094+
let mut sched2 = ~Scheduler::new(loop2, worker2, queues.clone(),
10941095
sleepers.clone());
10951096
10961097
let handle1 = Cell::new(sched1.make_handle());

0 commit comments

Comments
 (0)