Skip to content

Commit

Permalink
Merge pull request #115 from TomGillen/experimental
Browse files Browse the repository at this point in the history
Rewrite of the legion crate.
  • Loading branch information
TomGillen authored Jul 27, 2020
2 parents 80a3d15 + 94d2293 commit 91266c8
Show file tree
Hide file tree
Showing 89 changed files with 12,235 additions and 15,246 deletions.
6 changes: 2 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,13 @@ jobs:
strategy:
matrix:
features:
- --manifest-path=example/Cargo.toml
- --all-features --release
- --no-default-features --release
- --all-features
- --no-default-features
- --no-default-features --features par-iter
- --no-default-features --features par-schedule
- --no-default-features --features metrics
- --no-default-features --features ffi
- --no-default-features --features extended-tuple-impls
- --no-default-features --features serialize
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
Expand Down
49 changes: 24 additions & 25 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "legion"
version = "0.2.4"
version = "0.3.0"
description = "High performance entity component system (ECS) library"
authors = ["Thomas Gillen <[email protected]>"]
repository = "https://github.com/TomGillen/legion"
Expand All @@ -14,35 +14,34 @@ edition = "2018"
travis-ci = { repository = "TomGillen/legion", branch = "master" }

[features]
default = ["par-iter", "par-schedule", "ffi"]
par-iter = ["legion-core/par-iter", "legion-systems/par-iter"]
par-schedule = ["legion-systems/par-schedule"]
log = ["tracing/log", "tracing/log-always"]
ffi = ["legion-core/ffi"]
serialize = ["legion-core/serialize"]
metrics = ["legion-core/metrics"]

[workspace]
members = [
"legion_core",
"legion_systems",
]
default = ["par-iter", "serialize", "crossbeam-events"]
par-iter = ["rayon"]
extended-tuple-impls = []
serialize = ["serde", "erased-serde", "uuid/serde"]
crossbeam-events = ["crossbeam-channel"]

[dependencies]
legion-core = { path = "legion_core", version = "0.2.4", default-features = false }
legion-systems = { path = "legion_systems", version = "0.2.4", default-features = false }
smallvec = "1.4"
itertools = "0.9"
downcast-rs = "1.2"
derivative = "2.1"
paste = "0.1"
parking_lot = "0.11"
bit-set = "0.5"
tracing = "0.1"
thiserror = "1.0"
uuid = { version = "0.8", features = ["v4"] }
rayon = { version = "1.3", optional = true }
serde = { version = "1", features = ["derive"], optional = true }
erased-serde = { version = "0.3", optional = true }
crossbeam-channel = {version ="0.4", optional = true}

[dev-dependencies]
serde_json = "1.0"
bincode = "1.3"
tracing-subscriber = "0.2"
criterion = "0.3"
cgmath = "0.17"
tracing-subscriber = "0.2"
erased-serde = "0.3"
serde = { version = "1", features = ["derive"]}
uuid = { version = "0.8", features = ["v4"] }
tracing = "0.1"
itertools = "0.8"
rayon = "1.2"
crossbeam-channel = "0.4.0"

[[bench]]
name = "benchmarks"
Expand All @@ -58,4 +57,4 @@ harness = false

[[bench]]
name = "insertion"
harness = false
harness = false
64 changes: 25 additions & 39 deletions benches/benchmarks.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use criterion::*;
use itertools::*;

use legion::prelude::*;
use legion::*;

