use criterion::{black_box, criterion_group, criterion_main, Criterion};
use rand::rngs::StdRng;
use rand::SeedableRng;
use rustsim_core::interaction::{PositionedAgent, SpaceInteraction};
use rustsim_core::prelude::*;
#[derive(Debug, Default, Clone, Copy)]
struct NothingSpace;
impl Space for NothingSpace {}
impl<A> SpaceInteraction<A> for NothingSpace
where
A: PositionedAgent<Position = ()>,
{
type Error = std::convert::Infallible;
fn random_position<R: rand::RngCore>(&self, _rng: &mut R) -> A::Position {}
fn add_agent(&mut self, _agent: &A) -> Result<(), Self::Error> {
Ok(())
}
fn remove_agent(&mut self, _agent: &A) -> Result<(), Self::Error> {
Ok(())
}
fn nearby_ids(&self, _position: &A::Position, _radius: usize) -> Vec<AgentId> {
Vec::new()
}
}
#[derive(Debug, Clone)]
struct Particle {
id: AgentId,
x: f32,
vx: f32,
}
impl Agent for Particle {
fn id(&self) -> AgentId {
self.id
}
}
type ParticleModel =
StandardModel<NothingSpace, Particle, HashMapStore<Particle>, (), StdRng, Fastest>;
fn particle_step(
agent: &mut Particle,
_ctx: &mut StepContext<'_, NothingSpace, Particle, (), StdRng, Fastest>,
) {
agent.x += agent.vx;
}
fn make_model(n: u64) -> ParticleModel {
let mut store = HashMapStore::new();
for i in 1..=n {
store.insert(Particle {
id: i,
x: 0.0,
vx: 0.001,
});
}
ParticleModel::new(
store,
NothingSpace,
Fastest::new(),
(),
StdRng::seed_from_u64(42),
Some(Box::new(particle_step)),
None,
true,
)
}
fn bench_step_1k(c: &mut Criterion) {
let mut model = make_model(1_000);
c.bench_function("step 1k agents", |b| {
b.iter(|| {
model.step();
black_box(model.time());
});
});
}
fn bench_step_100k(c: &mut Criterion) {
let mut model = make_model(100_000);
c.bench_function("step 100k agents", |b| {
b.iter(|| {
model.step();
black_box(model.time());
});
});
}
fn bench_step_with_removal(c: &mut Criterion) {
c.bench_function("step 10k with 50% deferred removal", |b| {
b.iter_batched(
|| {
fn remove_evens(
agent: &mut Particle,
ctx: &mut StepContext<'_, NothingSpace, Particle, (), StdRng, Fastest>,
) {
if agent.id.is_multiple_of(2) {
ctx.defer_remove_agent(agent.id());
} else {
agent.x += agent.vx;
}
}
let mut store = HashMapStore::new();
for i in 1..=10_000u64 {
store.insert(Particle {
id: i,
x: 0.0,
vx: 0.001,
});
}
ParticleModel::new(
store,
NothingSpace,
Fastest::new(),
(),
StdRng::seed_from_u64(42),
Some(Box::new(remove_evens)),
None,
true,
)
},
|mut model| {
model.step();
black_box(model.agents_len());
},
criterion::BatchSize::SmallInput,
);
});
}
criterion_group!(
benches,
bench_step_1k,
bench_step_100k,
bench_step_with_removal
);
criterion_main!(benches);