Skip to content
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

System sets and parallel executor v2 #1144

Merged
merged 78 commits into from
Feb 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
c18476a
new year new schedule
cart Dec 5, 2020
234e766
everything works!
cart Dec 5, 2020
2f6c231
fix stuff
cart Dec 6, 2020
474dc05
state work
cart Dec 6, 2020
40e8953
states kind of work?
cart Dec 6, 2020
0cdcfd9
run_criteria, FixedTimestep, and fix stages
cart Dec 6, 2020
e4d7ab5
remove System::is_initialized
cart Dec 6, 2020
e370da0
simpler timestep
cart Dec 6, 2020
bf9c513
IntoStage
cart Dec 6, 2020
7699ec4
remove startup_schedule in favor of stage::STARTUP. add RunOnce
cart Dec 6, 2020
dbe3748
clippy and fmt
cart Dec 6, 2020
cadd846
initial state example
cart Dec 6, 2020
2611cc5
renames
cart Dec 7, 2020
509f5f5
run StateStage until there are no queued changes
cart Dec 7, 2020
000dd7e
state example
cart Dec 7, 2020
9b382ea
fmt
cart Dec 7, 2020
061f0c4
adapt to new clippy rule
cart Dec 7, 2020
5c435be
fix tests
cart Dec 7, 2020
ccad3c6
rename System Input and Output to In and Out
cart Dec 10, 2020
465f59e
partial SystemSet impl (intentionally broken)
cart Dec 11, 2020
b966034
Preparatory work for new parallel scheduling implementation:
Ratysz Dec 12, 2020
457262c
Preparatory work, continued:
Ratysz Dec 13, 2020
ffe34e7
Parallel executor implementation, pt 1:
Ratysz Dec 14, 2020
26afcfe
Parallel executor implementation, pt 2:
Ratysz Dec 14, 2020
0e75a60
Parallel executor implementation, pt 3:
Ratysz Dec 15, 2020
7d36fc0
Parallel executor implementation, pt 4:
Ratysz Dec 20, 2020
4a6db18
Fixed access violation.
Ratysz Dec 22, 2020
c29ab55
Merge remote-tracking branch 'upstream/master' into schedule-v2
Ratysz Dec 23, 2020
52f692f
Revert deletion via merge screwup...
Ratysz Dec 23, 2020
1746bb1
Fixed more merge artefacts, implemented `Stage::initialize()`.
Ratysz Dec 23, 2020
5d133fa
Actually mark new systems as uninitialized.
Ratysz Dec 23, 2020
a68611b
... remove repeat initialization from `run_once()`.
Ratysz Dec 23, 2020
55e8eb1
Fix formatting.
Ratysz Dec 24, 2020
8fbe2a7
Remove (yet) unused imports from tests.
Ratysz Dec 24, 2020
c4e8261
Absorbed `AccessSet` implementation into `TypeAccess`.
Ratysz Dec 29, 2020
e0b9d14
Merge branch 'upstream-master' into executor-v2
Ratysz Jan 9, 2021
504055f
System insertion API, part 1:
Ratysz Jan 12, 2021
64a276a
System insertion API, part 2:
Ratysz Jan 13, 2021
7234d22
Implemented dependency cycle detection; refactors.
Ratysz Jan 16, 2021
fe60c85
Merge branch 'upstream-master' into executor-v2
Ratysz Jan 16, 2021
44d4271
Removed usage of `AHashExt`.
Ratysz Jan 17, 2021
43a08f9
Decoupled exclusive systems from parallel systems:
Ratysz Jan 18, 2021
70850fa
Reworked parallel system insertion API with `.before()` and `.after()`.
Ratysz Jan 18, 2021
027f80a
Removed "writes all" case from access types, simplified them accordin…
Ratysz Jan 18, 2021
116c877
Removed `Stage::initialize()`, `Schedule::initialize_and_run()`.
Ratysz Jan 18, 2021
c972161
Merge branch 'upstream-master' into executor-v2
Ratysz Jan 19, 2021
19c7430
Reworked the parallel executor to make use of `!Send` tasks.
Ratysz Jan 19, 2021
ad14e57
Fixed tests broken by `initialize_and_run` removal.
Ratysz Jan 19, 2021
43dd985
Fixed & exposed `ThreadLocal`; refactors; some tests; topological sor…
Ratysz Jan 21, 2021
e1da00a
Made dependencies "soft" by default, added test cases for that; added…
Ratysz Jan 23, 2021
6ae4398
... include the change that fell off of previous commit, somehow.
Ratysz Jan 23, 2021
e8b02fe
Refactors: `SystemStageExecutor` renamed to `ParallelSystemExecutor`,…
Ratysz Jan 23, 2021
cd20ee4
Renamed `ThreadLocal` and friends into `NonSend`; preemptively fixed …
Ratysz Jan 25, 2021
59a03ad
Moved the burder of creating and maintaining the parallel "should run…
Ratysz Jan 25, 2021
5c9cf4d
Flattened stages' system storage.
Ratysz Jan 26, 2021
61a0211
Implemented parallel system order ambiguity detection; plumbed archet…
Ratysz Jan 26, 2021
c5fc80d
Fixed parallel executor "starting" more than one non-send system at a…
Ratysz Jan 27, 2021
e9321f8
Unified system descriptors, deduplicated system insertion methods; re…
Ratysz Jan 27, 2021
0c30716
Execution order ambiguity for exclusive systems; refactors; reverted …
Ratysz Jan 28, 2021
01164e5
Switched ambiguity reporting to proper logging.
Ratysz Jan 28, 2021
a8df35c
Switched to `Cow`s for system labels.
Ratysz Jan 29, 2021
976cc53
Added basic executor benchmarks.
Ratysz Feb 1, 2021
ad89d68
Tweak benchmarks.
Ratysz Feb 1, 2021
4a82850
Renamed & rearranged variants of `ShouldRun`; more descriptive panics…
Ratysz Feb 4, 2021
feb38d5
Bare minimum documentation.
Ratysz Feb 4, 2021
a32063e
Merge branch 'upstream-master' into executor-v2
Ratysz Feb 4, 2021
e42f1f4
Post-merge fix.
Ratysz Feb 4, 2021
f7a0eb6
Removed outdated tests in `shedule`; `// TODO` -> `// TODO:`.
Ratysz Feb 5, 2021
3cfd48a
Renamed `ShouldRun::NoButCheckAgain` to `NoAndCheckAgain`.
Ratysz Feb 5, 2021
e09298f
Removed `SystemKind` and associated branching.
Ratysz Feb 5, 2021
d9fa55d
Minor refactors for clarity.
Ratysz Feb 5, 2021
ec845c5
Refactors; better errors; opt-in and better ambiguity reporting.
Ratysz Feb 6, 2021
42118c9
Clippy.
Ratysz Feb 6, 2021
b532235
`NonSend` documentation, minor error message fixes.
Ratysz Feb 6, 2021
e23c8a8
fix flex system ambiguity
cart Feb 7, 2021
c69579f
Improved ambiguity detection tests.
Ratysz Feb 8, 2021
d929da3
Fixed ambiguity detection bug.
Ratysz Feb 9, 2021
69a55aa
Applied suggested optimization.
Ratysz Feb 9, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions crates/bevy_app/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::app_builder::AppBuilder;
use bevy_ecs::{Resources, Schedule, World};
use bevy_ecs::{Resources, Schedule, Stage, World};
#[cfg(feature = "trace")]
use bevy_utils::tracing::info_span;

