1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
//! Whole-unit tasks for passes that address their own data: the walk is a
//! range of unit indices, so only the task width comes from the runtime.
use ;
use crateExecutionPolicy;
use ;
/// Apply `f(state, first_unit, units)` to consecutive runs of whole units of a
/// pass that addresses its own data, each run sized to about
/// [`crate::UNIT_TASK_BYTES`] of work.
///
/// This is [`crate::for_each_unit_task_mut_with`] for a pass whose units are not a
/// dense slice the runtime can split: a strided row walk, a tiled block pass,
/// a reduction that writes one output per axis index. The caller owns the
/// disjointness proof for whatever those indices address, exactly as it does
/// today; this owns the one decision the slice operators own — how many units
/// a task carries, from the bytes a unit moves, and whether the pass spreads
/// over workers at all.
///
/// `unit_bytes` is the total a unit moves, its own bytes plus any input read
/// beside it. `init` builds one state per scheduled task (one in all when
/// serial). Each unit index in `0..units` is passed to exactly one call, in
/// one run of consecutive indices.
///
/// # Panics
///
/// Propagates a panic raised by `init` or `f`.
///
/// # Examples
///
/// ```
/// use moirai_parallel::{for_each_unit_task_range_with, Parallel};
/// use std::sync::atomic::{AtomicUsize, Ordering};
///
/// // Rows of a strided matrix: the walk addresses its own offsets, so only
/// // the task width comes from the runtime.
/// let (rows, row_bytes) = (1024, 8 * 64);
/// let visited: Vec<AtomicUsize> = (0..rows).map(|_| AtomicUsize::new(0)).collect();
/// for_each_unit_task_range_with::<Parallel, _, _, _>(
/// rows,
/// row_bytes,
/// || (),
/// |(), first_row, count| {
/// for row in first_row..first_row + count {
/// visited[row].fetch_add(1, Ordering::Relaxed);
/// }
/// },
/// );
/// assert!(visited.iter().all(|seen| seen.load(Ordering::Relaxed) == 1));
/// ```