mod collect;
mod dcbo;
mod dra;
mod random;
mod round_robin;
use core::ops::{Deref, DerefMut};
pub use collect::{DoubleCollect, NoCollect};
use crossbeam_utils::CachePadded;
pub use dcbo::DCBO;
pub use dra::DRA;
pub use random::RandomAccess;
pub use round_robin::RoundRobin;
use crate::{
Collection,
Signature,
storage::StorageBackend,
sync::atomic::{AtomicUsize, Ordering},
};
pub trait Strategy<Q: Collection> {
type Gambler: Hooked;
#[must_use = "a pulled arm should be used and the result communicated back to the gambler via the `Hooked` trait"]
fn choose_offer_arm(
&self,
state: &impl StorageBackend<<Self::Gambler as Hooked>::Stake>,
gambler: &mut Self::Gambler,
) -> usize;
#[must_use = "a pulled arm should be used and the result communicated back to the gambler via the `Hooked` trait"]
fn choose_poll_arm(
&self,
state: &impl StorageBackend<<Self::Gambler as Hooked>::Stake>,
gambler: &mut Self::Gambler,
) -> usize;
#[must_use]
fn fork_gambler(&self, parent: &mut Self::Gambler) -> Self::Gambler;
#[must_use]
fn create_gambler(&self) -> Self::Gambler;
#[inline]
fn collect<'b, 'c>(
&self,
_state: &impl StorageBackend<<Self::Gambler as Hooked>::Stake>,
bandit_arms: &'c impl StorageBackend<Q>,
input: <Q::PollSignature as Signature>::Input<'b>,
) -> Option<(<Q::PollSignature as Signature>::Output<'b, 'c>, usize)>
where
Q: 'c,
{
for (i, q) in bandit_arms.iter().enumerate() {
if let Ok(item) = q.poll(input) {
return Some((item, i));
}
}
None
}
}
pub trait Hook {
#[inline]
fn on_offer_succ(&self) {}
#[inline]
fn on_offer_fail(&self) {}
#[inline]
fn on_poll_succ(&self) {}
#[inline]
fn on_poll_fail(&self) {}
}
pub trait Hooked {
type Stake: Default + Hook;
#[inline]
fn on_offer_succ(&mut self, sub_state: &Self::Stake) {
sub_state.on_offer_succ();
}
#[inline]
fn on_offer_fail(&mut self, sub_state: &Self::Stake) {
sub_state.on_offer_fail();
}
#[inline]
fn on_poll_succ(&mut self, sub_state: &Self::Stake) {
sub_state.on_poll_succ();
}
#[inline]
fn on_poll_fail(&mut self, sub_state: &Self::Stake) {
sub_state.on_poll_fail();
}
}
#[derive(Debug, Default)]
pub struct InstrumentedState<T> {
#[cfg(feature = "instrumented")]
offer_count: AtomicUsize,
#[cfg(feature = "instrumented")]
poll_count: AtomicUsize,
sched_state: T,
}
#[cfg(feature = "instrumented")]
impl<T> InstrumentedState<T> {
#[inline]
pub fn offer_count(&self) -> usize {
self.offer_count.load(Ordering::Relaxed)
}
#[inline]
pub fn poll_count(&self) -> usize {
self.poll_count.load(Ordering::Relaxed)
}
}
impl<T> Deref for InstrumentedState<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.sched_state
}
}
impl<T> DerefMut for InstrumentedState<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.sched_state
}
}
impl<T> Clone for InstrumentedState<T>
where
T: Clone,
{
#[inline]
fn clone(&self) -> Self {
Self {
#[cfg(feature = "instrumented")]
offer_count: self.offer_count.load(Ordering::Relaxed).into(),
#[cfg(feature = "instrumented")]
poll_count: self.poll_count.load(Ordering::Relaxed).into(),
sched_state: self.sched_state.clone(),
}
}
}
impl<T> Hook for InstrumentedState<T>
where
T: Hook,
{
#[inline]
fn on_offer_succ(&self) {
#[cfg(feature = "instrumented")]
self.offer_count.fetch_add(1, Ordering::Relaxed);
self.sched_state.on_offer_succ();
}
#[inline]
fn on_offer_fail(&self) {
self.sched_state.on_offer_fail();
}
#[inline]
fn on_poll_succ(&self) {
#[cfg(feature = "instrumented")]
self.poll_count.fetch_add(1, Ordering::Relaxed);
self.sched_state.on_poll_succ();
}
#[inline]
fn on_poll_fail(&self) {
self.sched_state.on_poll_fail();
}
}
#[derive(Default, Debug)]
pub struct EDCount {
offer_count: AtomicUsize,
poll_count: AtomicUsize,
}
impl Clone for EDCount {
#[inline]
fn clone(&self) -> Self {
Self {
offer_count: self.offer_count.load(Ordering::Relaxed).into(),
poll_count: self.poll_count.load(Ordering::Relaxed).into(),
}
}
}
impl EDCount {
#[inline]
pub fn offer_count(&self) -> usize {
self.offer_count.load(Ordering::Relaxed)
}
#[inline]
pub fn poll_count(&self) -> usize {
self.poll_count.load(Ordering::Relaxed)
}
}
impl Hook for EDCount {
#[inline]
fn on_offer_succ(&self) {
self.offer_count.fetch_add(1, Ordering::Relaxed);
}
#[inline]
fn on_poll_succ(&self) {
self.poll_count.fetch_add(1, Ordering::Relaxed);
}
}
impl Hook for () {}
impl<T> Hook for CachePadded<T>
where
T: Hook,
{
#[inline]
fn on_offer_succ(&self) {
T::on_offer_succ(self);
}
#[inline]
fn on_offer_fail(&self) {
T::on_offer_fail(self);
}
#[inline]
fn on_poll_succ(&self) {
T::on_poll_succ(self);
}
#[inline]
fn on_poll_fail(&self) {
T::on_poll_fail(self);
}
}
#[repr(transparent)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NoPad<T>(T);
impl<T> Deref for NoPad<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for NoPad<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> Hook for NoPad<T>
where
T: Hook,
{
#[inline]
fn on_offer_succ(&self) {
T::on_offer_succ(self);
}
#[inline]
fn on_offer_fail(&self) {
T::on_offer_fail(self);
}
#[inline]
fn on_poll_succ(&self) {
T::on_poll_succ(self);
}
#[inline]
fn on_poll_fail(&self) {
T::on_poll_fail(self);
}
}