mirror of
https://github.com/bevyengine/bevy
synced 2024-12-28 22:13:08 +00:00
ae9775c83b
# Objective Improve performance scalability when adding new event types to a Bevy app. Currently, just using Bevy in the default configuration, all apps spend upwards of 100+us in the `First` schedule, every app tick, evaluating if it should update events or not, even if events are not being used for that particular frame, and this scales with the number of Events registered in the app. ## Solution As `Events::update` is guaranteed `O(1)` by just checking if a resource's value, swapping two Vecs, and then clearing one of them, the actual cost of running `event_update_system` is *very* cheap. The overhead of doing system dependency injection, task scheduling ,and the multithreaded executor outweighs the cost of running the system by a large margin. Create an `EventRegistry` resource that keeps a number of function pointers that update each event. Replace the per-event type `event_update_system` with a singular exclusive system uses the `EventRegistry` to update all events instead. Update `SubApp::add_event` to use `EventRegistry` instead. ## Performance This speeds reduces the cost of the `First` schedule in both many_foxes and many_cubes by over 80%. Note this is with system spans on. The majority of this is now context-switching costs from launching `time_system`, which should be mostly eliminated with #12869. ![image](https://github.com/bevyengine/bevy/assets/3137680/037624be-21a2-4dc2-a42f-9d0bfa3e9b4a) The actual `event_update_system` is usually *very* short, using only a few microseconds on average. ![image](https://github.com/bevyengine/bevy/assets/3137680/01ff1689-3595-49b6-8f09-5c44bcf903e8) --- ## Changelog TODO ## Migration Guide TODO --------- Co-authored-by: Josh Matthews <josh@joshmatthews.net> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
64 lines
2.2 KiB
Rust
64 lines
2.2 KiB
Rust
//! In this example a system sends a custom event with a 50/50 chance during any frame.
|
|
//! If an event was send, it will be printed by the console in a receiving system.
|
|
|
|
use bevy_ecs::{event::EventRegistry, prelude::*};
|
|
|
|
fn main() {
|
|
// Create a new empty world and add the event as a resource
|
|
let mut world = World::new();
|
|
// The event registry is stored as a resource, and allows us to quickly update all events at once.
|
|
// This call adds both the registry resource and the events resource into the world.
|
|
EventRegistry::register_event::<MyEvent>(&mut world);
|
|
|
|
// Create a schedule to store our systems
|
|
let mut schedule = Schedule::default();
|
|
|
|
// Events need to be updated in every frame in order to clear our buffers.
|
|
// This update should happen before we use the events.
|
|
// Here, we use system sets to control the ordering.
|
|
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub struct FlushEvents;
|
|
|
|
schedule.add_systems(bevy_ecs::event::event_update_system.in_set(FlushEvents));
|
|
|
|
// Add systems sending and receiving events after the events are flushed.
|
|
schedule.add_systems((
|
|
sending_system.after(FlushEvents),
|
|
receiving_system.after(sending_system),
|
|
));
|
|
|
|
// Simulate 10 frames of our world
|
|
for iteration in 1..=10 {
|
|
println!("Simulating frame {iteration}/10");
|
|
schedule.run(&mut world);
|
|
}
|
|
}
|
|
|
|
// This is our event that we will send and receive in systems
|
|
#[derive(Event)]
|
|
struct MyEvent {
|
|
pub message: String,
|
|
pub random_value: f32,
|
|
}
|
|
|
|
// In every frame we will send an event with a 50/50 chance
|
|
fn sending_system(mut event_writer: EventWriter<MyEvent>) {
|
|
let random_value: f32 = rand::random();
|
|
if random_value > 0.5 {
|
|
event_writer.send(MyEvent {
|
|
message: "A random event with value > 0.5".to_string(),
|
|
random_value,
|
|
});
|
|
}
|
|
}
|
|
|
|
// This system listens for events of the type MyEvent
|
|
// If an event is received it will be printed to the console
|
|
fn receiving_system(mut event_reader: EventReader<MyEvent>) {
|
|
for my_event in event_reader.read() {
|
|
println!(
|
|
" Received message {:?}, with random value of {}",
|
|
my_event.message, my_event.random_value
|
|
);
|
|
}
|
|
}
|