Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/batching.rs
6601 views
1
//! Types for controlling batching behavior during parallel processing.
2
3
use core::ops::Range;
4
5
/// Dictates how a parallel operation chunks up large quantities
6
/// during iteration.
7
///
8
/// A parallel query will chunk up large tables and archetypes into
9
/// chunks of at most a certain batch size. Similarly, a parallel event
10
/// reader will chunk up the remaining events.
11
///
12
/// By default, this batch size is automatically determined by dividing
13
/// the size of the largest matched archetype by the number
14
/// of threads (rounded up). This attempts to minimize the overhead of scheduling
15
/// tasks onto multiple threads, but assumes each entity has roughly the
16
/// same amount of work to be done, which may not hold true in every
17
/// workload.
18
///
19
/// See [`Query::par_iter`], [`EventReader::par_read`] for more information.
20
///
21
/// [`Query::par_iter`]: crate::system::Query::par_iter
22
/// [`EventReader::par_read`]: crate::event::EventReader::par_read
23
#[derive(Clone, Debug)]
24
pub struct BatchingStrategy {
25
/// The upper and lower limits for a batch of items.
26
///
27
/// Setting the bounds to the same value will result in a fixed
28
/// batch size.
29
///
30
/// Defaults to `[1, usize::MAX]`.
31
pub batch_size_limits: Range<usize>,
32
/// The number of batches per thread in the [`ComputeTaskPool`].
33
/// Increasing this value will decrease the batch size, which may
34
/// increase the scheduling overhead for the iteration.
35
///
36
/// Defaults to 1.
37
///
38
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
39
pub batches_per_thread: usize,
40
}
41
42
impl Default for BatchingStrategy {
43
fn default() -> Self {
44
Self::new()
45
}
46
}
47
48
impl BatchingStrategy {
49
/// Creates a new unconstrained default batching strategy.
50
pub const fn new() -> Self {
51
Self {
52
batch_size_limits: 1..usize::MAX,
53
batches_per_thread: 1,
54
}
55
}
56
57
/// Declares a batching strategy with a fixed batch size.
58
pub const fn fixed(batch_size: usize) -> Self {
59
Self {
60
batch_size_limits: batch_size..batch_size,
61
batches_per_thread: 1,
62
}
63
}
64
65
/// Configures the minimum allowed batch size of this instance.
66
pub const fn min_batch_size(mut self, batch_size: usize) -> Self {
67
self.batch_size_limits.start = batch_size;
68
self
69
}
70
71
/// Configures the maximum allowed batch size of this instance.
72
pub const fn max_batch_size(mut self, batch_size: usize) -> Self {
73
self.batch_size_limits.end = batch_size;
74
self
75
}
76
77
/// Configures the number of batches to assign to each thread for this instance.
78
pub fn batches_per_thread(mut self, batches_per_thread: usize) -> Self {
79
assert!(
80
batches_per_thread > 0,
81
"The number of batches per thread must be non-zero."
82
);
83
self.batches_per_thread = batches_per_thread;
84
self
85
}
86
87
/// Calculate the batch size according to the given thread count and max item count.
88
/// The count is provided as a closure so that it can be calculated only if needed.
89
///
90
/// # Panics
91
///
92
/// Panics if `thread_count` is 0.
93
#[inline]
94
pub fn calc_batch_size(&self, max_items: impl FnOnce() -> usize, thread_count: usize) -> usize {
95
if self.batch_size_limits.is_empty() {
96
return self.batch_size_limits.start;
97
}
98
assert!(
99
thread_count > 0,
100
"Attempted to run parallel iteration with an empty TaskPool"
101
);
102
let batches = thread_count * self.batches_per_thread;
103
// Round up to the nearest batch size.
104
let batch_size = max_items().div_ceil(batches);
105
batch_size.clamp(self.batch_size_limits.start, self.batch_size_limits.end)
106
}
107
}
108
109