-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Task System for Bevy #384
Task System for Bevy #384
Conversation
Move the github.com/lachlansneff/small-tasks prototype into bevy/crates/bevy_tasks. This is intended to replace rayon to provide better idling behavior. Initial commit Make scope return a vector of results Add par_chunk_map(_mut) and par_splat_map(_mut) apis onto slices Make calling thread do work until complete Remove current-thread doing work Ignore clion/intellij project files Remove dependency on futures-util Set up a builder for constructing the TaskPool with customizable thread count, stack size, and thread name. Add a couple examples to demonstrate busy and idle workloads. More detail on thread name doc comments and static build() function on TaskPool Update to README (add description, status, license) Reflect rayon's ThreadPoolBuilder api in TaskPoolBuilder Co-authored-by: Philip Degarmo <[email protected]>
Add test of global pool Formatting
… already installed globally
…or (#1) Add a task newtype so that we don't expose multitask::Task Remove some of the README/license info that was present in the prototype repo Add some doc comments
…l a resource instead of an internal static
* 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
Nice! Any idea by how much? |
Just to crudely illustrate how much of an improvement this is, when I run the breakout example I get the following cpu usage (average across cores): rayon 1.3: ~50% |
This also cuts our dependency count by 7 and significantly decreases compile times. For example, before breakout clean-compiled in release mode on my machine in Now it compiles in |
Actually I ran a few more tests and I dont think the difference is quite that stark. Probably closer to 5-10 seconds. |
Great stuff!
thread_local! {
static EXECUTOR: RefCell<LocalExecutor> = RefCell::new(LocalExecutor::new());
}
To protect from people trying to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fantastic work. A big thanks to everyone involved!
crates/bevy_app/Cargo.toml
Outdated
@@ -13,6 +13,8 @@ keywords = ["bevy"] | |||
# bevy | |||
bevy_derive = { path = "../bevy_derive", version = "0.1" } | |||
bevy_ecs = { path = "../bevy_ecs", version = "0.1" } | |||
bevy_tasks = { path = "../bevy_tasks" } | |||
num_cpus = "1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bevy_tasks also relies on num_cpus. this seems like functionality that is relevant enough to consumers that we could just provide a bevy_tasks api.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good
@@ -63,6 +63,12 @@ impl App { | |||
} | |||
|
|||
pub fn run(mut self) { | |||
// Setup the default bevy task pools | |||
self.resources |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced bevy_tasks should be hard-coded into apps, especially given that we're just adding resources. Can we make this a plugin that we add with add_default_plugins()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making a plugin in bevy_tasks will cause circular dependencies (app depends on ecs, ecs depends on tasks). Where to do you want it to be?
use bevy_ecs::Resources; | ||
use bevy_tasks::{AsyncComputeTaskPool, ComputeTaskPool, IOTaskPool, TaskPoolBuilder}; | ||
|
||
fn clamp_usize(value: usize, min: usize, max: usize) -> usize { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clamp is a big enough missing piece in the rust std that it probably makes sense to expose it in bevy_math
. Can we add a generic version there and then consume it here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll copy/paste num-traits implementation (licensed MIT) with a note as to where it came from
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://doc.rust-lang.org/std/cmp/trait.Ord.html#method.clamp
it's available on nightly, is it possible to switch to the default impl for nightly users?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooh I didn't know that. Definitely good to know. In general I would prefer to wait for nightly features to land in stable. Otherwise we'll need to maintain multiple code paths, which makes it harder to debug and repro potential issues.
crates/bevy_tasks/src/slice.rs
Outdated
let task_pool = TaskPool::new(); | ||
let outputs = v.par_splat_map(&task_pool, None, |numbers| -> i32 { numbers.iter().sum() }); | ||
|
||
println!("outputs: {:?}", outputs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we swap the println!()
calls in these tests for asserts on output values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea
crates/bevy_tasks/src/task_pool.rs
Outdated
/// Vec<Task<T>> contained within TaskPoolInner | ||
executor: Arc<multitask::Executor>, | ||
|
||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: empty docs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will fix
@kabergstrom yeah that would be a welcome feature. when this gets merged, can you create an issue for it? id prefer to keep this pr constrained to its current scope. @lachlansneff some of the schedule tests are failing because ComputeTaskPool doesn't exist. we'll need to fix them before merging. |
On a 3950x with 32 cores, I see a bigger difference (and rayon 1.3 and 1.4 give the same results for me): |
I think I addressed everything - I PR'ed it to @lachlansneff's branch so he can review it before we ask @cart to take another look. |
* Address some feedback for the bevy_tasks PR - Add a general clamp fn to bevy_math - Expose num_cpus in bevy_tasks - Fill out empty doc comment * Add comments and clean up pinning in bevy_tasks, fix a couple tests
Co-authored-by: stefee <[email protected]>
@cart I think this is ready for a second look, the two main issues remaining are:
|
Ok I think this ready to merge now. The "bevy_tasks hard coded into apps" issue can be resolved separately. I'd rather merge this and then iterate than wait longer. One more huge thanks to everyone involved. This is a big step forward! |
Add bevy_tasks crate to replace rayon
I chose to remove the extended documentation for `TaskPool::executor`. It references `TaskPoolInner` which was added in bevyengine#384 when `bevy_tasks` was first created, but that struct was later removed in bevyengine#2250. James may be able to rewrite the comment, but I do not know enough about the task pool to write anything.
Currently bevy depends on rayon for multithreaded dispatching of systems. This PR replaces rayon with a custom designed task system that consists of several threaded "TaskPools."
Why replace Rayon
Bevy Tasks
bevy_tasks
does three things:These are enough to replace all current rayon functionality within bevy, as well as to provide additional functionality that can partially supplant parts of rayon's parallel iteration support.
Exposed API
IOTaskPool
,ComputePool
, andAsyncComputePool
.bevy_app
exportsDefaultTaskPoolOptions
now.Future work:
Resolves #318