Michele Caini před 7 roky
rodič
revize
cb93a3bee3
2 změnil soubory, kde provedl 252 přidání a 10 odebrání
  1. 6 10
      src/entt/entity/group.hpp
  2. 246 0
      test/benchmark/benchmark.cpp

+ 6 - 10
src/entt/entity/group.hpp

@@ -5,7 +5,6 @@
 #include <cassert>
 #include <tuple>
 #include <utility>
-#include <algorithm>
 #include <type_traits>
 #include "../config/config.h"
 #include "../core/type_traits.hpp"
@@ -257,15 +256,13 @@ public:
      */
     template<typename Func>
     inline void each(Func func) const {
-        if constexpr(std::is_invocable_v<Func, std::add_lvalue_reference_t<Get>...>) {
-            std::for_each(handler->begin(), handler->end(), [func = std::move(func), this](const auto entity) mutable {
+        for(const auto entity: *handler) {
+            if constexpr(std::is_invocable_v<Func, std::add_lvalue_reference_t<Get>...>) {
                 func(std::get<pool_type<Get> *>(pools)->get(entity)...);
-            });
-        } else {
-            std::for_each(handler->begin(), handler->end(), [func = std::move(func), this](const auto entity) mutable {
+            } else {
                 func(entity, std::get<pool_type<Get> *>(pools)->get(entity)...);
-            });
-        }
+            }
+        };
     }
 
     /**
@@ -537,9 +534,8 @@ public:
     inline void each(Func func) const {
         auto raw = std::make_tuple((std::get<pool_type<Owned> *>(pools)->end() - *length)...);
         [[maybe_unused]] auto data = std::get<0>(pools)->sparse_set<entity_type>::end() - *length;
-        const auto cend = std::get<0>(pools)->end();
 
-        while(std::get<0>(raw) != cend) {
+        for(auto next = *length; next; --next) {
             if constexpr(std::is_invocable_v<Func, std::add_lvalue_reference_t<Owned>..., std::add_lvalue_reference_t<Get>...>) {
                 if constexpr(sizeof...(Get) == 0) {
                     func(*(std::get<component_iterator_type<Owned>>(raw)++)...);

+ 246 - 0
test/benchmark/benchmark.cpp

@@ -380,6 +380,252 @@ TEST(Benchmark, IterateTwoComponentsRuntime1MOne) {
     });
 }
 
+TEST(Benchmark, IterateThreeComponents1M) {
+    entt::registry<> registry;
+
+    std::cout << "Iterating over 1000000 entities, three components" << std::endl;
+
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        const auto entity = registry.create();
+        registry.assign<position>(entity);
+        registry.assign<velocity>(entity);
+        registry.assign<comp<0>>(entity);
+    }
+
+    auto test = [&registry](auto func) {
+        timer timer;
+        registry.view<position, velocity, comp<0>>().each(func);
+        timer.elapsed();
+    };
+
+    test([](const auto &...) {});
+    test([](auto &... comp) {
+        ((comp.x = {}), ...);
+    });
+}
+
+TEST(Benchmark, IterateThreeComponents1MHalf) {
+    entt::registry<> registry;
+
+    std::cout << "Iterating over 1000000 entities, three components, half of the entities have all the components" << std::endl;
+
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        const auto entity = registry.create();
+        registry.assign<velocity>(entity);
+        registry.assign<comp<0>>(entity);
+
+        if(i % 2) {
+            registry.assign<position>(entity);
+        }
+    }
+
+    auto test = [&registry](auto func) {
+        timer timer;
+        registry.view<position, velocity, comp<0>>().each(func);
+        timer.elapsed();
+    };
+
+    test([](const auto &...) {});
+    test([](auto &... comp) {
+        ((comp.x = {}), ...);
+    });
+}
+
+TEST(Benchmark, IterateThreeComponents1MOne) {
+    entt::registry<> registry;
+
+    std::cout << "Iterating over 1000000 entities, three components, only one entity has all the components" << std::endl;
+
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        const auto entity = registry.create();
+        registry.assign<velocity>(entity);
+        registry.assign<comp<0>>(entity);
+
+        if(i == 5000000L) {
+            registry.assign<position>(entity);
+        }
+    }
+
+    auto test = [&registry](auto func) {
+        timer timer;
+        registry.view<position, velocity, comp<0>>().each(func);
+        timer.elapsed();
+    };
+
+    test([](const auto &...) {});
+    test([](auto &... comp) {
+        ((comp.x = {}), ...);
+    });
+}
+
+TEST(Benchmark, IterateThreeComponentsNonOwningGroup1M) {
+    entt::registry<> registry;
+    registry.group<>(entt::get<position, velocity>);
+
+    std::cout << "Iterating over 1000000 entities, three components, non owning group" << std::endl;
+
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        const auto entity = registry.create();
+        registry.assign<position>(entity);
+        registry.assign<velocity>(entity);
+        registry.assign<comp<0>>(entity);
+    }
+
+    auto test = [&registry](auto func) {
+        timer timer;
+        registry.group<>(entt::get<position, velocity, comp<0>>).each(func);
+        timer.elapsed();
+    };
+
+    test([](const auto &...) {});
+    test([](auto &... comp) {
+        ((comp.x = {}), ...);
+    });
+}
+
+TEST(Benchmark, IterateThreeComponentsFullOwningGroup1M) {
+    entt::registry<> registry;
+    registry.group<position, velocity, comp<0>>();
+
+    std::cout << "Iterating over 1000000 entities, three components, full owning group" << std::endl;
+
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        const auto entity = registry.create();
+        registry.assign<position>(entity);
+        registry.assign<velocity>(entity);
+        registry.assign<comp<0>>(entity);
+    }
+
+    auto test = [&registry](auto func) {
+        timer timer;
+        registry.group<position, velocity, comp<0>>().each(func);
+        timer.elapsed();
+    };
+
+    test([](const auto &...) {});
+    test([](auto &... comp) {
+        ((comp.x = {}), ...);
+    });
+}
+
+TEST(Benchmark, IterateThreeComponentsPartialOwningGroup1M) {
+    entt::registry<> registry;
+    registry.group<position, velocity>(entt::get<comp<0>>);
+
+    std::cout << "Iterating over 1000000 entities, three components, partial owning group" << std::endl;
+
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        const auto entity = registry.create();
+        registry.assign<position>(entity);
+        registry.assign<velocity>(entity);
+        registry.assign<comp<0>>(entity);
+    }
+
+    auto test = [&registry](auto func) {
+        timer timer;
+        registry.group<position, velocity>(entt::get<comp<0>>).each(func);
+        timer.elapsed();
+    };
+
+    test([](const auto &...) {});
+    test([](auto &... comp) {
+        ((comp.x = {}), ...);
+    });
+}
+
+TEST(Benchmark, IterateThreeComponentsRuntime1M) {
+    entt::registry<> registry;
+
+    std::cout << "Iterating over 1000000 entities, three components, runtime view" << std::endl;
+
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        const auto entity = registry.create();
+        registry.assign<position>(entity);
+        registry.assign<velocity>(entity);
+        registry.assign<comp<0>>(entity);
+    }
+
+    auto test = [&registry](auto func) {
+        using component_type = typename entt::registry<>::component_type;
+        component_type types[] = { registry.type<position>(), registry.type<velocity>(), registry.type<comp<0>>() };
+
+        timer timer;
+        registry.runtime_view(std::begin(types), std::end(types)).each(func);
+        timer.elapsed();
+    };
+
+    test([](auto) {});
+    test([&registry](auto entity) {
+        registry.get<position>(entity).x = {};
+        registry.get<velocity>(entity).x = {};
+        registry.get<comp<0>>(entity).x = {};
+    });
+}
+
+TEST(Benchmark, IterateThreeComponentsRuntime1MHalf) {
+    entt::registry<> registry;
+
+    std::cout << "Iterating over 1000000 entities, three components, half of the entities have all the components, runtime view" << std::endl;
+
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        const auto entity = registry.create();
+        registry.assign<velocity>(entity);
+        registry.assign<comp<0>>(entity);
+
+        if(i % 2) {
+            registry.assign<position>(entity);
+        }
+    }
+
+    auto test = [&registry](auto func) {
+        using component_type = typename entt::registry<>::component_type;
+        component_type types[] = { registry.type<position>(), registry.type<velocity>(), registry.type<comp<0>>() };
+
+        timer timer;
+        registry.runtime_view(std::begin(types), std::end(types)).each(func);
+        timer.elapsed();
+    };
+
+    test([](auto) {});
+    test([&registry](auto entity) {
+        registry.get<position>(entity).x = {};
+        registry.get<velocity>(entity).x = {};
+        registry.get<comp<0>>(entity).x = {};
+    });
+}
+
+TEST(Benchmark, IterateThreeComponentsRuntime1MOne) {
+    entt::registry<> registry;
+
+    std::cout << "Iterating over 1000000 entities, three components, only one entity has all the components, runtime view" << std::endl;
+
+    for(std::uint64_t i = 0; i < 1000000L; i++) {
+        const auto entity = registry.create();
+        registry.assign<velocity>(entity);
+        registry.assign<comp<0>>(entity);
+
+        if(i == 5000000L) {
+            registry.assign<position>(entity);
+        }
+    }
+
+    auto test = [&registry](auto func) {
+        using component_type = typename entt::registry<>::component_type;
+        component_type types[] = { registry.type<position>(), registry.type<velocity>(), registry.type<comp<0>>() };
+
+        timer timer;
+        registry.runtime_view(std::begin(types), std::end(types)).each(func);
+        timer.elapsed();
+    };
+
+    test([](auto) {});
+    test([&registry](auto entity) {
+        registry.get<position>(entity).x = {};
+        registry.get<velocity>(entity).x = {};
+        registry.get<comp<0>>(entity).x = {};
+    });
+}
+
 TEST(Benchmark, IterateFiveComponents1M) {
     entt::registry<> registry;