Skip to main content

molframe_core/parallel/
policy.rs

1//! Whether a reduction may reassociate.
2//!
3//! Determinism is not free of consequence but it is nearly free of cost: it
4//! holds one partial per block live until the merge, and it fixes the order
5//! those partials combine in. What it buys is that a result does not change
6//! when a caller changes the thread count, which is what makes a recorded
7//! result reproducible by someone who has only the record.
8//!
9//! A caller who would rather have work stealing says so, and the result says
10//! so too. A speedup bought by silently changing the answer is not a speedup.
11
12use std::fmt;
13
14/// Whether a parallel reduction must combine partials in block order.
15#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)]
16pub enum ReductionPolicy {
17    /// Partials combine in ascending block index, whatever order they finish in.
18    ///
19    /// Output is bit-identical at any worker count.
20    #[default]
21    Deterministic,
22    /// Partials combine as they complete.
23    ///
24    /// Permits work stealing, and reassociates floating-point sums. A result
25    /// produced under this policy MUST record it in its provenance.
26    Fast,
27}
28
29impl ReductionPolicy {
30    /// Returns true when combination order is fixed by block index.
31    #[must_use]
32    pub const fn is_deterministic(self) -> bool {
33        matches!(self, Self::Deterministic)
34    }
35
36    /// The name recorded in provenance.
37    #[must_use]
38    pub const fn name(self) -> &'static str {
39        match self {
40            Self::Deterministic => "deterministic",
41            Self::Fast => "fast",
42        }
43    }
44}
45
46impl fmt::Display for ReductionPolicy {
47    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
48        formatter.write_str(self.name())
49    }
50}
51
52#[cfg(test)]
53#[path = "policy_tests.rs"]
54mod tests;