Skip to content

Commit

Permalink
Merge pull request #26 from abeimler/develop
Browse files Browse the repository at this point in the history
7.1.0
  • Loading branch information
abeimler authored Jul 14, 2024
2 parents 2743723 + 2c6f318 commit 087cf9e
Show file tree
Hide file tree
Showing 121 changed files with 2,009 additions and 2,082 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ cpmaddpackage(
GITHUB_REPOSITORY
aminya/project_options
VERSION
0.34.0
0.35.1
# GIT_TAG main
DOWNLOAD_ONLY)
if(project_options_ADDED)
Expand Down
321 changes: 177 additions & 144 deletions README.md

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions README.md.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,17 @@ task generate:readme
2. `pipx run --spec ./scripts/gen-benchmark-report gen-benchmark-report -i ./info.json gen-results-md ./reports/entityx.json ./reports/entt.json ./reports/ginseng.json ./reports/mustache.json ./reports/openecs.json ./reports/flecs.json` _(generate full report)_


### Run a single benchmark

```bash
cmake -G Ninja -S . -B build
cmake --build build --target ecs-benchmark-entt -j 4
./build/benchmark/benchmarks/entt/ecs-benchmark-entt
```

You can use `-DCMAKE_BUILD_TYPE=Debug` to enable Sanitizers.


## Links and More

