Sdk/World: Add profiler
This commit is contained in:
parent
6161b1a751
commit
a9364ab7e2
|
|
@ -96,6 +96,7 @@ Nazara Development Kit:
|
||||||
- Fix CollisionComponent3D initialization (teleportation to their real coordinates) which could sometimes mess up the physics scene.
|
- Fix CollisionComponent3D initialization (teleportation to their real coordinates) which could sometimes mess up the physics scene.
|
||||||
- ⚠️ Renamed World::Update() to World::Refresh() for more clarity and to differentiate it from World::Update(elapsedTime)
|
- ⚠️ Renamed World::Update() to World::Refresh() for more clarity and to differentiate it from World::Update(elapsedTime)
|
||||||
- World entity ids are now reused from lowest to highest (they were previously reused in reverse order of death)
|
- World entity ids are now reused from lowest to highest (they were previously reused in reverse order of death)
|
||||||
|
- World now has an internal profiler, allowing to measure the refresh and system update time
|
||||||
|
|
||||||
# 0.4:
|
# 0.4:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ namespace Ndk
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using EntityVector = std::vector<EntityHandle>;
|
using EntityVector = std::vector<EntityHandle>;
|
||||||
|
struct ProfilerData;
|
||||||
|
|
||||||
inline World(bool addDefaultSystems = true);
|
inline World(bool addDefaultSystems = true);
|
||||||
World(const World&) = delete;
|
World(const World&) = delete;
|
||||||
|
|
@ -46,8 +47,12 @@ namespace Ndk
|
||||||
void Clear() noexcept;
|
void Clear() noexcept;
|
||||||
const EntityHandle& CloneEntity(EntityId id);
|
const EntityHandle& CloneEntity(EntityId id);
|
||||||
|
|
||||||
|
inline void DisableProfiler();
|
||||||
|
inline void EnableProfiler(bool enable = true);
|
||||||
|
|
||||||
inline const EntityHandle& GetEntity(EntityId id);
|
inline const EntityHandle& GetEntity(EntityId id);
|
||||||
inline const EntityList& GetEntities() const;
|
inline const EntityList& GetEntities() const;
|
||||||
|
inline const ProfilerData& GetProfilerData() const;
|
||||||
inline BaseSystem& GetSystem(SystemIndex index);
|
inline BaseSystem& GetSystem(SystemIndex index);
|
||||||
template<typename SystemType> SystemType& GetSystem();
|
template<typename SystemType> SystemType& GetSystem();
|
||||||
|
|
||||||
|
|
@ -59,18 +64,27 @@ namespace Ndk
|
||||||
|
|
||||||
inline bool IsEntityValid(const Entity* entity) const;
|
inline bool IsEntityValid(const Entity* entity) const;
|
||||||
inline bool IsEntityIdValid(EntityId id) const;
|
inline bool IsEntityIdValid(EntityId id) const;
|
||||||
|
inline bool IsProfilerEnabled() const;
|
||||||
|
|
||||||
inline void RemoveAllSystems();
|
inline void RemoveAllSystems();
|
||||||
inline void RemoveSystem(SystemIndex index);
|
inline void RemoveSystem(SystemIndex index);
|
||||||
template<typename SystemType> void RemoveSystem();
|
template<typename SystemType> void RemoveSystem();
|
||||||
|
|
||||||
void Refresh();
|
void Refresh();
|
||||||
|
inline void ResetProfiler();
|
||||||
|
|
||||||
void Update(float elapsedTime);
|
void Update(float elapsedTime);
|
||||||
|
|
||||||
World& operator=(const World&) = delete;
|
World& operator=(const World&) = delete;
|
||||||
inline World& operator=(World&& world) noexcept;
|
inline World& operator=(World&& world) noexcept;
|
||||||
|
|
||||||
|
struct ProfilerData
|
||||||
|
{
|
||||||
|
Nz::UInt64 refreshTime = 0;
|
||||||
|
std::vector<Nz::UInt64> updateTime;
|
||||||
|
std::size_t updateCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline void Invalidate();
|
inline void Invalidate();
|
||||||
inline void Invalidate(EntityId id);
|
inline void Invalidate(EntityId id);
|
||||||
|
|
@ -97,10 +111,12 @@ namespace Ndk
|
||||||
std::vector<EntityBlock*> m_entityBlocks;
|
std::vector<EntityBlock*> m_entityBlocks;
|
||||||
std::vector<std::unique_ptr<EntityBlock>> m_waitingEntities;
|
std::vector<std::unique_ptr<EntityBlock>> m_waitingEntities;
|
||||||
EntityList m_aliveEntities;
|
EntityList m_aliveEntities;
|
||||||
|
ProfilerData m_profilerData;
|
||||||
Nz::Bitset<Nz::UInt64> m_dirtyEntities;
|
Nz::Bitset<Nz::UInt64> m_dirtyEntities;
|
||||||
Nz::Bitset<Nz::UInt64> m_freeEntityIds;
|
Nz::Bitset<Nz::UInt64> m_freeEntityIds;
|
||||||
Nz::Bitset<Nz::UInt64> m_killedEntities;
|
Nz::Bitset<Nz::UInt64> m_killedEntities;
|
||||||
bool m_orderedSystemsUpdated;
|
bool m_orderedSystemsUpdated;
|
||||||
|
bool m_isProfilerEnabled;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// This file is part of the "Nazara Development Kit"
|
// This file is part of the "Nazara Development Kit"
|
||||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||||
|
|
||||||
|
#include <NDK/World.hpp>
|
||||||
#include <Nazara/Core/Error.hpp>
|
#include <Nazara/Core/Error.hpp>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
|
@ -14,7 +15,8 @@ namespace Ndk
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline World::World(bool addDefaultSystems) :
|
inline World::World(bool addDefaultSystems) :
|
||||||
m_orderedSystemsUpdated(false)
|
m_orderedSystemsUpdated(false),
|
||||||
|
m_isProfilerEnabled(false)
|
||||||
{
|
{
|
||||||
if (addDefaultSystems)
|
if (addDefaultSystems)
|
||||||
AddDefaultSystems();
|
AddDefaultSystems();
|
||||||
|
|
@ -47,7 +49,10 @@ namespace Ndk
|
||||||
|
|
||||||
// We must ensure that the vector is big enough to hold the new system
|
// We must ensure that the vector is big enough to hold the new system
|
||||||
if (index >= m_systems.size())
|
if (index >= m_systems.size())
|
||||||
|
{
|
||||||
m_systems.resize(index + 1);
|
m_systems.resize(index + 1);
|
||||||
|
m_profilerData.updateTime.resize(index + 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Affectation and return of system
|
// Affectation and return of system
|
||||||
m_systems[index] = std::move(system);
|
m_systems[index] = std::move(system);
|
||||||
|
|
@ -82,7 +87,6 @@ namespace Ndk
|
||||||
*
|
*
|
||||||
* \param count Number of entities to create
|
* \param count Number of entities to create
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline World::EntityVector World::CreateEntities(unsigned int count)
|
inline World::EntityVector World::CreateEntities(unsigned int count)
|
||||||
{
|
{
|
||||||
EntityVector list;
|
EntityVector list;
|
||||||
|
|
@ -94,16 +98,79 @@ namespace Ndk
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Disables the profiler, clearing up results
|
||||||
|
*
|
||||||
|
* This is just a shortcut to EnableProfiler(false)
|
||||||
|
*
|
||||||
|
* \param enable Should the entity be enabled
|
||||||
|
*
|
||||||
|
* \see EnableProfiler
|
||||||
|
*/
|
||||||
|
inline void World::DisableProfiler()
|
||||||
|
{
|
||||||
|
EnableProfiler(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Enables/Disables the internal profiler
|
||||||
|
*
|
||||||
|
* Worlds come with a built-in profiler, allowing to measure update count along with time passed in refresh and system updates.
|
||||||
|
* This is disabled by default as it adds an small overhead to the update process.
|
||||||
|
*
|
||||||
|
* \param enable Should the profiler be enabled
|
||||||
|
*
|
||||||
|
* \remark Disabling the profiler clears up results, as if ResetProfiler has been called
|
||||||
|
*/
|
||||||
|
inline void World::EnableProfiler(bool enable)
|
||||||
|
{
|
||||||
|
if (m_isProfilerEnabled != enable)
|
||||||
|
{
|
||||||
|
m_isProfilerEnabled = enable;
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
ResetProfiler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Gets an entity
|
||||||
|
* \return A constant reference to a handle of the entity
|
||||||
|
*
|
||||||
|
* \param id Identifier of the entity
|
||||||
|
*
|
||||||
|
* \remark Handle referenced by this function can move in memory when updating the world, do not keep a handle reference from a world update to another
|
||||||
|
* \remark If an invalid identifier is provided, an error got triggered and an invalid handle is returned
|
||||||
|
*/
|
||||||
|
inline const EntityHandle& World::GetEntity(EntityId id)
|
||||||
|
{
|
||||||
|
if (IsEntityIdValid(id))
|
||||||
|
return m_entityBlocks[id]->handle;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NazaraError("Invalid ID");
|
||||||
|
return EntityHandle::InvalidHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets every entities in the world
|
* \brief Gets every entities in the world
|
||||||
* \return A constant reference to the entities
|
* \return A constant reference to the entities
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline const EntityList& World::GetEntities() const
|
inline const EntityList& World::GetEntities() const
|
||||||
{
|
{
|
||||||
return m_aliveEntities;
|
return m_aliveEntities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Gets the latest profiler data
|
||||||
|
* \return A constant reference to the profiler data
|
||||||
|
*/
|
||||||
|
inline const World::ProfilerData& World::GetProfilerData() const
|
||||||
|
{
|
||||||
|
return m_profilerData;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets a system in the world by index
|
* \brief Gets a system in the world by index
|
||||||
* \return A reference to the system
|
* \return A reference to the system
|
||||||
|
|
@ -192,26 +259,6 @@ namespace Ndk
|
||||||
KillEntity(entity);
|
KillEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Gets an entity
|
|
||||||
* \return A constant reference to a handle of the entity
|
|
||||||
*
|
|
||||||
* \param id Identifier of the entity
|
|
||||||
*
|
|
||||||
* \remark Handle referenced by this function can move in memory when updating the world, do not keep a handle reference from a world update to another
|
|
||||||
* \remark If an invalid identifier is provided, an error got triggered and an invalid handle is returned
|
|
||||||
*/
|
|
||||||
inline const EntityHandle& World::GetEntity(EntityId id)
|
|
||||||
{
|
|
||||||
if (IsEntityIdValid(id))
|
|
||||||
return m_entityBlocks[id]->handle;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NazaraError("Invalid ID");
|
|
||||||
return EntityHandle::InvalidHandle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Checks whether or not an entity is valid
|
* \brief Checks whether or not an entity is valid
|
||||||
* \return true If it is the case
|
* \return true If it is the case
|
||||||
|
|
@ -230,12 +277,22 @@ namespace Ndk
|
||||||
*
|
*
|
||||||
* \param id Identifier of the entity
|
* \param id Identifier of the entity
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline bool World::IsEntityIdValid(EntityId id) const
|
inline bool World::IsEntityIdValid(EntityId id) const
|
||||||
{
|
{
|
||||||
return id < m_entityBlocks.size() && m_entityBlocks[id]->entity.IsValid();
|
return id < m_entityBlocks.size() && m_entityBlocks[id]->entity.IsValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Checks whether or not the profiler is enabled
|
||||||
|
* \return true If it is the case
|
||||||
|
*
|
||||||
|
* \see EnableProfiler
|
||||||
|
*/
|
||||||
|
inline bool World::IsProfilerEnabled() const
|
||||||
|
{
|
||||||
|
return m_isProfilerEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Removes each system from the world
|
* \brief Removes each system from the world
|
||||||
*/
|
*/
|
||||||
|
|
@ -265,10 +322,21 @@ namespace Ndk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Clear profiler results
|
||||||
|
*
|
||||||
|
* This reset the profiler results, filling all counters with zero
|
||||||
|
*/
|
||||||
|
inline void World::ResetProfiler()
|
||||||
|
{
|
||||||
|
m_profilerData.refreshTime = 0;
|
||||||
|
m_profilerData.updateCount = 0;
|
||||||
|
std::fill(m_profilerData.updateTime.begin(), m_profilerData.updateTime.end(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Removes a system from the world by type
|
* \brief Removes a system from the world by type
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename SystemType>
|
template<typename SystemType>
|
||||||
void World::RemoveSystem()
|
void World::RemoveSystem()
|
||||||
{
|
{
|
||||||
|
|
@ -292,6 +360,8 @@ namespace Ndk
|
||||||
m_killedEntities = std::move(world.m_killedEntities);
|
m_killedEntities = std::move(world.m_killedEntities);
|
||||||
m_orderedSystems = std::move(world.m_orderedSystems);
|
m_orderedSystems = std::move(world.m_orderedSystems);
|
||||||
m_orderedSystemsUpdated = world.m_orderedSystemsUpdated;
|
m_orderedSystemsUpdated = world.m_orderedSystemsUpdated;
|
||||||
|
m_profilerData = std::move(world.m_profilerData);
|
||||||
|
m_isProfilerEnabled = m_isProfilerEnabled;
|
||||||
|
|
||||||
m_entities = std::move(world.m_entities);
|
m_entities = std::move(world.m_entities);
|
||||||
for (EntityBlock& block : m_entities)
|
for (EntityBlock& block : m_entities)
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,10 @@ namespace Ndk
|
||||||
world.BindMethod("CreateEntity", &World::CreateEntity);
|
world.BindMethod("CreateEntity", &World::CreateEntity);
|
||||||
world.BindMethod("CreateEntities", &World::CreateEntities);
|
world.BindMethod("CreateEntities", &World::CreateEntities);
|
||||||
world.BindMethod("Clear", &World::Clear);
|
world.BindMethod("Clear", &World::Clear);
|
||||||
|
world.BindMethod("DisableProfiler", &World::DisableProfiler);
|
||||||
|
world.BindMethod("EnableProfiler", &World::EnableProfiler);
|
||||||
|
world.BindMethod("IsProfilerEnabled", &World::IsProfilerEnabled);
|
||||||
|
world.BindMethod("ResetProfiler", &World::ResetProfiler);
|
||||||
|
|
||||||
world.BindMethod("IsValidHandle", &WorldHandle::IsValid);
|
world.BindMethod("IsValidHandle", &WorldHandle::IsValid);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||||
|
|
||||||
#include <NDK/World.hpp>
|
#include <NDK/World.hpp>
|
||||||
|
#include <Nazara/Core/Clock.hpp>
|
||||||
#include <Nazara/Core/Error.hpp>
|
#include <Nazara/Core/Error.hpp>
|
||||||
#include <NDK/BaseComponent.hpp>
|
#include <NDK/BaseComponent.hpp>
|
||||||
#include <NDK/Systems/PhysicsSystem2D.hpp>
|
#include <NDK/Systems/PhysicsSystem2D.hpp>
|
||||||
|
|
@ -177,6 +178,10 @@ namespace Ndk
|
||||||
* - Destroying dead entities and allowing their ids to be used by newly created entities
|
* - Destroying dead entities and allowing their ids to be used by newly created entities
|
||||||
* - Update dirty entities, destroying their removed components and filtering them along systems
|
* - Update dirty entities, destroying their removed components and filtering them along systems
|
||||||
*
|
*
|
||||||
|
* \remark Calling this outside of Update will not increase the profiler values
|
||||||
|
*
|
||||||
|
* \see GetProfilerData
|
||||||
|
* \see Update
|
||||||
*/
|
*/
|
||||||
void World::Refresh()
|
void World::Refresh()
|
||||||
{
|
{
|
||||||
|
|
@ -257,17 +262,40 @@ namespace Ndk
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Updates the world
|
* \brief Updates the world
|
||||||
*
|
|
||||||
* \param elapsedTime Delta time used for the update
|
* \param elapsedTime Delta time used for the update
|
||||||
|
*
|
||||||
|
* This function Refreshes the world and calls the Update function of every active system part of it with the elapsedTime value.
|
||||||
|
* It also increase the profiler data with the elapsed time passed in Refresh and every system update.
|
||||||
*/
|
*/
|
||||||
void World::Update(float elapsedTime)
|
void World::Update(float elapsedTime)
|
||||||
{
|
{
|
||||||
Refresh(); //< Update entities
|
if (m_isProfilerEnabled)
|
||||||
|
{
|
||||||
|
Nz::UInt64 t1 = Nz::GetElapsedMicroseconds();
|
||||||
|
Refresh();
|
||||||
|
Nz::UInt64 t2 = Nz::GetElapsedMicroseconds();
|
||||||
|
|
||||||
|
m_profilerData.refreshTime += t2 - t1;
|
||||||
|
|
||||||
|
for (auto& systemPtr : m_orderedSystems)
|
||||||
|
{
|
||||||
|
systemPtr->Update(elapsedTime);
|
||||||
|
|
||||||
|
Nz::UInt64 t3 = Nz::GetElapsedMicroseconds();
|
||||||
|
m_profilerData.updateTime[systemPtr->GetIndex()] += t3 - t2;
|
||||||
|
t2 = t3;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_profilerData.updateCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Refresh();
|
||||||
|
|
||||||
// And then update systems
|
|
||||||
for (auto& systemPtr : m_orderedSystems)
|
for (auto& systemPtr : m_orderedSystems)
|
||||||
systemPtr->Update(elapsedTime);
|
systemPtr->Update(elapsedTime);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void World::ReorderSystems()
|
void World::ReorderSystems()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue