forked from bevyengine/bevy
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add default task pools and method for configuring them (bevyengine#2)
* Remove generics from TaskPool newtypes and some of the task API Add IO, AsyncCompute and Compute TaskPools Move TaskPool setup from bevy_ecs to bevy_app ParallelExecutorOptions is essentially replaced by DefaultTaskPoolOptions * Pull TaskPool and related types out of bevy_tasks/lib.rs into a separate module Add a prelude to bevy_tasks Update the version of bevy_tasks to match other crates * Assert percent of cores >= 0
- Loading branch information
Showing
13 changed files
with
521 additions
and
378 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
use bevy_ecs::Resources; | ||
use bevy_tasks::{AsyncComputeTaskPool, ComputeTaskPool, IOTaskPool, TaskPoolBuilder}; | ||
|
||
fn clamp_usize(value: usize, min: usize, max: usize) -> usize { | ||
if value > max { | ||
max | ||
} else if value < min { | ||
min | ||
} else { | ||
value | ||
} | ||
} | ||
|
||
/// Defines a simple way to determine how many threads to use given the number of remaining cores | ||
/// and number of total cores | ||
#[derive(Clone)] | ||
pub struct TaskPoolThreadAssignmentPolicy { | ||
/// Force using at least this many threads | ||
pub min_threads: usize, | ||
/// Under no circumstance use more than this many threads for this pool | ||
pub max_threads: usize, | ||
/// Target using this percentage of total cores, clamped by min_threads and max_threads. It is | ||
/// permitted to use 1.0 to try to use all remaining threads | ||
pub percent: f32, | ||
} | ||
|
||
impl TaskPoolThreadAssignmentPolicy { | ||
/// Determine the number of threads to use for this task pool | ||
fn get_number_of_threads(&self, remaining_threads: usize, total_threads: usize) -> usize { | ||
assert!(self.percent >= 0.0); | ||
let mut desired = (total_threads as f32 * self.percent).round() as usize; | ||
|
||
// Limit ourselves to the number of cores available | ||
desired = desired.min(remaining_threads); | ||
|
||
// Clamp by min_threads, max_threads. (This may result in us using more threads than are | ||
// available, this is intended. An example case where this might happen is a device with | ||
// <= 2 threads. | ||
clamp_usize(desired, self.min_threads, self.max_threads) | ||
} | ||
} | ||
|
||
/// Helper for configuring and creating the default task pools. For end-users who want full control, | ||
/// insert the default task pools into the resource map manually. If the pools are already inserted, | ||
/// this helper will do nothing. | ||
#[derive(Clone)] | ||
pub struct DefaultTaskPoolOptions { | ||
/// If the number of physical cores is less than min_total_threads, force using min_total_threads | ||
pub min_total_threads: usize, | ||
/// If the number of physical cores is grater than max_total_threads, force using max_total_threads | ||
pub max_total_threads: usize, | ||
|
||
/// Used to determine number of IO threads to allocate | ||
pub io: TaskPoolThreadAssignmentPolicy, | ||
/// Used to determine number of async compute threads to allocate | ||
pub async_compute: TaskPoolThreadAssignmentPolicy, | ||
/// Used to determine number of compute threads to allocate | ||
pub compute: TaskPoolThreadAssignmentPolicy, | ||
} | ||
|
||
impl Default for DefaultTaskPoolOptions { | ||
fn default() -> Self { | ||
DefaultTaskPoolOptions { | ||
// By default, use however many cores are available on the system | ||
min_total_threads: 1, | ||
max_total_threads: std::usize::MAX, | ||
|
||
// Use 25% of cores for IO, at least 1, no more than 4 | ||
io: TaskPoolThreadAssignmentPolicy { | ||
min_threads: 1, | ||
max_threads: 4, | ||
percent: 0.25, | ||
}, | ||
|
||
// Use 25% of cores for async compute, at least 1, no more than 4 | ||
async_compute: TaskPoolThreadAssignmentPolicy { | ||
min_threads: 1, | ||
max_threads: 4, | ||
percent: 0.25, | ||
}, | ||
|
||
// Use all remaining cores for compute (at least 1) | ||
compute: TaskPoolThreadAssignmentPolicy { | ||
min_threads: 1, | ||
max_threads: std::usize::MAX, | ||
percent: 1.0, // This 1.0 here means "whatever is left over" | ||
}, | ||
} | ||
} | ||
} | ||
|
||
impl DefaultTaskPoolOptions { | ||
/// Create a configuration that forces using the given number of threads. | ||
pub fn with_num_threads(thread_count: usize) -> Self { | ||
let mut options = Self::default(); | ||
options.min_total_threads = thread_count; | ||
options.max_total_threads = thread_count; | ||
|
||
options | ||
} | ||
|
||
/// Inserts the default thread pools into the given resource map based on the configured values | ||
pub fn create_default_pools(&self, resources: &mut Resources) { | ||
let total_threads = clamp_usize( | ||
num_cpus::get(), | ||
self.min_total_threads, | ||
self.max_total_threads, | ||
); | ||
|
||
let mut remaining_threads = total_threads; | ||
|
||
if !resources.contains::<IOTaskPool>() { | ||
// Determine the number of IO threads we will use | ||
let io_threads = self | ||
.io | ||
.get_number_of_threads(remaining_threads, total_threads); | ||
remaining_threads -= io_threads; | ||
|
||
resources.insert(IOTaskPool( | ||
TaskPoolBuilder::default() | ||
.num_threads(io_threads) | ||
.thread_name("IO Task Pool".to_string()) | ||
.build(), | ||
)); | ||
} | ||
|
||
if !resources.contains::<AsyncComputeTaskPool>() { | ||
// Determine the number of async compute threads we will use | ||
let async_compute_threads = self | ||
.async_compute | ||
.get_number_of_threads(remaining_threads, total_threads); | ||
remaining_threads -= async_compute_threads; | ||
|
||
resources.insert(AsyncComputeTaskPool( | ||
TaskPoolBuilder::default() | ||
.num_threads(async_compute_threads) | ||
.thread_name("Async Compute Task Pool".to_string()) | ||
.build(), | ||
)); | ||
} | ||
|
||
if !resources.contains::<ComputeTaskPool>() { | ||
// Determine the number of compute threads we will use | ||
// This is intentionally last so that an end user can specify 1.0 as the percent | ||
let compute_threads = self | ||
.compute | ||
.get_number_of_threads(remaining_threads, total_threads); | ||
|
||
resources.insert(ComputeTaskPool( | ||
TaskPoolBuilder::default() | ||
.num_threads(compute_threads) | ||
.thread_name("Compute Task Pool".to_string()) | ||
.build(), | ||
)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
[package] | ||
name = "bevy_tasks" | ||
version = "0.1.0" | ||
version = "0.1.3" | ||
authors = [ | ||
"Bevy Contributors <[email protected]>", | ||
"Lachlan Sneff <[email protected]>", | ||
|
Oops, something went wrong.