Expand Down Expand Up @@ -53,8 +53,7 @@ impl App {
}

pub fn update(&mut self) {
self.schedule
.initialize_and_run(&mut self.world, &mut self.resources);
self.schedule.run(&mut self.world, &mut self.resources);
}

pub fn run(mut self) {
Expand Down
84 changes: 41 additions & 43 deletions crates/bevy_app/src/app_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::{
stage, startup_stage, PluginGroup, PluginGroupBuilder,
};
use bevy_ecs::{
clear_trackers_system, FromResources, IntoSystem, Resource, Resources, RunOnce, Schedule,
Stage, StateStage, System, SystemStage, World,
clear_trackers_system, FromResources, IntoExclusiveSystem, IntoSystem, Resource, Resources,
RunOnce, Schedule, Stage, StateStage, SystemDescriptor, SystemStage, World,
};
use bevy_utils::tracing::debug;

Expand All @@ -24,7 +24,7 @@ impl Default for AppBuilder {
app_builder
.add_default_stages()
.add_event::<AppExit>()
.add_system_to_stage(stage::LAST, clear_trackers_system.system());
.add_system_to_stage(stage::LAST, clear_trackers_system.exclusive_system());
app_builder
}
}
Expand Down Expand Up @@ -125,60 +125,69 @@ impl AppBuilder {
self
}

