Skip to main content

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}