music21/common/parallel.rs
1//! music21's `common.parallel`, as far as it is not about Python objects.
2
3use std::ops::Range;
4
5/// How many processes music21 runs at once on a machine with this many
6/// processors: one fewer than there are, leaving one free, from three up.
7///
8/// ```
9/// use music21::common::parallel::cpus_for;
10///
11/// assert_eq!(cpus_for(8), 7);
12/// assert_eq!(cpus_for(2), 2);
13/// ```
14pub fn cpus_for(count: usize) -> usize {
15 if count >= 3 {
16 return count - 1;
17 }
18 count
19}
20
21/// [`cpus_for`] this machine, as far as the standard library can tell how
22/// many processors it has.
23pub fn cpus() -> usize {
24 cpus_for(std::thread::available_parallelism().map_or(1, std::num::NonZero::get))
25}
26
27/// The positions an update reports on once `done` tasks are done and it
28/// reports every `window` of them: the last `window` positions, none before
29/// the first.
30///
31/// ```
32/// use music21::common::parallel::update_positions;
33///
34/// assert_eq!(update_positions(3, 3), 0..3);
35/// assert_eq!(update_positions(2, 3), 0..2);
36/// ```
37pub fn update_positions(done: i64, window: i64) -> Range<i64> {
38 done.saturating_sub(window).max(0)..done
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44
45 /// Nothing is reported before any task is done, nor for a window that
46 /// is not positive.
47 #[test]
48 fn updates_report_only_done_positions() {
49 assert!(update_positions(0, 3).is_empty());
50 assert!(update_positions(5, 0).is_empty());
51 assert!(update_positions(5, -2).is_empty());
52 assert_eq!(update_positions(9, 3), 6..9);
53 assert_eq!(cpus_for(1), 1);
54 assert_eq!(cpus_for(3), 2);
55 assert!(cpus() >= 1);
56 }
57}