Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
env:
CARGO_TERM_COLOR: always
RUST_CACHE_KEY: rust-cache-20240701
CARGO_PROFILE_DEV_DEBUG: none

jobs:
check-fmt:
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["bevy_rapier2d", "bevy_rapier3d"]
members = ["bevy_rapier2d", "bevy_rapier3d", "custom_benches"]
resolver = "2"

[profile.dev]
Expand Down
9 changes: 9 additions & 0 deletions benches_common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "benches_common"
version = "0.1.0"
edition = "2021"

[dependencies]
bevy = { version = "0.14.0-rc.3", default-features = false }
bevy_rapier3d = { path = "../bevy_rapier3d", default-features = false }
divan = "0.1"
63 changes: 63 additions & 0 deletions benches_common/src/lib.rs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of benches_common be its own create, it should just be a subdirectory in the bevy_rapier3d/benches folder.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed the same hierarchy of avian : https://github.com/Jondolf/avian/tree/main/crates ; I'd have preferred a way to enable feature on benches_common to support either 2d or 3d, but I didn't try that.

Either way, it's not too much code, and we can probably focus on 3d for now.

Copy link
Contributor Author

@ThierryBerger ThierryBerger Jul 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That actually allows me to share some logic with the custom benchmark.

I did add this logic in the custom benchmark, and call into this custom benchmark library from the "simpler" benches.

Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use bevy::{
app::PluginsState,
prelude::*,
render::{
settings::{RenderCreation, WgpuSettings},
RenderPlugin,
},
scene::ScenePlugin,
time::TimeUpdateStrategy,
};
use bevy_rapier3d::prelude::*;

pub fn default_app() -> App {
let mut app = App::new();

app.add_plugins((
WindowPlugin::default(),
MinimalPlugins,
AssetPlugin::default(),
ScenePlugin,
RenderPlugin {
render_creation: RenderCreation::Automatic(WgpuSettings {
backends: None,
..Default::default()
}),
..Default::default()
},
ImagePlugin::default(),
HierarchyPlugin,
TransformPlugin,
RapierPhysicsPlugin::<()>::default(),
));

// 60 physics
app.insert_resource(TimeUpdateStrategy::ManualDuration(
std::time::Duration::from_secs_f32(1f32 / 60f32),
));
app
}

pub fn wait_app_start(app: &mut App) {
while app.plugins_state() != PluginsState::Ready {
bevy::tasks::tick_global_task_pools_on_main_thread();
}

app.finish();
app.cleanup();
}

pub fn bench_app(bencher: divan::Bencher, steps: u32, setup: impl Fn(&mut App)) {
bencher
.with_inputs(|| {
let mut app = default_app();
setup(&mut app);
wait_app_start(&mut app);
app
})
.bench_local_values(|mut app| {
for _ in 0..steps {
app.update();
}
});
}
18 changes: 18 additions & 0 deletions bevy_rapier3d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,32 @@ log = "0.4"
serde = { version = "1", features = ["derive"], optional = true }

[dev-dependencies]
benches_common = { path = "../benches_common" }
bevy = { version = "0.14.0-rc.3", default-features = false, features = [
"x11",
"tonemapping_luts",
"bevy_state",
] }
approx = "0.5.1"
glam = { version = "0.27", features = ["approx"] }
divan = "0.1"

[dev-dependencies.rapier3d]
features = ["profiler"]
version = "0.20"

[package.metadata.docs.rs]
# Enable all the features when building the docs on docs.rs
features = ["debug-render-3d", "serde-serialize"]

[[bench]]
name = "cubes"
harness = false

[[bench]]
name = "many_pyramids3"
harness = false

[[bench]]
name = "many_pyramids3_custom"
harness = false
43 changes: 43 additions & 0 deletions bevy_rapier3d/benches/cubes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//! Translated from avian benchmark.

use benches_common::bench_app;
use bevy::prelude::*;
use bevy_rapier3d::math::*;
use bevy_rapier3d::prelude::*;

fn setup_cubes(app: &mut App, size: u32) {
app.add_systems(Startup, move |mut commands: Commands| {
commands.spawn((
RigidBody::Fixed,
Transform::from_translation(-2.0 * Vect::Z),
Collider::cuboid(100.0, 1.0, 100.0),
));
for x in 0..size {
for z in 0..size {
commands.spawn((
RigidBody::Dynamic,
Transform::from_translation(Vec3::new(x as f32, 2.0, z as f32)),
Collider::cuboid(1.0, 1.0, 1.0),
));
}
}
});
}

#[divan::bench]
fn cubes_3x3_30_steps(bencher: divan::Bencher) {
bench_app(bencher, 30, |app| setup_cubes(app, 3))
}
#[divan::bench]
fn cubes_5x5_30_steps(bencher: divan::Bencher) {
bench_app(bencher, 30, |app| setup_cubes(app, 5))
}
#[divan::bench]
fn cubes_10x10__30_steps(bencher: divan::Bencher) {
bench_app(bencher, 30, |app| setup_cubes(app, 10))
}

fn main() {
// Run registered benchmarks.
divan::main();
}
86 changes: 86 additions & 0 deletions bevy_rapier3d/benches/many_pyramids3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//! Translated from rapier benchmark.
use benches_common::bench_app;
use bevy::prelude::*;
use bevy_rapier3d::math::*;
use bevy_rapier3d::prelude::*;

