mirror of
https://github.com/bevyengine/bevy
synced 2024-12-21 02:23:08 +00:00
d70595b667
# Objective - Fixes #6370 - Closes #6581 ## Solution - Added the following lints to the workspace: - `std_instead_of_core` - `std_instead_of_alloc` - `alloc_instead_of_core` - Used `cargo +nightly fmt` with [item level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A) to split all `use` statements into single items. - Used `cargo clippy --workspace --all-targets --all-features --fix --allow-dirty` to _attempt_ to resolve the new linting issues, and intervened where the lint was unable to resolve the issue automatically (usually due to needing an `extern crate alloc;` statement in a crate root). - Manually removed certain uses of `std` where negative feature gating prevented `--all-features` from finding the offending uses. - Used `cargo +nightly fmt` with [crate level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A) to re-merge all `use` statements matching Bevy's previous styling. - Manually fixed cases where the `fmt` tool could not re-merge `use` statements due to conditional compilation attributes. ## Testing - Ran CI locally ## Migration Guide The MSRV is now 1.81. Please update to this version or higher. ## Notes - This is a _massive_ change to try and push through, which is why I've outlined the semi-automatic steps I used to create this PR, in case this fails and someone else tries again in the future. - Making this change has no impact on user code, but does mean Bevy contributors will be warned to use `core` and `alloc` instead of `std` where possible. - This lint is a critical first step towards investigating `no_std` options for Bevy. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com>
107 lines
3.7 KiB
Rust
107 lines
3.7 KiB
Rust
//! Types for controlling batching behavior during parallel processing.
|
|
|
|
use core::ops::Range;
|
|
|
|
/// Dictates how a parallel operation chunks up large quantities
|
|
/// during iteration.
|
|
///
|
|
/// A parallel query will chunk up large tables and archetypes into
|
|
/// chunks of at most a certain batch size. Similarly, a parallel event
|
|
/// reader will chunk up the remaining events.
|
|
///
|
|
/// By default, this batch size is automatically determined by dividing
|
|
/// the size of the largest matched archetype by the number
|
|
/// of threads (rounded up). This attempts to minimize the overhead of scheduling
|
|
/// tasks onto multiple threads, but assumes each entity has roughly the
|
|
/// same amount of work to be done, which may not hold true in every
|
|
/// workload.
|
|
///
|
|
/// See [`Query::par_iter`], [`EventReader::par_read`] for more information.
|
|
///
|
|
/// [`Query::par_iter`]: crate::system::Query::par_iter
|
|
/// [`EventReader::par_read`]: crate::event::EventReader::par_read
|
|
#[derive(Clone, Debug)]
|
|
pub struct BatchingStrategy {
|
|
/// The upper and lower limits for a batch of entities.
|
|
///
|
|
/// Setting the bounds to the same value will result in a fixed
|
|
/// batch size.
|
|
///
|
|
/// Defaults to `[1, usize::MAX]`.
|
|
pub batch_size_limits: Range<usize>,
|
|
/// The number of batches per thread in the [`ComputeTaskPool`].
|
|
/// Increasing this value will decrease the batch size, which may
|
|
/// increase the scheduling overhead for the iteration.
|
|
///
|
|
/// Defaults to 1.
|
|
///
|
|
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
|
pub batches_per_thread: usize,
|
|
}
|
|
|
|
impl Default for BatchingStrategy {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl BatchingStrategy {
|
|
/// Creates a new unconstrained default batching strategy.
|
|
pub const fn new() -> Self {
|
|
Self {
|
|
batch_size_limits: 1..usize::MAX,
|
|
batches_per_thread: 1,
|
|
}
|
|
}
|
|
|
|
/// Declares a batching strategy with a fixed batch size.
|
|
pub const fn fixed(batch_size: usize) -> Self {
|
|
Self {
|
|
batch_size_limits: batch_size..batch_size,
|
|
batches_per_thread: 1,
|
|
}
|
|
}
|
|
|
|
/// Configures the minimum allowed batch size of this instance.
|
|
pub const fn min_batch_size(mut self, batch_size: usize) -> Self {
|
|
self.batch_size_limits.start = batch_size;
|
|
self
|
|
}
|
|
|
|
/// Configures the maximum allowed batch size of this instance.
|
|
pub const fn max_batch_size(mut self, batch_size: usize) -> Self {
|
|
self.batch_size_limits.end = batch_size;
|
|
self
|
|
}
|
|
|
|
/// Configures the number of batches to assign to each thread for this instance.
|
|
pub fn batches_per_thread(mut self, batches_per_thread: usize) -> Self {
|
|
assert!(
|
|
batches_per_thread > 0,
|
|
"The number of batches per thread must be non-zero."
|
|
);
|
|
self.batches_per_thread = batches_per_thread;
|
|
self
|
|
}
|
|
|
|
/// Calculate the batch size according to the given thread count and max item count.
|
|
/// The count is provided as a closure so that it can be calculated only if needed.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// Panics if `thread_count` is 0.
|
|
#[inline]
|
|
pub fn calc_batch_size(&self, max_items: impl FnOnce() -> usize, thread_count: usize) -> usize {
|
|
if self.batch_size_limits.is_empty() {
|
|
return self.batch_size_limits.start;
|
|
}
|
|
assert!(
|
|
thread_count > 0,
|
|
"Attempted to run parallel iteration with an empty TaskPool"
|
|
);
|
|
let batches = thread_count * self.batches_per_thread;
|
|
// Round up to the nearest batch size.
|
|
let batch_size = (max_items() + batches - 1) / batches;
|
|
batch_size.clamp(self.batch_size_limits.start, self.batch_size_limits.end)
|
|
}
|
|
}
|