id/version review

This commit is contained in:
Michele Caini
2018-03-04 15:32:08 +01:00
parent 9c540c03aa
commit 7bf550a75f
5 changed files with 99 additions and 117 deletions

View File

@@ -189,19 +189,19 @@ Dell XPS 13 out of the mid 2014):
| Benchmark | EntityX (compile-time) | EnTT |
|-----------|-------------|-------------|
| Create 10M entities | 0.1289s | **0.0423s** |
| Destroy 10M entities | 0.0531s | **0.0221s** |
| Standard view, 10M entities, one component | 0.0107s | **7.8e-08s** |
| Standard view, 10M entities, two components | **0.0113s** | 0.0142s |
| Standard view, 10M entities, two components<br/>Half of the entities have all the components | 0.0078s | **0.0072s** |
| Standard view, 10M entities, two components<br/>One of the entities has all the components | 0.0071s | **5.5e-07s** |
| Persistent view, 10M entities, two components | 0.0113s | **1.1e-07s** |
| Standard view, 10M entities, five components | **0.0091s** | 0.0352s |
| Persistent view, 10M entities, five components | 0.0091s | **2.5e-07s** |
| Standard view, 10M entities, ten components | **0.0105s** | 0.0780s |
| Standard view, 10M entities, ten components<br/>Half of the entities have all the components | **0.0090s** | 0.0407s |
| Standard view, 10M entities, ten components<br/>One of the entities has all the components | 0.0070s | **1.3e-06s** |
| Persistent view, 10M entities, ten components | 0.0105s | **5.0e-07s** |
| Create 1M entities | 0.0167s | **0.0076s** |
| Destroy 1M entities | 0.0053s | **0.0031s** |
| Standard view, 1M entities, one component | 0.0012s | **1.9e-07s** |
| Standard view, 1M entities, two components | **0.0012s** | 0.0013s |
| Standard view, 1M entities, two components<br/>Half of the entities have all the components | 0.0009s | **0.0007s** |
| Standard view, 1M entities, two components<br/>One of the entities has all the components | 0.0008s | **1.3e-06s** |
| Persistent view, 1M entities, two components | 0.0012s | **2.8e-07s** |
| Standard view, 1M entities, five components | **0.0010s** | 0.0034s |
| Persistent view, 1M entities, five components | 0.0010s | **2.8e-07s** |
| Standard view, 1M entities, ten components | **0.0011s** | 0.0075s |
| Standard view, 1M entities, ten components<br/>Half of the entities have all the components | **0.0010s** | 0.0041s |
| Standard view, 1M entities, ten components<br/>One of the entities has all the components | 0.0008s | **1.7e-06s** |
| Persistent view, 1M entities, ten components | 0.0011s | **3.0e-07s** |
| Sort 150k entities, one component<br/>Arrays are in reverse order | - | **0.0040s** |
| Sort 150k entities, enforce permutation<br/>Arrays are in reverse order | - | **0.0006s** |

View File

@@ -58,11 +58,11 @@ struct entt_traits<std::uint32_t> {
using version_type = std::uint16_t;
/*! @brief Mask to use to get the entity number out of an identifier. */
static constexpr auto entity_mask = 0xFFFFFF;
static constexpr auto entity_mask = 0xFFFFF;
/*! @brief Mask to use to get the version out of an identifier. */
static constexpr auto version_mask = 0xFF;
static constexpr auto version_mask = 0xFFF;
/*! @brief Extent of the entity number within an identifier. */
static constexpr auto entity_shift = 24;
static constexpr auto entity_shift = 20;
};

View File

