simplified threshold and configurable synchronizers

This commit is contained in:
debris 2016-11-09 21:42:17 +01:00
parent cca36dee30
commit 078a71ba15
1 changed files with 29 additions and 49 deletions

View File

@ -66,23 +66,19 @@ impl Synchronizer for NoopSynchronizer {
#[derive(Debug)] #[derive(Debug)]
struct ThresholdSynchronizer { struct ThresholdSynchronizer {
inner: FifoSynchronizer, inner: FifoSynchronizer,
start_id: u32, to_grant_min: u32,
threshold: u32, to_grant_max: u32,
} }
impl ThresholdSynchronizer { impl ThresholdSynchronizer {
fn new(next_to_grant: u32, threshold: u32) -> Self { fn new(declared: u32, threshold: u32) -> Self {
// let's mark all ids in threshold as declared
// this may cause some ids, to be skipped, but we don't care
// it won't affect correct execution of the program
let declared = next_to_grant + threshold;
ThresholdSynchronizer { ThresholdSynchronizer {
inner: FifoSynchronizer { inner: FifoSynchronizer {
declared_responses: declared, declared_responses: declared,
next_to_grant: declared, next_to_grant: declared,
}, },
start_id: next_to_grant, to_grant_min: declared.overflowing_sub(threshold).0,
threshold: threshold, to_grant_max: declared,
} }
} }
} }
@ -97,14 +93,19 @@ impl Synchronizer for ThresholdSynchronizer {
return true; return true;
} }
id.overflowing_sub(self.start_id).0 < self.threshold || if self.to_grant_min <= self.to_grant_max {
self.start_id.overflowing_sub(id).0 < self.threshold // if max is bigger then min, id must be in range [min, max)
self.to_grant_min <= id && id < self.to_grant_max
} else {
// otherwise if is in range [min, u32::max_value()] || [0, max)
(self.to_grant_min <= id && id <= u32::max_value()) ||
id < self.to_grant_max
}
} }
} }
#[derive(Debug)] #[derive(Debug)]
enum InnerSynchronizer { enum InnerSynchronizer {
Fifo(FifoSynchronizer),
Noop(NoopSynchronizer), Noop(NoopSynchronizer),
Threshold(ThresholdSynchronizer), Threshold(ThresholdSynchronizer),
} }
@ -112,7 +113,7 @@ enum InnerSynchronizer {
impl InnerSynchronizer { impl InnerSynchronizer {
pub fn new(sync: bool) -> Self { pub fn new(sync: bool) -> Self {
if sync { if sync {
InnerSynchronizer::Fifo(FifoSynchronizer::default()) InnerSynchronizer::Threshold(ThresholdSynchronizer::new(0, 0))
} else { } else {
InnerSynchronizer::Noop(NoopSynchronizer::default()) InnerSynchronizer::Noop(NoopSynchronizer::default())
} }
@ -123,8 +124,6 @@ impl InnerSynchronizer {
pub struct ConfigurableSynchronizer { pub struct ConfigurableSynchronizer {
/// Inner synchronizer which is currently used /// Inner synchronizer which is currently used
inner: InnerSynchronizer, inner: InnerSynchronizer,
/// Id of next response which is likely to be granted permission.
probably_next_to_grant: u32,
} }
impl Default for ConfigurableSynchronizer { impl Default for ConfigurableSynchronizer {
@ -137,7 +136,6 @@ impl ConfigurableSynchronizer {
pub fn new(sync: bool) -> Self { pub fn new(sync: bool) -> Self {
ConfigurableSynchronizer { ConfigurableSynchronizer {
inner: InnerSynchronizer::new(sync), inner: InnerSynchronizer::new(sync),
probably_next_to_grant: 0,
} }
} }
@ -145,22 +143,15 @@ impl ConfigurableSynchronizer {
/// from last_processed response will still be granted permissions. /// from last_processed response will still be granted permissions.
pub fn change_sync_policy(&mut self, sync: bool) { pub fn change_sync_policy(&mut self, sync: bool) {
let new_inner = match self.inner { let new_inner = match self.inner {
InnerSynchronizer::Fifo(ref s) if sync == false => {
self.probably_next_to_grant = s.next_to_grant;
InnerSynchronizer::Noop(NoopSynchronizer {
declared_responses: s.declared_responses,
})
},
InnerSynchronizer::Threshold(ref s) if sync == false => { InnerSynchronizer::Threshold(ref s) if sync == false => {
self.probably_next_to_grant = s.inner.next_to_grant;
InnerSynchronizer::Noop(NoopSynchronizer { InnerSynchronizer::Noop(NoopSynchronizer {
declared_responses: s.inner.declared_responses, declared_responses: s.inner.declared_responses,
}) })
}, },
InnerSynchronizer::Noop(_) if sync == true => { InnerSynchronizer::Noop(ref s) if sync == true => {
let threshold = ThresholdSynchronizer::new( let threshold = ThresholdSynchronizer::new(
self.probably_next_to_grant, s.declared_responses,
CONFIGURABLE_SYNCHRONIZER_THRESHOLD CONFIGURABLE_SYNCHRONIZER_THRESHOLD,
); );
InnerSynchronizer::Threshold(threshold) InnerSynchronizer::Threshold(threshold)
}, },
@ -174,7 +165,6 @@ impl ConfigurableSynchronizer {
impl Synchronizer for ConfigurableSynchronizer { impl Synchronizer for ConfigurableSynchronizer {
fn declare_response(&mut self) -> u32 { fn declare_response(&mut self) -> u32 {
match self.inner { match self.inner {
InnerSynchronizer::Fifo(ref mut s) => s.declare_response(),
InnerSynchronizer::Noop(ref mut s) => s.declare_response(), InnerSynchronizer::Noop(ref mut s) => s.declare_response(),
InnerSynchronizer::Threshold(ref mut s) => s.declare_response(), InnerSynchronizer::Threshold(ref mut s) => s.declare_response(),
} }
@ -182,12 +172,8 @@ impl Synchronizer for ConfigurableSynchronizer {
fn permission_for_response(&mut self, id: u32) -> bool { fn permission_for_response(&mut self, id: u32) -> bool {
match self.inner { match self.inner {
InnerSynchronizer::Fifo(ref mut s) => s.permission_for_response(id),
InnerSynchronizer::Threshold(ref mut s) => s.permission_for_response(id), InnerSynchronizer::Threshold(ref mut s) => s.permission_for_response(id),
InnerSynchronizer::Noop(ref mut s) => { InnerSynchronizer::Noop(ref mut s) => s.permission_for_response(id),
self.probably_next_to_grant = id.overflowing_add(1).0;
s.permission_for_response(id)
},
} }
} }
} }
@ -195,7 +181,7 @@ impl Synchronizer for ConfigurableSynchronizer {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{ use super::{
Synchronizer, FifoSynchronizer, NoopSynchronizer, ConfigurableSynchronizer, ThresholdSynchronizer, CONFIGURABLE_SYNCHRONIZER_THRESHOLD Synchronizer, FifoSynchronizer, NoopSynchronizer, ConfigurableSynchronizer, ThresholdSynchronizer
}; };
#[test] #[test]
@ -235,12 +221,10 @@ mod tests {
assert!(!s.permission_for_response(id2)); assert!(!s.permission_for_response(id2));
assert!(s.permission_for_response(id1)); assert!(s.permission_for_response(id1));
assert!(s.permission_for_response(id2)); assert!(s.permission_for_response(id2));
// historic permissions // historic permissions, order does not matter
assert!(!s.permission_for_response(0));
assert!(s.permission_for_response(1)); assert!(s.permission_for_response(1));
assert!(s.permission_for_response(2)); assert!(s.permission_for_response(0));
assert!(s.permission_for_response(3)); assert!(!s.permission_for_response(2));
assert!(!s.permission_for_response(4));
} }
#[test] #[test]
@ -268,11 +252,13 @@ mod tests {
assert!(s.permission_for_response(id2)); assert!(s.permission_for_response(id2));
assert!(s.permission_for_response(id0)); assert!(s.permission_for_response(id0));
let d0 = s.declare_response();
let d1 = s.declare_response();
// process messages synchronously again // process messages synchronously again
s.change_sync_policy(true); s.change_sync_policy(true);
let last_async = id2;
// let's check again if we can process them only synchronously // let's check again if we can process them only synchronously
let id0 = s.declare_response(); let id0 = s.declare_response();
let id1 = s.declare_response(); let id1 = s.declare_response();
@ -284,14 +270,8 @@ mod tests {
assert!(s.permission_for_response(id1)); assert!(s.permission_for_response(id1));
assert!(s.permission_for_response(id2)); assert!(s.permission_for_response(id2));
// order of requests before changing to policy to sync should not matter
// there might be ~10 unhandled messages, assert!(s.permission_for_response(d1));
// let's check if we can process them out of order (eg. in reverse) assert!(s.permission_for_response(d0));
for i in (0..CONFIGURABLE_SYNCHRONIZER_THRESHOLD - 1).into_iter().rev() {
assert!(s.permission_for_response(last_async + i));
}
// the next one should fail
assert!(!s.permission_for_response(last_async + CONFIGURABLE_SYNCHRONIZER_THRESHOLD));
} }
} }