//! Generic traits for queue benchmarking. use crate::tokio_queue; use st3; /// Error returned on stealing failure. pub enum GenericStealError { Empty, Busy, } /// Generic interface for a queue worker. pub trait GenericWorker: Send { type S: GenericStealer; fn new() -> Self; fn push(&self, item: T) -> Result<(), T>; fn pop(&self) -> Option; fn stealer(&self) -> Self::S; } /// Generic interface for a queue stealer. pub trait GenericStealer: Clone + Send + Sync { type W: GenericWorker; fn steal_batch_and_pop(&self, worker: &Self::W) -> Result; } /// Generic work-stealing queue traits implementation for St3 (LIFO). impl GenericWorker for st3::lifo::Worker { type S = st3::lifo::Stealer; fn new() -> Self { Self::new(256) } fn push(&self, item: T) -> Result<(), T> { self.push(item) } fn pop(&self) -> Option { self.pop() } fn stealer(&self) -> Self::S { self.stealer() } } impl GenericStealer for st3::lifo::Stealer { type W = st3::lifo::Worker; fn steal_batch_and_pop(&self, worker: &Self::W) -> Result { // The maximum number of tasks to be stolen is limited in order to match // the behavior of `crossbeam-dequeue`. const MAX_BATCH_SIZE: usize = 32; self.steal_and_pop(worker, |n| (n - n / 2).min(MAX_BATCH_SIZE)) .map(|out| out.0) .map_err(|e| match e { st3::StealError::Empty => GenericStealError::Empty, st3::StealError::Busy => GenericStealError::Busy, }) } } /// Generic work-stealing queue traits implementation for St3 (FIFO). impl GenericWorker for st3::fifo::Worker { type S = st3::fifo::Stealer; fn new() -> Self { Self::new(256) } fn push(&self, item: T) -> Result<(), T> { self.push(item) } fn pop(&self) -> Option { self.pop() } fn stealer(&self) -> Self::S { self.stealer() } } impl GenericStealer for st3::fifo::Stealer { type W = st3::fifo::Worker; fn steal_batch_and_pop(&self, worker: &Self::W) -> Result { // The maximum number of tasks to be stolen is limited in order to match // the behavior of `crossbeam-dequeue`. const MAX_BATCH_SIZE: usize = 32; self.steal_and_pop(worker, |n| (n - n / 2).min(MAX_BATCH_SIZE)) .map(|out| out.0) .map_err(|e| match e { st3::StealError::Empty => GenericStealError::Empty, st3::StealError::Busy => GenericStealError::Busy, }) } } /// Generic work-stealing queue traits implementation for tokio. impl GenericWorker for tokio_queue::Local { type S = tokio_queue::Steal; fn new() -> Self { Self::new() } fn push(&self, item: T) -> Result<(), T> { self.push_back(item) } fn pop(&self) -> Option { self.pop() } fn stealer(&self) -> Self::S { self.stealer() } } impl GenericStealer for tokio_queue::Steal { type W = tokio_queue::Local; fn steal_batch_and_pop(&self, worker: &Self::W) -> Result { // Note that `steal_into` was slightly altered compared to the original // tokio implementation in order to match the behavior of // `crossbeam-dequeue`. self.steal_into(worker).map_err(|e| match e { tokio_queue::StealError::Empty => GenericStealError::Empty, tokio_queue::StealError::Busy => GenericStealError::Busy, }) } } /// Newtypes distinguishing between FIFO and LIFO crossbeam queues. pub struct CrossbeamFifoWorker(crossbeam_deque::Worker); pub struct CrossbeamFifoStealer(crossbeam_deque::Stealer); pub struct CrossbeamLifoWorker(crossbeam_deque::Worker); pub struct CrossbeamLifoStealer(crossbeam_deque::Stealer); /// Generic work-stealing queue traits implementation for crossbeam-deque (FIFO). impl GenericWorker for CrossbeamFifoWorker { type S = CrossbeamFifoStealer; fn new() -> Self { Self(crossbeam_deque::Worker::new_fifo()) } fn push(&self, item: T) -> Result<(), T> { self.0.push(item); Ok(()) } fn pop(&self) -> Option { self.0.pop() } fn stealer(&self) -> Self::S { CrossbeamFifoStealer(self.0.stealer()) } } impl Clone for CrossbeamFifoStealer { fn clone(&self) -> Self { Self(self.0.clone()) } } impl GenericStealer for CrossbeamFifoStealer { type W = CrossbeamFifoWorker; fn steal_batch_and_pop(&self, worker: &Self::W) -> Result { match self.0.steal_batch_and_pop(&worker.0) { crossbeam_deque::Steal::Empty => Err(GenericStealError::Empty), crossbeam_deque::Steal::Retry => Err(GenericStealError::Busy), crossbeam_deque::Steal::Success(item) => Ok(item), } } } /// Generic work-stealing queue traits implementation for crossbeam-deque (LIFO). impl GenericWorker for CrossbeamLifoWorker { type S = CrossbeamLifoStealer; fn new() -> Self { Self(crossbeam_deque::Worker::new_lifo()) } fn push(&self, item: T) -> Result<(), T> { self.0.push(item); Ok(()) } fn pop(&self) -> Option { self.0.pop() } fn stealer(&self) -> Self::S { CrossbeamLifoStealer(self.0.stealer()) } } impl Clone for CrossbeamLifoStealer { fn clone(&self) -> Self { Self(self.0.clone()) } } impl GenericStealer for CrossbeamLifoStealer { type W = CrossbeamLifoWorker; fn steal_batch_and_pop(&self, worker: &Self::W) -> Result { match self.0.steal_batch_and_pop(&worker.0) { crossbeam_deque::Steal::Empty => Err(GenericStealError::Empty), crossbeam_deque::Steal::Retry => Err(GenericStealError::Busy), crossbeam_deque::Steal::Success(item) => Ok(item), } } }