pub fn add_system<S: System<In = (), Out = ()>>(&mut self, system: S) -> &mut Self {
pub fn add_system(&mut self, system: impl Into<SystemDescriptor>) -> &mut Self {
self.add_system_to_stage(stage::UPDATE, system)
}

pub fn on_state_enter<T: Clone + Resource, S: System<In = (), Out = ()>>(
pub fn add_system_to_stage(
&mut self,
stage_name: &'static str,
system: impl Into<SystemDescriptor>,
) -> &mut Self {
self.app.schedule.add_system_to_stage(stage_name, system);
self
}

pub fn add_startup_system(&mut self, system: impl Into<SystemDescriptor>) -> &mut Self {
self.add_startup_system_to_stage(startup_stage::STARTUP, system)
}

pub fn add_startup_system_to_stage(
&mut self,
stage_name: &'static str,
system: impl Into<SystemDescriptor>,
) -> &mut Self {
self.app
.schedule
.stage(stage::STARTUP, |schedule: &mut Schedule| {
schedule.add_system_to_stage(stage_name, system)
});
self
}

pub fn on_state_enter<T: Clone + Resource>(
&mut self,
stage: &str,
state: T,
system: S,
system: impl Into<SystemDescriptor>,
) -> &mut Self {
self.stage(stage, |stage: &mut StateStage<T>| {
stage.on_state_enter(state, system)
})
}

pub fn on_state_update<T: Clone + Resource, S: System<In = (), Out = ()>>(
pub fn on_state_update<T: Clone + Resource>(
&mut self,
stage: &str,
state: T,
system: S,
system: impl Into<SystemDescriptor>,
) -> &mut Self {
self.stage(stage, |stage: &mut StateStage<T>| {
stage.on_state_update(state, system)
})
}

pub fn on_state_exit<T: Clone + Resource, S: System<In = (), Out = ()>>(
pub fn on_state_exit<T: Clone + Resource>(
&mut self,
stage: &str,
state: T,
system: S,
system: impl Into<SystemDescriptor>,
) -> &mut Self {
self.stage(stage, |stage: &mut StateStage<T>| {
stage.on_state_exit(state, system)
})
}

pub fn add_startup_system_to_stage<S: System<In = (), Out = ()>>(
&mut self,
stage_name: &'static str,
system: S,
) -> &mut Self {
self.app
.schedule
.stage(stage::STARTUP, |schedule: &mut Schedule| {
schedule.add_system_to_stage(stage_name, system)
});
self
}

pub fn add_startup_system<S: System<In = (), Out = ()>>(&mut self, system: S) -> &mut Self {
self.add_startup_system_to_stage(startup_stage::STARTUP, system)
}

pub fn add_default_stages(&mut self) -> &mut Self {
self.add_stage(
stage::STARTUP,
Expand All @@ -197,15 +206,6 @@ impl AppBuilder {
.add_stage(stage::LAST, SystemStage::parallel())
}

pub fn add_system_to_stage<S: System<In = (), Out = ()>>(
&mut self,
stage_name: &'static str,
system: S,
) -> &mut Self {
self.app.schedule.add_system_to_stage(stage_name, system);
self
}

pub fn add_event<T>(&mut self) -> &mut Self
where
T: Send + Sync + 'static,
Expand All @@ -223,11 +223,11 @@ impl AppBuilder {
self
}

pub fn insert_thread_local_resource<T>(&mut self, resource: T) -> &mut Self
pub fn insert_non_send_resource<T>(&mut self, resource: T) -> &mut Self
where
T: 'static,
{
self.app.resources.insert_thread_local(resource);
self.app.resources.insert_non_send(resource);
self
}

Expand All @@ -242,20 +242,18 @@ impl AppBuilder {
let resource = R::from_resources(&self.resources());
self.insert_resource(resource);
}

self
}

pub fn init_thread_local_resource<R>(&mut self) -> &mut Self
pub fn init_non_send_resource<R>(&mut self) -> &mut Self
where
R: FromResources + 'static,
{
// See perf comment in init_resource
if self.app.resources.get_thread_local::<R>().is_none() {
if self.app.resources.get_non_send::<R>().is_none() {
let resource = R::from_resources(&self.app.resources);
self.app.resources.insert_thread_local(resource);
self.app.resources.insert_non_send(resource);
}

self
}

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_audio/src/audio_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ where
<P as Decodable>::Decoder: rodio::Source + Send + Sync,
<<P as Decodable>::Decoder as Iterator>::Item: rodio::Sample + Send + Sync,
{
let audio_output = resources.get_thread_local::<AudioOutput<P>>().unwrap();
let audio_output = resources.get_non_send::<AudioOutput<P>>().unwrap();
let mut audio = resources.get_mut::<Audio<P>>().unwrap();

if let Some(audio_sources) = resources.get::<Assets<P>>() {
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_audio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ pub mod prelude {

use bevy_app::prelude::*;
use bevy_asset::AddAsset;
use bevy_ecs::IntoSystem;
use bevy_ecs::IntoExclusiveSystem;

/// Adds support for audio playback to an App
#[derive(Default)]
pub struct AudioPlugin;

impl Plugin for AudioPlugin {
fn build(&self, app: &mut AppBuilder) {
app.init_thread_local_resource::<AudioOutput<AudioSource>>()
app.init_non_send_resource::<AudioOutput<AudioSource>>()
.add_asset::<AudioSource>()
.init_asset_loader::<Mp3Loader>()
.init_resource::<Audio<AudioSource>>()
.add_system_to_stage(
stage::POST_UPDATE,
play_queued_audio_system::<AudioSource>.system(),
play_queued_audio_system::<AudioSource>.exclusive_system(),
);
}
}
31 changes: 16 additions & 15 deletions crates/bevy_core/src/label.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,14 @@ pub(crate) fn entity_labels_system(
#[cfg(test)]
mod tests {
use super::*;
use bevy_ecs::Stage;

fn setup() -> (World, Resources, bevy_ecs::Schedule) {
let world = World::new();
let mut resources = Resources::default();
resources.insert(EntityLabels::default());
let mut schedule = bevy_ecs::Schedule::default();
schedule.add_stage("test", SystemStage::serial());
schedule.add_stage("test", SystemStage::single_threaded());
schedule.add_system_to_stage("test", entity_labels_system.system());
(world, resources, schedule)
}
Expand All @@ -139,7 +140,7 @@ mod tests {
let (mut world, mut resources, mut schedule) = setup();

let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[e1], "holy");
Expand All @@ -151,10 +152,10 @@ mod tests {
fn add_labels() {
let (mut world, mut resources, mut schedule) = setup();
let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

world.get_mut::<Labels>(e1).unwrap().insert("shalau");
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[e1], "holy");
Expand All @@ -166,10 +167,10 @@ mod tests {
fn remove_labels() {
let (mut world, mut resources, mut schedule) = setup();
let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

world.get_mut::<Labels>(e1).unwrap().remove("holy");
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[], "holy");
Expand All @@ -181,10 +182,10 @@ mod tests {
fn removes_despawned_entity() {
let (mut world, mut resources, mut schedule) = setup();
let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

world.despawn(e1).unwrap();
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[], "holy");
Expand All @@ -196,10 +197,10 @@ mod tests {
fn removes_labels_when_component_removed() {
let (mut world, mut resources, mut schedule) = setup();
let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

world.remove_one::<Labels>(e1).unwrap();
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[], "holy");
Expand All @@ -211,10 +212,10 @@ mod tests {
fn adds_another_spawned_entity() {
let (mut world, mut resources, mut schedule) = setup();
let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let e2 = world.spawn((holy_shamoni(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[e1, e2], "holy");
Expand All @@ -227,13 +228,13 @@ mod tests {
fn removes_despawned_entity_but_leaves_other() {
let (mut world, mut resources, mut schedule) = setup();
let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let e2 = world.spawn((holy_shamoni(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

world.despawn(e1).unwrap();
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[e2], "holy");
Expand Down
22 changes: 14 additions & 8 deletions crates/bevy_core/src/time/fixed_timestep.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::Time;
use bevy_ecs::{ArchetypeComponent, ShouldRun, System, SystemId, ThreadLocalExecution, TypeAccess};
use bevy_ecs::{ArchetypeComponent, ShouldRun, System, SystemId, TypeAccess};
use bevy_utils::HashMap;
use std::{any::TypeId, borrow::Cow};

Expand Down Expand Up @@ -47,8 +47,9 @@ pub struct FixedTimestep {
looping: bool,
system_id: SystemId,
label: Option<String>, // TODO: consider making this a TypedLabel
resource_access: TypeAccess<TypeId>,
archetype_access: TypeAccess<ArchetypeComponent>,
component_access: TypeAccess<TypeId>,
resource_access: TypeAccess<TypeId>,
}

impl Default for FixedTimestep {
Expand All @@ -59,8 +60,9 @@ impl Default for FixedTimestep {
accumulator: 0.0,
looping: false,
label: None,
resource_access: Default::default(),
component_access: Default::default(),
archetype_access: Default::default(),
resource_access: Default::default(),
}
}
}
Expand Down Expand Up @@ -93,7 +95,7 @@ impl FixedTimestep {
if self.accumulator >= self.step {
self.accumulator -= self.step;
self.looping = true;
ShouldRun::YesAndLoop
ShouldRun::YesAndCheckAgain
} else {
self.looping = false;
ShouldRun::No
Expand All @@ -113,18 +115,22 @@ impl System for FixedTimestep {
self.system_id
}

fn update(&mut self, _world: &bevy_ecs::World) {}
fn update_access(&mut self, _world: &bevy_ecs::World) {}

fn archetype_component_access(&self) -> &TypeAccess<ArchetypeComponent> {
&self.archetype_access
}

fn component_access(&self) -> &TypeAccess<TypeId> {
&self.component_access
}

fn resource_access(&self) -> &TypeAccess<TypeId> {
&self.resource_access
}

fn thread_local_execution(&self) -> ThreadLocalExecution {
ThreadLocalExecution::Immediate
fn is_non_send(&self) -> bool {
false
}

unsafe fn run_unsafe(
Expand All @@ -145,7 +151,7 @@ impl System for FixedTimestep {
Some(result)
}

fn run_thread_local(
fn apply_buffers(
&mut self,
_world: &mut bevy_ecs::World,
_resources: &mut bevy_ecs::Resources,
Expand Down
Loading