#[derive(Copy, Clone, Debug, PartialEq)]
struct A(f32);
Expand Down Expand Up @@ -42,7 +42,7 @@ fn create_entities(
.chunks(num_components);

for initializers in (&components).into_iter().take(count) {
let entity = world.insert((), Some((A(0.0),)))[0];
let entity = world.push((A(0.0),));
for i in initializers {
let init = variants.get_mut(i).unwrap();
init(entity, world);
Expand All @@ -54,16 +54,12 @@ fn add_background_entities(world: &mut World, count: usize) {
create_entities(
world,
&mut [
Box::new(|e, w| w.add_component(e, A(0.0)).unwrap()),
Box::new(|e, w| w.add_component(e, B(0.0)).unwrap()),
Box::new(|e, w| w.add_component(e, C(0.0)).unwrap()),
Box::new(|e, w| w.add_tag(e, Tag(0.0)).unwrap()),
Box::new(|e, w| w.add_component(e, D(0.0)).unwrap()),
Box::new(|e, w| w.add_tag(e, Tag(1.0)).unwrap()),
Box::new(|e, w| w.add_component(e, E(0.0)).unwrap()),
Box::new(|e, w| w.add_tag(e, Tag(2.0)).unwrap()),
Box::new(|e, w| w.add_component(e, F(0.0)).unwrap()),
Box::new(|e, w| w.add_tag(e, Tag(3.0)).unwrap()),
Box::new(|e, w| w.entry(e).unwrap().add_component(B(0.0))),
Box::new(|e, w| w.entry(e).unwrap().add_component(A(0.0))),
Box::new(|e, w| w.entry(e).unwrap().add_component(C(0.0))),
Box::new(|e, w| w.entry(e).unwrap().add_component(D(0.0))),
Box::new(|e, w| w.entry(e).unwrap().add_component(E(0.0))),
Box::new(|e, w| w.entry(e).unwrap().add_component(F(0.0))),
],
5,
count,
Expand All @@ -74,7 +70,7 @@ fn setup(n: usize) -> World {
let universe = Universe::new();
let mut world = universe.create_world();

world.insert((), (0..n).map(|_| (Position(0.), Rotation(0.))));
world.extend((0..n).map(|_| (Position(0.), Rotation(0.))));

world
}
Expand All @@ -85,12 +81,10 @@ fn bench_create_delete(c: &mut Criterion) {
|b, count| {
let mut world = setup(0);
b.iter(|| {
let entities = world
.insert((), (0..*count).map(|_| (Position(0.),)))
.to_vec();
let entities = world.extend((0..*count).map(|_| (Position(0.),))).to_vec();

for e in entities {
world.delete(e);
world.remove(e);
}
})
},
Expand All @@ -103,10 +97,10 @@ fn bench_iter_simple(c: &mut Criterion) {
let mut world = setup(2000);
add_background_entities(&mut world, 10000);

let query = <(Read<Position>, Write<Rotation>)>::query();
let mut query = <(Read<Position>, Write<Rotation>)>::query();

b.iter(|| {
for (pos, mut rot) in query.iter_mut(&mut world) {
for (pos, rot) in query.iter_mut(&mut world) {
rot.0 = pos.0;
}
});
Expand All @@ -118,18 +112,14 @@ fn bench_iter_complex(c: &mut Criterion) {
let mut world = setup(0);
add_background_entities(&mut world, 10000);

for i in 0..200 {
world.insert(
(Tag(i as f32),),
(0..2000).map(|_| (Position(0.), Rotation(0.))),
);
for _ in 0..200 {
world.extend((0..2000).map(|_| (Position(0.), Rotation(0.))));
}

let query = <(Read<Position>, Write<Rotation>)>::query()
.filter(!component::<A>() & tag_value(&Tag(2.0)));
let mut query = <(Read<Position>, Write<Rotation>)>::query().filter(!component::<A>());

b.iter(|| {
for (pos, mut rot) in query.iter_mut(&mut world) {
for (pos, rot) in query.iter_mut(&mut world) {
rot.0 = pos.0;
}
});
Expand All @@ -141,12 +131,12 @@ fn bench_iter_chunks_simple(c: &mut Criterion) {
let mut world = setup(10000);
add_background_entities(&mut world, 10000);

let query = <(Write<Position>, Read<Rotation>)>::query();
let mut query = <(Write<Position>, Read<Rotation>)>::query();

b.iter(|| {
for c in query.iter_chunks_mut(&mut world) {
for mut c in query.iter_chunks_mut(&mut world) {
unsafe {
c.components_mut::<Position>()
c.component_slice_mut::<Position>()
.unwrap()
.get_unchecked_mut(0)
.0 = 0.0
Expand All @@ -161,20 +151,16 @@ fn bench_iter_chunks_complex(c: &mut Criterion) {
let mut world = setup(0);
add_background_entities(&mut world, 10000);

for i in 0..200 {
world.insert(
(Tag(i as f32),),
(0..10000).map(|_| (Position(0.), Rotation(0.))),
);
for _ in 0..200 {
world.extend((0..10000).map(|_| (Position(0.), Rotation(0.))));
}

let query = <(Write<Position>, Read<Rotation>)>::query()
.filter(!component::<A>() & tag_value(&Tag(2.0)));
let mut query = <(Write<Position>, Read<Rotation>)>::query().filter(!component::<A>());

b.iter(|| {
for c in query.iter_chunks_mut(&mut world) {
for mut c in query.iter_chunks_mut(&mut world) {
unsafe {
c.components_mut::<Position>()
c.component_slice_mut::<Position>()
.unwrap()
.get_unchecked_mut(0)
.0 = 0.0
Expand Down
8 changes: 4 additions & 4 deletions benches/insertion.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use criterion::*;

use legion::prelude::*;
use legion::*;

fn bench_insert_zero_baseline(c: &mut Criterion) {
c.bench_function("insert_zero_baseline", |b| {
Expand All @@ -21,7 +21,7 @@ fn bench_insert_one_baseline(c: &mut Criterion) {
let components: Vec<isize> = (0..10000).map(|i| i).collect();
criterion::black_box(components);

world.insert((), vec![(1usize,)]);
world.extend(vec![(1usize,)]);
});
});
}
Expand All @@ -34,7 +34,7 @@ fn bench_insert_unbatched(c: &mut Criterion) {
let components: Vec<isize> = (0..10000).map(|i| i).collect();

for component in components {
world.insert((), vec![(component,)]);
world.extend(vec![(component,)]);
}
});
});
Expand All @@ -51,7 +51,7 @@ fn bench_insert_batched(c: &mut Criterion) {
let mut world = universe.create_world();
let components: Vec<(isize,)> = (0..*n).map(|i| (i,)).collect();

world.insert((), components);
world.extend(components);
});
},
(1..11).map(|i| i * 1000),
Expand Down
41 changes: 28 additions & 13 deletions benches/parallel_query.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use criterion::*;

use itertools::*;
use legion::prelude::*;
use legion::*;
use rayon::join;

#[derive(Copy, Clone, Debug, PartialEq)]
Expand Down Expand Up @@ -53,8 +53,7 @@ fn setup(data: &[Variants]) -> World {

for (i, group) in &data.iter().group_by(|x| index(**x)) {
match i {
0 => world.insert(
(),
0 => world.extend(
group
.map(|x| {
if let Variants::AB(a, b) = x {
Expand All @@ -65,8 +64,7 @@ fn setup(data: &[Variants]) -> World {
})
.collect::<Vec<_>>(),
),
_ => world.insert(
(),
_ => world.extend(
group
.map(|x| {
if let Variants::AC(a, c) = x {
Expand Down Expand Up @@ -108,40 +106,57 @@ fn ideal(ab: &mut Vec<(A, B)>, ac: &mut Vec<(A, C)>) {
}

fn sequential(world: &mut World) {
for (mut b, a) in <(Write<B>, Read<A>)>::query().iter_mut(world) {
for (b, a) in <(Write<B>, Read<A>)>::query().iter_mut(world) {
b.0 = a.0;
}

for (mut c, a) in <(Write<C>, Read<A>)>::query().iter_mut(world) {
for (c, a) in <(Write<C>, Read<A>)>::query().iter_mut(world) {
c.0 = a.0;
}
}

fn parallel(world: &mut World) {
join(
|| unsafe {
for (mut b, a) in <(Write<B>, Read<A>)>::query().iter_unchecked(world) {
for (b, a) in <(Write<B>, Read<A>)>::query().iter_unchecked(world) {
b.0 = a.0;
}
},
|| unsafe {
for (mut c, a) in <(Write<C>, Read<A>)>::query().iter_unchecked(world) {
for (c, a) in <(Write<C>, Read<A>)>::query().iter_unchecked(world) {
c.0 = a.0;
}
},
);
}

fn par_for_each_mut(world: &mut World) {
// join(
// || unsafe {
// <(Write<B>, Read<A>)>::query().par_for_each_unchecked(world, |(b, a)| {
// b.0 = a.0;
// });
// },
// || unsafe {
// <(Write<C>, Read<A>)>::query().par_for_each_unchecked(world, |(c, a)| {
// c.0 = a.0;
// });
// },
// );
use rayon::iter::{IntoParallelIterator, ParallelIterator};
join(
|| unsafe {
<(Write<B>, Read<A>)>::query().par_for_each_unchecked(world, |(mut b, a)| {
b.0 = a.0;
<(Write<B>, Read<A>)>::query().for_each_chunk_unchecked(world, |chunk| {
chunk.into_par_iter().for_each(|(b, a)| {
b.0 = a.0;
})
});
},
|| unsafe {
<(Write<C>, Read<A>)>::query().par_for_each_unchecked(world, |(mut c, a)| {
c.0 = a.0;
<(Write<C>, Read<A>)>::query().for_each_chunk_unchecked(world, |chunk| {
chunk.into_par_iter().for_each(|(c, a)| {
c.0 = a.0;
})
});
},
);
Expand Down
6 changes: 3 additions & 3 deletions benches/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use criterion::*;

use cgmath::prelude::*;
use cgmath::{vec3, Matrix4, Quaternion, Vector3};
use legion::prelude::*;
use legion::*;
use rayon::join;

#[derive(Copy, Clone, Debug, PartialEq)]
Expand Down Expand Up @@ -36,7 +36,7 @@ fn setup(data: Vec<(Position, Orientation, Scale, Transform)>) -> World {
let universe = Universe::new();
let mut world = universe.create_world();

world.insert((), data);
world.extend(data);

world
}
Expand Down Expand Up @@ -85,7 +85,7 @@ fn par_for_each_mut(world: &mut World) {

fn bench_transform(c: &mut Criterion) {
c.bench(
"update transform (experimental)",
"update transform",
ParameterizedBenchmark::new(
"ideal sequential",
|b, n| {
Expand Down
6 changes: 0 additions & 6 deletions example/Cargo.toml

This file was deleted.

Loading

0 comments on commit 91266c8

Please sign in to comment.