pub fn create_pyramid(commands: &mut Commands, offset: Vect, stack_height: usize, rad: f32) {
let shift = rad * 2.0;

for i in 0usize..stack_height {
for j in i..stack_height {
let fj = j as f32;
let fi = i as f32;
let x = (fi * shift / 2.0) + (fj - fi) * shift;
let y = fi * shift;

// Build the rigid body.
commands.spawn((
RigidBody::Dynamic,
Transform::from_translation(Vec3::new(x, y, 0.0) + offset),
Collider::cuboid(1.0, 1.0, 1.0),
));
}
}
}

pub fn setup_cubes(app: &mut App, pyramid_count: usize, stack_height: usize) {
app.add_systems(Startup, move |mut commands: Commands| {
let rad = 0.5;
let spacing = 4.0;

/*
* Ground
*/
let ground_size = 50.0;
let ground_height = 0.1;

commands.spawn((
RigidBody::Fixed,
Transform::from_translation(Vect::new(0.0, -ground_height, 0.0)),
Collider::cuboid(
ground_size,
ground_height,
pyramid_count as f32 * spacing / 2.0 + ground_size,
),
));

/*
* Create the cubes
*/
for pyramid_index in 0..pyramid_count {
let bottomy = rad;
create_pyramid(
&mut commands,
Vect::new(
0.0,
bottomy,
(pyramid_index as f32 - pyramid_count as f32 / 2.0) * spacing,
),
stack_height,
rad,
);
}
});
}

#[divan::bench(sample_count = 5, sample_size = 5)]
fn pyramid_1_with_height_2(bencher: divan::Bencher) {
bench_app(bencher, 1000, |app| setup_cubes(app, 1, 2));
}

#[divan::bench(sample_count = 2, sample_size = 2)]
fn pyramid_1_with_height_20(bencher: divan::Bencher) {
bench_app(bencher, 100, |app| setup_cubes(app, 1, 20));
}

#[divan::bench(sample_count = 1, sample_size = 1)]
fn pyramid_2_with_height_20(bencher: divan::Bencher) {
bench_app(bencher, 100, |app| setup_cubes(app, 2, 20));
}

fn main() {
// Run registered benchmarks.
divan::main();
}
114 changes: 114 additions & 0 deletions bevy_rapier3d/benches/many_pyramids3_custom.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//! Translated from rapier benchmark.

use benches_common::default_app;
use benches_common::wait_app_start;
use bevy::prelude::*;
use bevy_rapier3d::dynamics::RigidBody;
use bevy_rapier3d::geometry::Collider;
use bevy_rapier3d::math::Vect;
use bevy_rapier3d::plugin::RapierContext;
use bevy_rapier3d::plugin::SimulationToRenderTime;

pub fn create_pyramid(commands: &mut Commands, offset: Vect, stack_height: usize, rad: f32) {
let shift = rad * 2.0;

for i in 0usize..stack_height {
for j in i..stack_height {
let fj = j as f32;
let fi = i as f32;
let x = (fi * shift / 2.0) + (fj - fi) * shift;
let y = fi * shift;

// Build the rigid body.
commands.spawn((
RigidBody::Dynamic,
Transform::from_translation(Vec3::new(x, y, 0.0) + offset),
Collider::cuboid(1.0, 1.0, 1.0),
));
}
}
}

pub fn setup_cubes(app: &mut App, pyramid_count: usize, stack_height: usize) {
app.add_systems(Startup, move |mut commands: Commands| {
let rad = 0.5;
let spacing = 4.0;

/*
* Ground
*/
let ground_size = 50.0;
let ground_height = 0.1;

commands.spawn((
RigidBody::Fixed,
Transform::from_translation(Vect::new(0.0, -ground_height, 0.0)),
Collider::cuboid(
ground_size,
ground_height,
pyramid_count as f32 * spacing / 2.0 + ground_size,
),
));

/*
* Create the cubes
*/
for pyramid_index in 0..pyramid_count {
let bottomy = rad;
create_pyramid(
&mut commands,
Vect::new(
0.0,
bottomy,
(pyramid_index as f32 - pyramid_count as f32 / 2.0) * spacing,
),
stack_height,
rad,
);
}
});
}

pub fn custom_bencher(steps: usize, setup: impl Fn(&mut App)) {
let mut app = default_app();
setup(&mut app);
wait_app_start(&mut app);

let mut timer_total = rapier3d::counters::Timer::new();
let mut timer_full_update = rapier3d::counters::Timer::new();
let mut bevy_overheads = vec![];
let mut rapier_step_times = vec![];
let mut total_update_times = vec![];
timer_total.start();
for _ in 0..steps {
timer_full_update.start();
app.update();
timer_full_update.pause();
let elapsed_time = timer_full_update.time() as f32;
let rc = app.world().resource::<RapierContext>();
let bevy_overhead = app.world().resource::<SimulationToRenderTime>();
bevy_overheads.push(bevy_overhead.diff);
rapier_step_times.push(rc.pipeline.counters.step_time.time() as f32);
total_update_times.push(elapsed_time);
}
timer_total.pause();
let average = bevy_overheads.iter().sum::<f32>() / bevy_overheads.len() as f32;
println!("average bevy overhead: {}", average);
let average = total_update_times.iter().sum::<f32>() / total_update_times.len() as f32;
println!("average total time: {}", average);
let average = rapier_step_times.iter().sum::<f32>() / rapier_step_times.len() as f32;
println!("average rapier step time: {}", average);
println!("total time: {}", timer_total.time());
}
fn pyramid_1_with_height_2() {
custom_bencher(1000, |app| setup_cubes(app, 1, 2));
}

fn pyramid_2_with_height_20() {
custom_bencher(100, |app| setup_cubes(app, 3, 20));
}

fn main() {
pyramid_1_with_height_2();
pyramid_2_with_height_20();
}
Loading