@@ -8,23 +8,38 @@ use std::time::{Duration, Instant};
88use std:: cmp:: Reverse ;
99use crossbeam_channel:: { Sender , Receiver } ;
1010
11- /// Methods required to act as a timely scheduler .
11+ /// Methods required to act as a scheduler for timely operators .
1212///
13- /// The core methods are the activation of "paths", sequences of integers, and
14- /// the enumeration of active paths by prefix. A scheduler may delay the report
15- /// of a path indefinitely, but it should report at least one extension for the
16- /// empty path `&[]` or risk parking the worker thread without a certain unpark.
13+ /// Operators are described by "paths" of integers, indicating the path along
14+ /// a tree of regions, arriving at the the operator. Each path is either "idle"
15+ /// or "active", where the latter indicates that someone has requested that the
16+ /// operator be scheduled by the worker. Operators go from idle to active when
17+ /// the `activate(path)` method is called, and from active to idle when the path
18+ /// is returned through a call to `extensions(path, _)`.
1719///
18- /// There is no known harm to "spurious wake-ups" where a not-active path is
19- /// returned through `extensions()`.
20+ /// The worker will continually probe for extensions to the root empty path `[]`,
21+ /// and then follow all returned addresses, recursively. A scheduler need not
22+ /// schedule all active paths, but it should return *some* active path when the
23+ /// worker probes the empty path, or the worker may put the thread to sleep.
24+ ///
25+ /// There is no known harm to scheduling an idle path.
26+ /// The worker may speculatively schedule paths of its own accord.
2027pub trait Scheduler {
2128 /// Mark a path as immediately scheduleable.
29+ ///
30+ /// The scheduler is not required to immediately schedule the path, but it
31+ /// should not signal that it has no work until the path has been scheduled.
2232 fn activate ( & mut self , path : & [ usize ] ) ;
2333 /// Populates `dest` with next identifiers on active extensions of `path`.
2434 ///
2535 /// This method is where a scheduler is allowed to exercise some discretion,
2636 /// in that it does not need to present *all* extensions, but it can instead
27- /// present only those that the runtime should schedule.
37+ /// present only those that the runtime should immediately schedule.
38+ ///
39+ /// The worker will schedule to all extensions before probing new prefixes.
40+ /// The scheduler is invited to rely on this, and to schedule in "batches",
41+ /// where the next time the worker probes for extensions to the empty path
42+ /// then all addresses in the batch have certainly been scheduled.
2843 fn extensions ( & mut self , path : & [ usize ] , dest : & mut Vec < usize > ) ;
2944}
3045
@@ -93,7 +108,7 @@ impl Activations {
93108 }
94109
95110 /// Discards the current active set and presents the next active set.
96- pub fn advance ( & mut self ) {
111+ fn advance ( & mut self ) {
97112
98113 // Drain inter-thread activations.
99114 while let Ok ( path) = self . rx . try_recv ( ) {
@@ -128,15 +143,15 @@ impl Activations {
128143 self . clean = self . bounds . len ( ) ;
129144 }
130145
131- /// Maps a function across activated paths.
132- pub fn map_active ( & self , logic : impl Fn ( & [ usize ] ) ) {
133- for ( offset, length) in self . bounds . iter ( ) {
134- logic ( & self . slices [ * offset .. ( * offset + * length) ] ) ;
135- }
136- }
137-
138146 /// Sets as active any symbols that follow `path`.
139- pub fn for_extensions ( & self , path : & [ usize ] , mut action : impl FnMut ( usize ) ) {
147+ pub fn for_extensions ( & mut self , path : & [ usize ] , mut action : impl FnMut ( usize ) ) {
148+
149+ // Each call for the root path is a moment where the worker has reset.
150+ // This relies on a worker implementation that follows the scheduling
151+ // instructions perfectly; if any offered paths are not explored, oops.
152+ if path. is_empty ( ) {
153+ self . advance ( ) ;
154+ }
140155
141156 let position =
142157 self . bounds [ ..self . clean ]
@@ -209,13 +224,14 @@ impl Activations {
209224 std:: thread:: park ( ) ;
210225 }
211226 }
227+ }
212228
213- /// True iff there are no immediate activations.
214- ///
215- /// Used by others to guard work done in anticipation of potentially parking.
216- /// An alternate method name could be `would_park`.
217- pub fn is_idle ( & self ) -> bool {
218- self . bounds . is_empty ( ) && self . timer . is_none ( )
229+ impl Scheduler for Activations {
230+ fn activate ( & mut self , path : & [ usize ] ) {
231+ self . activate ( path ) ;
232+ }
233+ fn extensions ( & mut self , path : & [ usize ] , dest : & mut Vec < usize > ) {
234+ self . for_extensions ( path , |index| dest . push ( index ) ) ;
219235 }
220236}
221237
0 commit comments