@@ -233,7 +233,7 @@ public:
assert(has(entity));
const auto entt = entity & traits_type::entity_mask;
// we must get rid of the in-use bit for it's not part of the position
return reverse[entt] & ~in_use;
return reverse[entt] & traits_type::entity_mask;
}
/**
@@ -278,10 +278,9 @@ public:
assert(has(entity));
const auto entt = entity & traits_type::entity_mask;
const auto back = direct.back() & traits_type::entity_mask;
const auto pos = reverse[entt] & ~in_use;
// the order matters: if back and entt are the same (for the sparse set
// has size 1), switching the two lines below doesn't work as expected
reverse[back] = pos | in_use;
// we must get rid of the in-use bit for it's not part of the position
const auto pos = reverse[entt] & traits_type::entity_mask;
reverse[back] = reverse[entt];
reverse[entt] = pos;
// swapping isn't required here, we are getting rid of the last element
direct[pos] = direct.back();

View File

@@ -34,11 +34,11 @@ private:
TEST(Benchmark, Construct) {
entt::DefaultRegistry registry;
std::cout << "Constructing 10000000 entities" << std::endl;
std::cout << "Constructing 1000000 entities" << std::endl;
Timer timer;
for(std::uint64_t i = 0; i < 10000000L; i++) {
for(std::uint64_t i = 0; i < 1000000L; i++) {
registry.create();
}
@@ -49,9 +49,9 @@ TEST(Benchmark, Destroy) {
entt::DefaultRegistry registry;
std::vector<entt::DefaultRegistry::entity_type> entities{};
std::cout << "Destroying 10000000 entities" << std::endl;
std::cout << "Destroying 1000000 entities" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
for(std::uint64_t i = 0; i < 1000000L; i++) {
entities.push_back(registry.create());
}
@@ -88,12 +88,12 @@ TEST(Benchmark, IterateCreateDeleteSingleComponent) {
timer.elapsed();
}
TEST(Benchmark, IterateSingleComponent10M) {
TEST(Benchmark, IterateSingleComponent1M) {
entt::DefaultRegistry registry;
std::cout << "Iterating over 10000000 entities, one component" << std::endl;
std::cout << "Iterating over 1000000 entities, one component" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
for(std::uint64_t i = 0; i < 1000000L; i++) {
registry.create<Position>();
}
@@ -102,12 +102,12 @@ TEST(Benchmark, IterateSingleComponent10M) {
timer.elapsed();
}
TEST(Benchmark, IterateTwoComponents10M) {
TEST(Benchmark, IterateTwoComponents1M) {
entt::DefaultRegistry registry;
std::cout << "Iterating over 10000000 entities, two components" << std::endl;
std::cout << "Iterating over 1000000 entities, two components" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
for(std::uint64_t i = 0; i < 1000000L; i++) {
registry.create<Position, Velocity>();
}
@@ -116,12 +116,12 @@ TEST(Benchmark, IterateTwoComponents10M) {
timer.elapsed();
}
TEST(Benchmark, IterateTwoComponents10MHalf) {
TEST(Benchmark, IterateTwoComponents1MHalf) {
entt::DefaultRegistry registry;
std::cout << "Iterating over 10000000 entities, two components, half of the entities have all the components" << std::endl;
std::cout << "Iterating over 1000000 entities, two components, half of the entities have all the components" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
for(std::uint64_t i = 0; i < 1000000L; i++) {
auto entity = registry.create<Velocity>();
if(i % 2) { registry.assign<Position>(entity); }
}
@@ -131,12 +131,12 @@ TEST(Benchmark, IterateTwoComponents10MHalf) {
timer.elapsed();
}
TEST(Benchmark, IterateTwoComponents10MOne) {
TEST(Benchmark, IterateTwoComponents1MOne) {
entt::DefaultRegistry registry;
std::cout << "Iterating over 10000000 entities, two components, only one entity has all the components" << std::endl;
std::cout << "Iterating over 1000000 entities, two components, only one entity has all the components" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
for(std::uint64_t i = 0; i < 1000000L; i++) {
auto entity = registry.create<Velocity>();
if(i == 5000000L) { registry.assign<Position>(entity); }
}
@@ -146,13 +146,13 @@ TEST(Benchmark, IterateTwoComponents10MOne) {
timer.elapsed();
}
TEST(Benchmark, IterateTwoComponentsPersistent10M) {
TEST(Benchmark, IterateTwoComponentsPersistent1M) {
entt::DefaultRegistry registry;
registry.prepare<Position, Velocity>();
std::cout << "Iterating over 10000000 entities, two components, persistent view" << std::endl;
std::cout << "Iterating over 1000000 entities, two components, persistent view" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
for(std::uint64_t i = 0; i < 1000000L; i++) {
registry.create<Position, Velocity>();
}
@@ -161,44 +161,12 @@ TEST(Benchmark, IterateTwoComponentsPersistent10M) {
timer.elapsed();
}
TEST(Benchmark, IterateTwoComponentsPersistent10MHalf) {
entt::DefaultRegistry registry;
registry.prepare<Position, Velocity>();
std::cout << "Iterating over 10000000 entities, two components, persistent view, half of the entities have all the components" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
auto entity = registry.create<Velocity>();
if(i % 2) { registry.assign<Position>(entity); }
}
Timer timer;
registry.persistent<Position, Velocity>().each([](auto, auto &...) {});
timer.elapsed();
}
TEST(Benchmark, IterateTwoComponentsPersistent10MOne) {
entt::DefaultRegistry registry;
registry.prepare<Position, Velocity>();
std::cout << "Iterating over 10000000 entities, two components, persistent view, only one entity has all the components" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
auto entity = registry.create<Velocity>();
if(i == 5000000L) { registry.assign<Position>(entity); }
}
Timer timer;
registry.persistent<Position, Velocity>().each([](auto, auto &...) {});
timer.elapsed();
}
TEST(Benchmark, IterateFiveComponents10M) {
TEST(Benchmark, IterateFiveComponents1M) {
entt::DefaultRegistry registry;
std::cout << "Iterating over 10000000 entities, five components" << std::endl;
std::cout << "Iterating over 1000000 entities, five components" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
for(std::uint64_t i = 0; i < 1000000L; i++) {
registry.create<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>();
}
@@ -207,57 +175,43 @@ TEST(Benchmark, IterateFiveComponents10M) {
timer.elapsed();
}
TEST(Benchmark, IterateTenComponents10M) {
TEST(Benchmark, IterateFiveComponents1MHalf) {
entt::DefaultRegistry registry;
std::cout << "Iterating over 10000000 entities, ten components" << std::endl;
std::cout << "Iterating over 1000000 entities, five components, half of the entities have all the components" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
registry.create<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
}
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
timer.elapsed();
}
TEST(Benchmark, IterateTenComponents10MHalf) {
entt::DefaultRegistry registry;
std::cout << "Iterating over 10000000 entities, ten components, half of the entities have all the components" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
auto entity = registry.create<Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
for(std::uint64_t i = 0; i < 1000000L; i++) {
auto entity = registry.create<Velocity, Comp<1>, Comp<2>, Comp<3>>();
if(i % 2) { registry.assign<Position>(entity); }
}
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each([](auto, auto &...) {});
timer.elapsed();
}
TEST(Benchmark, IterateTenComponents10MOne) {
TEST(Benchmark, IterateFiveComponents1MOne) {
entt::DefaultRegistry registry;
std::cout << "Iterating over 10000000 entities, ten components, only one entity has all the components" << std::endl;
std::cout << "Iterating over 1000000 entities, five components, only one entity has all the components" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
auto entity = registry.create<Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
for(std::uint64_t i = 0; i < 1000000L; i++) {
auto entity = registry.create<Velocity, Comp<1>, Comp<2>, Comp<3>>();
if(i == 5000000L) { registry.assign<Position>(entity); }
}
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each([](auto, auto &...) {});
timer.elapsed();
}
TEST(Benchmark, IterateFiveComponentsPersistent10M) {
TEST(Benchmark, IterateFiveComponentsPersistent1M) {
entt::DefaultRegistry registry;
registry.prepare<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>();
std::cout << "Iterating over 10000000 entities, five components, persistent view" << std::endl;
std::cout << "Iterating over 1000000 entities, five components, persistent view" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
for(std::uint64_t i = 0; i < 1000000L; i++) {
registry.create<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>();
}
@@ -266,46 +220,58 @@ TEST(Benchmark, IterateFiveComponentsPersistent10M) {
timer.elapsed();
}
TEST(Benchmark, IterateTenComponentsPersistent10M) {
TEST(Benchmark, IterateTenComponents1M) {
entt::DefaultRegistry registry;
registry.prepare<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
std::cout << "Iterating over 10000000 entities, ten components, persistent view" << std::endl;
std::cout << "Iterating over 1000000 entities, ten components" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
for(std::uint64_t i = 0; i < 1000000L; i++) {
registry.create<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
}
Timer timer;
registry.persistent<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
timer.elapsed();
}
TEST(Benchmark, IterateTenComponentsPersistent10MHalf) {
TEST(Benchmark, IterateTenComponents1MHalf) {
entt::DefaultRegistry registry;
registry.prepare<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
std::cout << "Iterating over 10000000 entities, ten components, persistent view, half of the entities have all the components" << std::endl;
std::cout << "Iterating over 1000000 entities, ten components, half of the entities have all the components" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
for(std::uint64_t i = 0; i < 1000000L; i++) {
auto entity = registry.create<Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
if(i % 2) { registry.assign<Position>(entity); }
}
Timer timer;
registry.persistent<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
timer.elapsed();
}
TEST(Benchmark, IterateTenComponentsPersistent10MOne) {
TEST(Benchmark, IterateTenComponents1MOne) {
entt::DefaultRegistry registry;
std::cout << "Iterating over 1000000 entities, ten components, only one entity has all the components" << std::endl;
for(std::uint64_t i = 0; i < 1000000L; i++) {
auto entity = registry.create<Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
if(i == 5000000L) { registry.assign<Position>(entity); }
}
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
timer.elapsed();
}
TEST(Benchmark, IterateTenComponentsPersistent1M) {
entt::DefaultRegistry registry;
registry.prepare<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
std::cout << "Iterating over 10000000 entities, ten components, persistent view, only one entity has all the components" << std::endl;
std::cout << "Iterating over 1000000 entities, ten components, persistent view" << std::endl;
for(std::uint64_t i = 0; i < 10000000L; i++) {
auto entity = registry.create<Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
if(i == 5000000L) { registry.assign<Position>(entity); }
for(std::uint64_t i = 0; i < 1000000L; i++) {
registry.create<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
}
Timer timer;

View File

@@ -3,6 +3,7 @@
#include <functional>
#include <type_traits>
#include <gtest/gtest.h>
#include <entt/entity/entt_traits.hpp>
#include <entt/entity/registry.hpp>
TEST(DefaultRegistry, Functionalities) {
@@ -149,6 +150,22 @@ TEST(DefaultRegistry, CreateDestroyCornerCase) {
ASSERT_EQ(registry.current(e1), entt::DefaultRegistry::version_type{1});
}
TEST(DefaultRegistry, VersionOverflow) {
entt::DefaultRegistry registry;
auto entity = registry.create();
registry.destroy(entity);
ASSERT_EQ(registry.version(entity), entt::DefaultRegistry::version_type{});
for(auto i = entt::entt_traits<entt::DefaultRegistry::entity_type>::version_mask; i; --i) {
ASSERT_NE(registry.current(entity), registry.version(entity));
registry.destroy(registry.create());
}
ASSERT_EQ(registry.current(entity), registry.version(entity));
}
TEST(DefaultRegistry, Each) {
entt::DefaultRegistry registry;
entt::DefaultRegistry::size_type tot;