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

Experimental refactor in legion_experiment crate #115

Merged
merged 48 commits into from
Jul 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
8c2a0a4
Initial work on legion_experiment crate
TomGillen Mar 8, 2020
1c16fb7
Packed archetypes experiment
TomGillen Apr 28, 2020
240340f
Implement component add and remove.
TomGillen May 5, 2020
cb4023f
Improve insert performance
TomGillen May 5, 2020
e9782c0
Implemented parallel iterators
TomGillen May 10, 2020
fdade3a
"extended-tuple-impls" feature (off by default) to improve compile times
TomGillen May 10, 2020
9b5ba37
Early serialization work
TomGillen May 30, 2020
6bde1ab
Implemented subworlds
TomGillen Jun 15, 2020
7af7f08
System query sets
TomGillen Jun 15, 2020
72f19d1
Ported systems to packed archetypes
TomGillen Jun 22, 2020
7dc57a4
Implemented world merging
TomGillen Jun 24, 2020
8034746
Implement merge_from_single and entity ID remapping
TomGillen Jun 27, 2020
60c2f02
Implemented serialisation for packed archetypes
TomGillen Jun 28, 2020
31891df
Basic world deserialization
TomGillen Jul 1, 2020
0dd3d62
Support bincode (de)serialization
TomGillen Jul 2, 2020
d578616
Implement human readable serialization layout
TomGillen Jul 3, 2020
bb636b1
Implemented event subscribers
TomGillen Jul 3, 2020
fb64738
Re-export most common types at crate root
TomGillen Jul 3, 2020
f8bcc66
Replace core crate with experimental crate
TomGillen Jul 4, 2020
e980305
Remove usafe of UnsafeCell in Components
TomGillen Jul 4, 2020
f5ccf50
Use flatten in par_for_each
TomGillen Jul 4, 2020
73f7f1d
Separate world and query lifetime in query iterators
TomGillen Jul 4, 2020
344b1c9
Documented types in world module
TomGillen Jul 4, 2020
f64dee5
Merge branch 'master' into experimental
TomGillen Jul 5, 2020
aade369
Update crate level documentation and readme
TomGillen Jul 5, 2020
4f2a521
Ran cargo fmt
TomGillen Jul 5, 2020
1f2056f
Minor clippy warning
TomGillen Jul 5, 2020
ab97e14
Documented most public types
TomGillen Jul 7, 2020
046a1b6
Moved modules into internal module
TomGillen Jul 7, 2020
ef049e4
Separate internal and public api modules
TomGillen Jul 7, 2020
334580e
Fix clippy issues
TomGillen Jul 7, 2020
80942d5
Update CI tests feature flags
TomGillen Jul 7, 2020
e35f545
Added missing derives fror ComponentMeta
TomGillen Jul 11, 2020
f89fe69
Implemented canonical entity names
TomGillen Jul 11, 2020
9cdf1f6
Export deserializer wrappers
TomGillen Jul 11, 2020
0f64771
rustfmt
TomGillen Jul 11, 2020
3f7c02a
Fix clippy warnings
TomGillen Jul 11, 2020
14b8036
Serialize entity names as a UUID
TomGillen Jul 11, 2020
1de05cd
Skip unknown component deserialization with IgnoredAny
TomGillen Jul 12, 2020
4aee7e1
Avoid component vec allocation when deserializing packed entities
TomGillen Jul 12, 2020
f74182d
More CI specific clippy warnings
TomGillen Jul 12, 2020
e7c58e9
Separate clone_from and move_from, fix canon id semantics
TomGillen Jul 13, 2020
28d3706
Export canon types
TomGillen Jul 13, 2020
bf9af1b
Derive error types with thiserror
TomGillen Jul 13, 2020
89e4acf
Allow merger to assign entity IDs
TomGillen Jul 17, 2020
e1691f6
Rewrite `Entity` during clone
TomGillen Jul 17, 2020
e51831d
Allow mergers to configure entity id rewriting
TomGillen Jul 20, 2020
94d2293
Return `Result` from Entry::get_component and added into_component
TomGillen Jul 23, 2020
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
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