Skip to content
This repository has been archived by the owner on Nov 27, 2022. It is now read-only.

Commit

Permalink
Update hecs, add to serialization benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
Ralith committed Mar 28, 2021
1 parent b2d7289 commit d3f4c7f
Show file tree
Hide file tree
Showing 5 changed files with 307 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ serde = { version = "1.0", features = ["derive"] }
rayon = "1.3"
legion = "0.3"
bevy_ecs = "0.3"
hecs = "0.3"
hecs = { version = "0.5", features = ["column-serialize", "row-serialize"] }
shipyard = "0.4"
specs = {version = "0.16.1", features = ["serde"] }
specs-derive = "0.4.1"
Expand Down
8 changes: 8 additions & 0 deletions benches/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ fn bench_serialize_text(c: &mut Criterion) {
let mut bench = legion::serialize_text::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("hecs", |b| {
let mut bench = hecs::serialize_text::Benchmark::new();
b.iter(move || bench.run());
});
// group.bench_function("bevy", |b| {
// let mut bench = bevy::serialize_text::Benchmark::new();
// b.iter(move || bench.run());
Expand All @@ -183,6 +187,10 @@ fn bench_serialize_binary(c: &mut Criterion) {
let mut bench = legion::serialize_binary::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("hecs", |b| {
let mut bench = hecs::serialize_binary::Benchmark::new();
b.iter(move || bench.run());
});
// group.bench_function("bevy", |b| {
// let mut bench = bevy::serialize_text::Benchmark::new();
// b.iter(move || bench.run());
Expand Down
2 changes: 2 additions & 0 deletions src/hecs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ pub mod frag_iter;
pub mod heavy_compute;
pub mod simple_insert;
pub mod simple_iter;
pub mod serialize_binary;
pub mod serialize_text;
180 changes: 180 additions & 0 deletions src/hecs/serialize_binary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
use hecs::{serialize::column::*, *};
use serde::{de::SeqAccess, ser::SerializeTuple, Deserialize, Serialize};

#[derive(Default, Copy, Clone, Serialize, Deserialize)]
struct Transform([f32; 16]);

#[derive(Default, Copy, Clone, Serialize, Deserialize)]
struct Position {
x: f32,
y: f32,
z: f32,
}

#[derive(Default, Copy, Clone, Serialize, Deserialize)]
struct Rotation {
x: f32,
y: f32,
z: f32,
}

#[derive(Default, Copy, Clone, Serialize, Deserialize)]
struct Velocity {
x: f32,
y: f32,
z: f32,
}

struct SerContext;

#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
enum ComponentId {
Transform,
Position,
Rotation,
Velocity,
}

impl SerializeContext for SerContext {
fn component_count(&self, archetype: &Archetype) -> usize {
use std::any::TypeId;
archetype
.component_types()
.filter(|&x| {
x == TypeId::of::<Transform>()
|| x == TypeId::of::<Position>()
|| x == TypeId::of::<Rotation>()
|| x == TypeId::of::<Velocity>()
})
.count()
}

fn serialize_component_ids<S: SerializeTuple>(
&mut self,
archetype: &Archetype,
out: &mut S,
) -> Result<(), S::Error> {
if archetype.has::<Transform>() {
out.serialize_element(&ComponentId::Transform)?;
}
if archetype.has::<Position>() {
out.serialize_element(&ComponentId::Position)?;
}
if archetype.has::<Rotation>() {
out.serialize_element(&ComponentId::Rotation)?;
}
if archetype.has::<Velocity>() {
out.serialize_element(&ComponentId::Velocity)?;
}
Ok(())
}

fn serialize_components<S: SerializeTuple>(
&mut self,
archetype: &Archetype,
out: &mut S,
) -> Result<(), S::Error> {
try_serialize::<Transform, _>(archetype, out)?;
try_serialize::<Position, _>(archetype, out)?;
try_serialize::<Rotation, _>(archetype, out)?;
try_serialize::<Velocity, _>(archetype, out)?;
Ok(())
}
}

struct DeContext {
components: Vec<ComponentId>,
}

impl DeserializeContext for DeContext {
fn deserialize_component_ids<'de, A>(&mut self, mut seq: A) -> Result<ColumnBatchType, A::Error>
where
A: SeqAccess<'de>,
{
self.components.clear();
let mut batch = ColumnBatchType::new();
while let Some(id) = seq.next_element()? {
match id {
ComponentId::Transform => {
batch.add::<Transform>();
}
ComponentId::Position => {
batch.add::<Position>();
}
ComponentId::Rotation => {
batch.add::<Rotation>();
}
ComponentId::Velocity => {
batch.add::<Velocity>();
}
}
self.components.push(id);
}
Ok(batch)
}

fn deserialize_components<'de, A>(
&mut self,
entity_count: u32,
mut seq: A,
batch: &mut ColumnBatchBuilder,
) -> Result<(), A::Error>
where
A: SeqAccess<'de>,
{
for &component in &self.components {
match component {
ComponentId::Transform => {
deserialize_column::<Transform, _>(entity_count, &mut seq, batch)?;
}
ComponentId::Position => {
deserialize_column::<Position, _>(entity_count, &mut seq, batch)?;
}
ComponentId::Rotation => {
deserialize_column::<Rotation, _>(entity_count, &mut seq, batch)?;
}
ComponentId::Velocity => {
deserialize_column::<Velocity, _>(entity_count, &mut seq, batch)?;
}
}
}
Ok(())
}
}

pub struct Benchmark(World);

impl Benchmark {
pub fn new() -> Self {
let mut world = World::new();

world.spawn_batch((0..1000).map(|_| {
(
Transform::default(),
Position::default(),
Rotation::default(),
Velocity::default(),
)
}));

Self(world)
}

pub fn run(&mut self) {
let Self(world) = self;
let mut encoded = Vec::new();
serialize(
&world,
&mut SerContext,
&mut bincode::Serializer::new(&mut encoded, bincode::options()),
)
.unwrap();
deserialize(
&mut DeContext {
components: Vec::new(),
},
&mut bincode::Deserializer::from_slice(&encoded, bincode::options()),
)
.unwrap();
}
}
116 changes: 116 additions & 0 deletions src/hecs/serialize_text.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use hecs::{serialize::row::*, *};
use serde::{de::MapAccess, ser::SerializeMap, Deserialize, Serialize};

#[derive(Default, Copy, Clone, Serialize, Deserialize)]
struct Transform([f32; 16]);

#[derive(Default, Copy, Clone, Serialize, Deserialize)]
struct Position {
x: f32,
y: f32,
z: f32,
}

#[derive(Default, Copy, Clone, Serialize, Deserialize)]
struct Rotation {
x: f32,
y: f32,
z: f32,
}

#[derive(Default, Copy, Clone, Serialize, Deserialize)]
struct Velocity {
x: f32,
y: f32,
z: f32,
}

struct SerContext;

#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
enum ComponentId {
Transform,
Position,
Rotation,
Velocity,
}

impl SerializeContext for SerContext {
fn serialize_entity<S: SerializeMap>(
&mut self,
entity: EntityRef<'_>,
map: &mut S,
) -> Result<(), S::Error> {
try_serialize::<Transform, _, _>(&entity, &ComponentId::Transform, map)?;
try_serialize::<Position, _, _>(&entity, &ComponentId::Position, map)?;
try_serialize::<Rotation, _, _>(&entity, &ComponentId::Rotation, map)?;
try_serialize::<Velocity, _, _>(&entity, &ComponentId::Velocity, map)?;
Ok(())
}
}

struct DeContext;

impl DeserializeContext for DeContext {
fn deserialize_entity<'de, M>(
&mut self,
mut map: M,
entity: &mut EntityBuilder,
) -> Result<(), M::Error>
where
M: MapAccess<'de>,
{
while let Some(key) = map.next_key()? {
match key {
ComponentId::Transform => {
entity.add::<Transform>(map.next_value()?);
}
ComponentId::Position => {
entity.add::<Position>(map.next_value()?);
}
ComponentId::Rotation => {
entity.add::<Rotation>(map.next_value()?);
}
ComponentId::Velocity => {
entity.add::<Velocity>(map.next_value()?);
}
}
}
Ok(())
}
}

pub struct Benchmark(World);

impl Benchmark {
pub fn new() -> Self {
let mut world = World::new();

world.spawn_batch((0..1000).map(|_| {
(
Transform::default(),
Position::default(),
Rotation::default(),
Velocity::default(),
)
}));

Self(world)
}

pub fn run(&mut self) {
let Self(world) = self;
let mut encoded = Vec::new();
serialize(
&world,
&mut SerContext,
&mut ron::Serializer::new(&mut encoded, None, false).unwrap(),
)
.unwrap();
deserialize(
&mut DeContext,
&mut ron::Deserializer::from_bytes(&encoded).unwrap(),
)
.unwrap();
}
}

0 comments on commit d3f4c7f

Please sign in to comment.