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

7.1.0 #26

Merged
merged 12 commits into from
Jul 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Loading