- [Dependency Setup](doc/README_dependencies.md)
Expand Down
62 changes: 21 additions & 41 deletions benchmark/benchmarks/ECSBenchmark.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,6 @@ class ECSBenchmark : protected BaseECSBenchmark<EntityFactory> {
[[nodiscard]] inline const char* name() const noexcept { return m_name; }
[[nodiscard]] inline auto framework_version() const { return m_options.version; }


void BM_SystemsUpdate_NoEntities(benchmark::State& state) {
// const auto nentities = 0;
std::vector<Entity> entities;
Application app(m_options.add_more_complex_system);
const ComponentsCounter components_counter = this->initApplicationWithoutEntities(app);
for (auto _ : state) {
app.update(fakeTimeDelta);
}
this->setCounters(state, entities, components_counter);
afterBenchmark(app);
uninitApplication(app);
}

void BM_SystemsUpdate(benchmark::State& state) {
const auto nentities = static_cast<size_t>(state.range(0));
std::vector<Entity> entities;
Expand Down Expand Up @@ -295,25 +281,6 @@ class ECSBenchmark : protected BaseECSBenchmark<EntityFactory> {
this->setCounters(state, entities, components_counter);
}

template <class tEntityFactory = EntityFactory>
requires(include_entity_benchmarks == ECSBenchmarkIncludeEntityBenchmarks::Yes &&
HasGetComponentsFeature<tEntityFactory>)
void BM_UnpackOneComponent_NoEntities(benchmark::State& state) {
const auto nentities = 0;
Application app(m_options.add_more_complex_system);
EntityManager& registry = app.getEntities();
std::vector<Entity> entities;
const ComponentsCounter components_counter =
this->createEntitiesWithMinimalComponents(registry, nentities, entities);

for (auto _ : state) {
for (auto& entity : entities) {
benchmark::DoNotOptimize(this->m_entities_factory.getComponentOne(registry, entity));
}
}
this->setCounters(state, entities, components_counter);
}

template <class tEntityFactory = EntityFactory>
requires(include_entity_benchmarks == ECSBenchmarkIncludeEntityBenchmarks::Yes &&
HasGetComponentsFeature<tEntityFactory>)
Expand Down Expand Up @@ -410,6 +377,27 @@ class ECSBenchmark : protected BaseECSBenchmark<EntityFactory> {
this->setCounters(state, entities, components_counter);
}

template <class tEntityFactory = EntityFactory>
requires(include_entity_benchmarks == ECSBenchmarkIncludeEntityBenchmarks::Yes)
void BM_AddComponent(benchmark::State& state) {
const auto nentities = static_cast<size_t>(state.range(0));
Application app(m_options.add_more_complex_system);
EntityManager& registry = app.getEntities();
std::vector<Entity> entities;
const ComponentsCounter components_counter =
this->createEntitiesWithMinimalComponents(registry, nentities, entities);

for (auto _ : state) {
for (auto& entity : entities) {
state.PauseTiming();
this->m_entities_factory.removeComponentOne(registry, entity);
state.ResumeTiming();
this->m_entities_factory.addComponentOne(registry, entity);
}
}
this->setCounters(state, entities, components_counter);
}

protected:
ComponentsCounter initApplicationWithoutEntities(Application& app) {
app.init();
Expand Down Expand Up @@ -490,10 +478,6 @@ class ECSBenchmark : protected BaseECSBenchmark<EntityFactory> {
} // namespace ecs::benchmarks::base

#define ECS_UPDATE_SYSTEMS_BENCHMARKS(benchmark_suite) \
static void BM_SystemsUpdate_NoEntities(benchmark::State& state) { \
benchmark_suite.BM_SystemsUpdate_NoEntities(state); \
} \
BENCHMARK(BM_SystemsUpdate_NoEntities); \
static void BM_SystemsUpdate(benchmark::State& state) { \
benchmark_suite.BM_SystemsUpdate(state); \
} \
Expand All @@ -505,10 +489,6 @@ class ECSBenchmark : protected BaseECSBenchmark<EntityFactory> {


#define ECS_COMPLEX_UPDATE_SYSTEMS_BENCHMARKS(benchmark_suite) \
static void BM_ComplexSystemsUpdate_NoEntities(benchmark::State& state) { \
benchmark_suite.BM_SystemsUpdate_NoEntities(state); \
} \
BENCHMARK(BM_ComplexSystemsUpdate_NoEntities); \
static void BM_ComplexSystemsUpdate(benchmark::State& state) { \
benchmark_suite.BM_SystemsUpdate(state); \
} \
Expand Down
59 changes: 27 additions & 32 deletions benchmark/benchmarks/EntityBenchmark.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ concept HasGetConstComponentsThreeFeature =
factory.getComponentTwoConst(entity_manager, entity);
factory.getOptionalComponentThreeConst(entity_manager, entity);
};
template <class EntityFactory, class EntityManager = typename EntityFactory::EntityManager,
class Entity = typename EntityFactory::Entity>
concept HasAddComponentThreeFeature = requires(EntityFactory factory, EntityManager& entity_manager, Entity entity) {
factory.addComponentEmpty(entity_manager, entity);
};

template <StringLiteral Name, class EntityFactory, class tEntityManager = typename EntityFactory::EntityManager>
requires std::default_initializable<tEntityManager>
Expand Down Expand Up @@ -286,34 +291,6 @@ class EntityBenchmark : public BaseECSBenchmark<EntityFactory> {
});
}

template <class tEntityFactory = EntityFactory>
requires HasGetComponentsFeature<tEntityFactory> || HasGetConstComponentsFeature<tEntityFactory>
void BM_UnpackOneComponent_NoEntities(benchmark::State& state) {
const auto nentities = 0;
EntityManager registry;
std::vector<Entity> entities;
const ComponentsCounter components_counter =
this->createEntitiesWithMinimalComponents(registry, nentities, entities);

constexpr bool hasOnlyGetConstComponentsFeature =
!HasGetComponentsFeature<tEntityFactory> || HasGetConstComponentsFeature<tEntityFactory>;

for (auto _ : state) {
for (auto& entity : entities) {
if constexpr (hasOnlyGetConstComponentsFeature) {
auto c = this->m_entities_factory.getComponentOneConst(registry, entity);
benchmark::DoNotOptimize(c);
} else {
// benchmark::DoNotOptimize(this->m_entities_factory.getComponentOne(registry, entity));
// to be fair
auto c = this->m_entities_factory.getComponentOne(registry, entity);
benchmark::DoNotOptimize(c);
}
}
}
this->setCounters(state, entities, components_counter);
}

template <class tEntityFactory = EntityFactory>
requires HasGetComponentsFeature<tEntityFactory> || HasGetConstComponentsFeature<tEntityFactory>
void BM_UnpackOneComponent(benchmark::State& state) {
Expand Down Expand Up @@ -428,6 +405,24 @@ class EntityBenchmark : public BaseECSBenchmark<EntityFactory> {
this->setCounters(state, entities, components_counter);
}

void BM_AddComponent(benchmark::State& state) {
const auto nentities = static_cast<size_t>(state.range(0));
EntityManager registry;
std::vector<Entity> entities;
const ComponentsCounter components_counter =
this->createEntitiesWithMinimalComponents(registry, nentities, entities);

for (auto _ : state) {
for (auto& entity : entities) {
state.PauseTiming();
this->m_entities_factory.removeComponentOne(registry, entity);
state.ResumeTiming();
this->m_entities_factory.addComponentOne(registry, entity);
}
}
this->setCounters(state, entities, components_counter);
}

protected:
inline static constexpr auto m_name{Name.value};
const ESCBenchmarkOptions m_options;
Expand Down Expand Up @@ -455,10 +450,6 @@ class EntityBenchmark : public BaseECSBenchmark<EntityFactory> {
benchmark_suite.BM_UnpackOneComponent(state); \
} \
BENCHMARK(BM_UnpackOneComponent)->Apply(ecs::benchmarks::base::BEDefaultArguments); \
static void BM_UnpackOneComponent_NoEntities(benchmark::State& state) { \
benchmark_suite.BM_UnpackOneComponent_NoEntities(state); \
} \
BENCHMARK(BM_UnpackOneComponent_NoEntities); \
static void BM_UnpackTwoComponents(benchmark::State& state) { \
benchmark_suite.BM_UnpackTwoComponents(state); \
} \
Expand All @@ -469,6 +460,10 @@ class EntityBenchmark : public BaseECSBenchmark<EntityFactory> {
BENCHMARK(BM_UnpackThreeComponents)->Apply(ecs::benchmarks::base::BEDefaultArguments);

#define ECS_REMOVE_ENTITY_BENCHMARKS(benchmark_suite) \
static void BM_AddComponent(benchmark::State& state) { \
benchmark_suite.BM_AddComponent(state); \
} \
BENCHMARK(BM_AddComponent)->Apply(ecs::benchmarks::base::BEDefaultArguments); \
static void BM_RemoveAddComponent(benchmark::State& state) { \
benchmark_suite.BM_RemoveAddComponent(state); \
} \
Expand Down
127 changes: 124 additions & 3 deletions benchmark/benchmarks/ExtendedECSBenchmark.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ concept HasForEach = requires(Iterable it, Func func) { it.for_each(func); };
template <typename Iterable, typename Func>
concept HasVisit = requires(Iterable it, Func func) { it.visit(func); };

template <class EntityFactory, class EntityManager = typename EntityFactory::EntityManager,
class Entity = typename EntityFactory::Entity>
concept HasClearComponentFeature = requires(EntityFactory factory, EntityManager& entity_manager, Entity entity) {
factory.clearComponentsEmpty(entity_manager);
};
template <class EntityFactory, class EntityManager = typename EntityFactory::EntityManager,
class Entity = typename EntityFactory::Entity>
concept HasAddComponentEmptyFeature = requires(EntityFactory factory, EntityManager& entity_manager, Entity entity) {
factory.addComponentEmpty(entity_manager, entity);
};

template <StringLiteral Name, class Application, class EntityFactory, class HeroMonsterEntityFactory,
ECSBenchmarkIncludeEntityBenchmarks include_entity_benchmarks = ECSBenchmarkIncludeEntityBenchmarks::No>
class ExtendedECSBenchmark
Expand Down Expand Up @@ -397,11 +408,121 @@ class ExtendedECSBenchmark
}


template <typename GetViewWithRegistry, typename PublishEventFunc>
requires std::invocable<GetViewWithRegistry&, EntityManager&> && HasClearComponentFeature<EntityFactory>
void BM_PublishEventsViaComponentWithMixedEntitiesCustom(benchmark::State& state, GetViewWithRegistry&& get_view_with_registry,
PublishEventFunc&& event_func) {
const auto nentities = static_cast<size_t>(state.range(0));
if constexpr (default_initializable_entity_manager) {
EntityManager registry;
std::vector<Entity> entities;
const ComponentsCounter components_counter =
this->template createEntitiesWithMixedComponents<EntityFactory>(registry, nentities, entities);

auto view = get_view_with_registry(registry);
for (auto _ : state) {
event_func(registry, view);
this->m_entities_factory.clearComponentsEmpty(registry);
}

this->setCounters(state, entities, components_counter);
} else {
Application app(this->m_options.add_more_complex_system);
EntityManager& registry = app.getEntities();
std::vector<Entity> entities;
const ComponentsCounter components_counter =
this->createEntitiesWithMinimalComponents(registry, nentities, entities);

auto view = get_view_with_registry(registry);
for (auto _ : state) {
event_func(registry, view);
this->m_entities_factory.clearComponentsEmpty(registry);
}

this->setCounters(state, entities, components_counter);
//state.counters["events_count"] = static_cast<double>(entities.size());
}
}
template <typename GetViewWithRegistry, typename PublishEventFunc>
requires std::invocable<GetViewWithRegistry&, EntityManager&> && HasClearComponentFeature<EntityFactory>
void BM_PublishEventsViaComponentWithMixedEntitiesViews(benchmark::State& state, GetViewWithRegistry&& get_view_with_registry, PublishEventFunc&& event_func) {
BM_PublishEventsViaComponentWithMixedEntitiesCustom(state, get_view_with_registry, [&](auto& registry, auto& view) {
generic_each(view, [&](auto&&... comps){ event_func(std::forward<decltype(registry)>(registry), std::forward<decltype(comps)>(comps)...); });
});
}
template <typename GetViewWithRegistry>
requires std::invocable<GetViewWithRegistry&, EntityManager&> && HasClearComponentFeature<EntityFactory> && HasAddComponentEmptyFeature<EntityFactory>
void BM_PublishEventsViaComponentWithMixedEntitiesViews(benchmark::State& state, GetViewWithRegistry&& get_view_with_registry) {
BM_PublishEventsViaComponentWithMixedEntitiesViews(state, get_view_with_registry, [&](auto& registry, auto entity, auto&... /*comps*/) {
this->m_entities_factory.addComponentEmpty(registry, entity);
});
}

template <typename GetViewWithRegistry, typename GetViewWithEvent, typename PublishEventFunc, typename UpdateFunc>
requires std::invocable<GetViewWithRegistry&, EntityManager&> && std::invocable<GetViewWithEvent&, EntityManager&> && HasClearComponentFeature<EntityFactory>
void BM_PublishAndUpdateEventsViaComponentWithMixedEntitiesCustom(benchmark::State& state, GetViewWithRegistry&& get_view_with_registry, GetViewWithEvent&& get_view_with_event,
PublishEventFunc&& event_func, UpdateFunc&& update_func) {
const auto nentities = static_cast<size_t>(state.range(0));
if constexpr (default_initializable_entity_manager) {
EntityManager registry;
std::vector<Entity> entities;
const ComponentsCounter components_counter =
this->template createEntitiesWithMixedComponents<EntityFactory>(registry, nentities, entities);

auto view = get_view_with_registry(registry);
auto event_view = get_view_with_event(registry);
for (auto _ : state) {
update_func(registry, view);
event_func(registry, event_view);
this->m_entities_factory.clearComponentsEmpty(registry);
}

this->setCounters(state, entities, components_counter);
} else {
Application app(this->m_options.add_more_complex_system);
EntityManager& registry = app.getEntities();
std::vector<Entity> entities;
const ComponentsCounter components_counter =
this->createEntitiesWithMinimalComponents(registry, nentities, entities);

auto view = get_view_with_registry(registry);
auto event_view = get_view_with_event(registry);
for (auto _ : state) {
update_func(registry, view);
event_func(registry, event_view);
this->m_entities_factory.clearComponentsEmpty(registry);
}

this->setCounters(state, entities, components_counter);
//state.counters["events_count"] = static_cast<double>(entities.size());
}
}
template <typename GetViewWithRegistry, typename GetViewWithEvent, typename PublishEventFunc, typename UpdateFunc>
requires std::invocable<GetViewWithRegistry&, EntityManager&> && std::invocable<GetViewWithEvent&, EntityManager&> && HasClearComponentFeature<EntityFactory>
void BM_PublishAndUpdateEventsViaComponentWithMixedEntitiesViews(benchmark::State& state, GetViewWithRegistry&& get_view_with_registry, GetViewWithEvent&& get_view_with_event, PublishEventFunc&& event_func, UpdateFunc&& update_func) {
BM_PublishAndUpdateEventsViaComponentWithMixedEntitiesCustom(state, get_view_with_registry, get_view_with_event, [&](auto& registry, auto& view) {
generic_each(view, [&](auto&&... comps){ event_func(std::forward<decltype(registry)>(registry), std::forward<decltype(comps)>(comps)...); });
}, [&](auto& /*registry*/, auto& view) {
generic_each(view, update_func);
});
}
template <typename GetViewWithRegistry, typename GetViewWithEvent>
requires std::invocable<GetViewWithRegistry&, EntityManager&> && std::invocable<GetViewWithEvent&, EntityManager&> && HasClearComponentFeature<EntityFactory> && HasAddComponentEmptyFeature<EntityFactory>
void BM_PublishAndUpdateEventsViaComponentWithMixedEntitiesViews(benchmark::State& state, GetViewWithRegistry&& get_view_with_registry, GetViewWithEvent&& get_view_with_event) {
BM_PublishAndUpdateEventsViaComponentWithMixedEntitiesViews(state, get_view_with_registry, get_view_with_event, [&](auto& registry, auto entity, auto&... /*comps*/) {
this->m_entities_factory.addComponentEmpty(registry, entity);
}, [](auto& /*entity*/, auto&... comp) {
dummy_each(comp...);
});
}


public:
template <class Comp, class... Args>
inline static void dummy_each(Comp& comp, Args&&... args) {
benchmark::DoNotOptimize(comp);
(benchmark::DoNotOptimize(args), ...);
inline static void dummy_each(Comp& comp_or_entity, Args&... comps) {
benchmark::DoNotOptimize(comp_or_entity);
(benchmark::DoNotOptimize(comps), ...);
//assert(comp_or_entity);
}

template <typename Iterable, typename Func>
Expand Down
6 changes: 6 additions & 0 deletions benchmark/benchmarks/basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,10 @@ void BEDefaultArguments(benchmark::internal::Benchmark* b) {
});
}

void BESmallArguments(benchmark::internal::Benchmark* b) {
b->ArgsProduct({
benchmark::CreateRange(MIN_ENTITIES_RANGE, SMALL_MAX_ENTITIES_RANGE, /*multi=*/2),
});
}

} // namespace ecs::benchmarks::base
5 changes: 4 additions & 1 deletion benchmark/benchmarks/basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,13 @@ struct ComponentsCounter {
size_t monster_count{0};
};

inline static constexpr auto MIN_ENTITIES_RANGE = 8L;
inline static constexpr auto MIN_ENTITIES_RANGE = 0L;
inline static constexpr auto MAX_ENTITIES_RANGE = 2'097'152L;
inline static constexpr auto SMALL_MAX_ENTITIES_RANGE = 32'768L;

void BEDefaultArguments(benchmark::internal::Benchmark* b);
void BESmallArguments(benchmark::internal::Benchmark* b);

} // namespace ecs::benchmarks::base

#endif // ECS_BENCHMARKS_BASICBENCHMARK_H_
Loading

0 comments on commit 087cf9e

Please sign in to comment.