From d5361c48f4d800b7e41f0e55dab423e4fe39dc19 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Dec 2024 14:14:52 +0100 Subject: [PATCH 1/3] Replace `AtomicCell` with `AtomicBool` --- src/cycle.rs | 3 ++- src/runtime.rs | 31 +++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/cycle.rs b/src/cycle.rs index 6071aa30..2c67e164 100644 --- a/src/cycle.rs +++ b/src/cycle.rs @@ -21,7 +21,8 @@ pub struct Cycle { participants: CycleParticipants, } -pub(crate) type CycleParticipants = Arc>; +// We want `Cycle`` to be thin +pub(crate) type CycleParticipants = Arc>; impl Cycle { pub(crate) fn new(participants: CycleParticipants) -> Self { diff --git a/src/runtime.rs b/src/runtime.rs index ba35f09f..360a805c 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -1,10 +1,12 @@ use std::{ panic::panic_any, - sync::{atomic::AtomicUsize, Arc}, + sync::{ + atomic::{AtomicBool, AtomicUsize, Ordering}, + Arc, + }, thread::ThreadId, }; -use crossbeam::atomic::AtomicCell; use parking_lot::Mutex; use crate::{ @@ -24,7 +26,7 @@ pub struct Runtime { /// Set to true when the current revision has been canceled. /// This is done when we an input is being changed. The flag /// is set back to false once the input has been changed. - revision_canceled: AtomicCell, + revision_canceled: AtomicBool, /// Stores the "last change" revision for values of each duration. /// This vector is always of length at least 1 (for Durability 0) @@ -131,11 +133,11 @@ impl Runtime { } pub(crate) fn load_cancellation_flag(&self) -> bool { - self.revision_canceled.load() + self.revision_canceled.load(Ordering::Acquire) } pub(crate) fn set_cancellation_flag(&self) { - self.revision_canceled.store(true); + self.revision_canceled.store(true, Ordering::Release); } pub(crate) fn table(&self) -> &Table { @@ -150,7 +152,7 @@ impl Runtime { let r_old = self.current_revision(); let r_new = r_old.next(); self.revisions[0].store(r_new); - self.revision_canceled.store(false); + self.revision_canceled.store(false, Ordering::Release); r_new } @@ -277,19 +279,16 @@ impl Runtime { // (at least for this execution, not necessarily across executions), // no matter where it started on the stack. Find the minimum // key and rotate it to the front. - let min = v + if let Some((_, index, _)) = v .iter() - .map(|key| (key.ingredient_index.debug_name(db), key)) + .enumerate() + .map(|(idx, key)| (key.ingredient_index.debug_name(db), idx, key)) .min() - .unwrap() - .1; - let index = v.iter().position(|p| p == min).unwrap(); - v.rotate_left(index); + { + v.rotate_left(index); + } - // No need to store extra memory. - v.shrink_to_fit(); - - Cycle::new(Arc::new(v)) + Cycle::new(Arc::new(v.into_boxed_slice())) }; tracing::debug!("cycle {cycle:?}, cycle_query {cycle_query:#?}"); From b56547695277eed2e48f0851ac69097f541ff1eb Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Dec 2024 14:23:26 +0100 Subject: [PATCH 2/3] Remove unused `Runtime::next_id` field --- src/runtime.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/runtime.rs b/src/runtime.rs index 360a805c..4cace07e 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -1,7 +1,7 @@ use std::{ panic::panic_any, sync::{ - atomic::{AtomicBool, AtomicUsize, Ordering}, + atomic::{AtomicBool, Ordering}, Arc, }, thread::ThreadId, @@ -20,9 +20,6 @@ use self::dependency_graph::DependencyGraph; mod dependency_graph; pub struct Runtime { - /// Stores the next id to use for a snapshotted runtime (starts at 1). - next_id: AtomicUsize, - /// Set to true when the current revision has been canceled. /// This is done when we an input is being changed. The flag /// is set back to false once the input has been changed. @@ -86,7 +83,6 @@ impl Default for Runtime { revisions: (0..Durability::LEN) .map(|_| AtomicRevision::start()) .collect(), - next_id: AtomicUsize::new(1), revision_canceled: Default::default(), dependency_graph: Default::default(), table: Default::default(), @@ -98,7 +94,6 @@ impl std::fmt::Debug for Runtime { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fmt.debug_struct("Runtime") .field("revisions", &self.revisions) - .field("next_id", &self.next_id) .field("revision_canceled", &self.revision_canceled) .field("dependency_graph", &self.dependency_graph) .finish() From 54a147b61af9039bb191ca19f4ea776b0165dc0d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Dec 2024 14:25:30 +0100 Subject: [PATCH 3/3] Turn `Runtime::revisions` from `Vec` to `Box` --- src/revision.rs | 2 +- src/runtime.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/revision.rs b/src/revision.rs index a7445610..3bda6085 100644 --- a/src/revision.rs +++ b/src/revision.rs @@ -48,7 +48,7 @@ pub(crate) struct AtomicRevision { } impl AtomicRevision { - pub(crate) fn start() -> Self { + pub(crate) const fn start() -> Self { Self { data: AtomicUsize::new(START), } diff --git a/src/runtime.rs b/src/runtime.rs index 4cace07e..fb2e0720 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -34,7 +34,7 @@ pub struct Runtime { /// revisions[i + 1]`, for all `i`. This is because when you /// modify a value with durability D, that implies that values /// with durability less than D may have changed too. - revisions: Vec, + revisions: Box<[AtomicRevision; Durability::LEN]>, /// The dependency graph tracks which runtimes are blocked on one /// another, waiting for queries to terminate. @@ -80,9 +80,7 @@ impl StampedValue { impl Default for Runtime { fn default() -> Self { Runtime { - revisions: (0..Durability::LEN) - .map(|_| AtomicRevision::start()) - .collect(), + revisions: Box::new([const { AtomicRevision::start() }; Durability::LEN]), revision_canceled: Default::default(), dependency_graph: Default::default(), table: Default::default(),