Skip to main content

shipyard/scheduler/
info.rs

1//! Types for displaying workload information.
2
3use crate::borrow::Mutability;
4use crate::scheduler::{AsLabel, Label};
5use crate::storage::StorageId;
6use crate::ShipHashMap;
7use alloc::borrow::Cow;
8use alloc::boxed::Box;
9use alloc::string::String;
10use alloc::vec::Vec;
11use core::any::TypeId;
12
13/// Contains information related to a workload.
14///
15/// A workload is a collection of systems with parallelism calculated based on the types borrow by the systems.
16#[derive(Debug, Clone, PartialEq, Eq)]
17#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
18pub struct WorkloadInfo {
19    #[allow(missing_docs)]
20    pub name: String,
21    #[allow(missing_docs)]
22    pub batches_info: Vec<BatchInfo>,
23}
24
25/// Contains information related to a batch.
26///
27/// A batch is a collection of system that can safely run in parallel.
28#[derive(Debug, Clone, PartialEq, Eq)]
29#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
30pub struct BatchInfo {
31    #[allow(missing_docs)]
32    pub systems: (Option<SystemInfo>, Vec<SystemInfo>),
33}
34
35impl BatchInfo {
36    /// Returns an iterator of all systems in this batch
37    pub fn systems(&self) -> impl Iterator<Item = &'_ SystemInfo> {
38        self.systems.0.iter().chain(&self.systems.1)
39    }
40}
41
42/// Contains information related to a system.
43#[derive(Clone, PartialEq, Eq)]
44#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
45pub struct SystemInfo {
46    #[allow(missing_docs)]
47    pub name: String,
48    #[allow(missing_docs)]
49    pub borrow: Vec<TypeInfo>,
50    /// Information explaining why this system could not be part of the previous batch.
51    pub conflict: Option<Conflict>,
52    /// Contains all ordering information the scheduler used to place this system
53    pub after: Vec<usize>,
54    /// List of all after_all constraints
55    pub after_all: Vec<BeforeAfterConstraint>,
56    /// List of all before_all constraints
57    pub before_all: Vec<BeforeAfterConstraint>,
58    /// A unique identifier for this system within the workload
59    pub unique_id: usize,
60}
61
62impl core::fmt::Debug for SystemInfo {
63    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
64        f.debug_struct("SystemInfo")
65            .field("name", &self.name)
66            .field("unique_id", &self.unique_id)
67            .field("borrow", &self.borrow)
68            .field("conflict", &self.conflict)
69            .field("after", &self.after)
70            .field("after_all", &self.after_all)
71            .field("before_all", &self.before_all)
72            .finish()
73    }
74}
75
76/// Pinpoints the type and system that made a system unable to get into a batch.
77#[derive(Debug, Clone, PartialEq, Eq)]
78#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
79pub enum Conflict {
80    /// Rust rules do not allow the type described by `type_info` to be borrowed at the same time as `other_type_info`.
81    Borrow {
82        #[allow(missing_docs)]
83        type_info: TypeInfo,
84        #[allow(missing_docs)]
85        other_system: usize,
86        #[allow(missing_docs)]
87        other_type_info: TypeInfo,
88    },
89    /// A `!Send` and/or `!Sync` type currently prevents any parrallelism.
90    NotSendSync(TypeInfo),
91    /// A `!Send` and/or `!Sync` type currently prevents any parrallelism.
92    OtherNotSendSync {
93        #[allow(missing_docs)]
94        system: usize,
95        #[allow(missing_docs)]
96        type_info: TypeInfo,
97    },
98}
99
100/// Identify a type.
101#[derive(Clone, Eq)]
102#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
103pub struct TypeInfo {
104    #[allow(missing_docs)]
105    pub name: Cow<'static, str>,
106    #[allow(missing_docs)]
107    pub mutability: Mutability,
108    #[allow(missing_docs)]
109    #[cfg_attr(feature = "serde1", serde(skip))]
110    pub storage_id: StorageId,
111    #[allow(missing_docs)]
112    pub thread_safe: bool,
113}
114
115impl PartialEq for TypeInfo {
116    fn eq(&self, rhs: &Self) -> bool {
117        self.storage_id == rhs.storage_id && self.mutability == rhs.mutability
118    }
119}
120
121impl PartialEq<(TypeId, Mutability)> for TypeInfo {
122    fn eq(&self, rhs: &(TypeId, Mutability)) -> bool {
123        self.storage_id == rhs.0 && self.mutability == rhs.1
124    }
125}
126
127impl PartialOrd for TypeInfo {
128    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
129        Some(self.cmp(other))
130    }
131}
132
133impl Ord for TypeInfo {
134    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
135        match self.storage_id.cmp(&other.storage_id) {
136            core::cmp::Ordering::Equal => {}
137            ord => return ord,
138        }
139        self.mutability.cmp(&other.mutability)
140    }
141}
142
143impl core::fmt::Debug for TypeInfo {
144    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
145        let mut debug_struct = f.debug_struct("TypeInfo");
146
147        debug_struct
148            .field("name", &self.name)
149            .field("mutability", &self.mutability)
150            .field("thread_safe", &self.thread_safe)
151            .finish()
152    }
153}
154
155impl core::hash::Hash for TypeInfo {
156    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
157        self.storage_id.hash(state);
158        self.mutability.hash(state);
159    }
160}
161
162/// Contains a list of workloads, their systems and which storages these systems borrow.
163#[derive(Default, Debug, PartialEq, Eq)]
164#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
165pub struct WorkloadsInfo(pub ShipHashMap<String, WorkloadInfo>);
166
167impl WorkloadsInfo {
168    /// Creates an empty [`WorkloadsInfo`].
169    pub fn new() -> WorkloadsInfo {
170        WorkloadsInfo(ShipHashMap::new())
171    }
172}
173
174/// List of before/after requirements for a system or workload.\
175/// The list dedups items.
176#[derive(Clone, Debug, Default)]
177pub struct DedupedLabels(Vec<Box<dyn Label>>);
178
179impl DedupedLabels {
180    pub(crate) fn new() -> DedupedLabels {
181        DedupedLabels(Vec::new())
182    }
183
184    pub(crate) fn with_capacity(capacity: usize) -> DedupedLabels {
185        DedupedLabels(Vec::with_capacity(capacity))
186    }
187
188    /// Returns `true` if the `Label` was not already present.
189    pub(crate) fn add<T>(&mut self, label: impl AsLabel<T>) -> bool {
190        let label = label.as_label();
191
192        // Can't use binary search here as Label can't be ordered
193        if !self.0.contains(&label) {
194            self.0.push(label);
195
196            true
197        } else {
198            false
199        }
200    }
201
202    pub(crate) fn is_empty(&self) -> bool {
203        self.0.is_empty()
204    }
205
206    pub(crate) fn iter(&self) -> RequirementsIter<'_> {
207        self.into_iter()
208    }
209
210    pub(crate) fn clear(&mut self) {
211        self.0.clear();
212    }
213
214    pub(crate) fn retain<F: FnMut(&Box<dyn Label>) -> bool>(&mut self, f: F) {
215        self.0.retain(f);
216    }
217}
218
219impl IntoIterator for DedupedLabels {
220    type Item = Box<dyn Label>;
221    type IntoIter = alloc::vec::IntoIter<Self::Item>;
222
223    fn into_iter(self) -> Self::IntoIter {
224        self.0.into_iter()
225    }
226}
227
228impl<'a> IntoIterator for &'a DedupedLabels {
229    type Item = &'a Box<dyn Label>;
230    type IntoIter = RequirementsIter<'a>;
231
232    fn into_iter(self) -> Self::IntoIter {
233        RequirementsIter(self.0.iter())
234    }
235}
236
237/// Iterator for requirements
238pub struct RequirementsIter<'a>(core::slice::Iter<'a, Box<dyn Label>>);
239
240impl<'a> Iterator for RequirementsIter<'a> {
241    type Item = &'a Box<dyn Label>;
242
243    fn next(&mut self) -> Option<Self::Item> {
244        self.0.next()
245    }
246}
247
248impl Extend<Box<dyn Label>> for DedupedLabels {
249    fn extend<T: IntoIterator<Item = Box<dyn Label>>>(&mut self, iter: T) {
250        for label in iter {
251            self.add(label);
252        }
253    }
254}
255
256impl<'a> Extend<&'a Box<dyn Label>> for DedupedLabels {
257    fn extend<T: IntoIterator<Item = &'a Box<dyn Label>>>(&mut self, iter: T) {
258        for label in iter {
259            self.add(label.clone());
260        }
261    }
262}
263
264/// Represents a pair of constraints-tag that matched during scheduling.
265#[derive(Clone, PartialEq, Eq, Debug)]
266#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
267pub struct BeforeAfterConstraint {
268    #[allow(missing_docs)]
269    pub other_system: usize,
270    #[allow(missing_docs)]
271    pub constraint: String,
272}