From ee3c3d0965df789bcda7d6b07cb501027b97555b Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 12 May 2020 17:55:39 -0700 Subject: [PATCH] debug option to track Entities (#2526) * debug option to track Entities Set FILAMENT_UTILS_TRACK_ENTITIES to true when building libutils to activate entity tracking. This adds two public methods: getActiveEntities() and dumpActiveEntities() the later displays the stack trace of where the remaining entities were allocated. This is useful for tracking leaks. * Update libs/utils/include/utils/EntityManager.h Co-authored-by: Philip Rideout Co-authored-by: Philip Rideout --- libs/utils/include/utils/EntityManager.h | 17 ++++++++++-- libs/utils/src/EntityManager.cpp | 15 ++++++++++ libs/utils/src/EntityManagerImpl.h | 35 ++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/libs/utils/include/utils/EntityManager.h b/libs/utils/include/utils/EntityManager.h index 8b3d9662a0..f44f6c2834 100644 --- a/libs/utils/include/utils/EntityManager.h +++ b/libs/utils/include/utils/EntityManager.h @@ -23,6 +23,15 @@ #include #include +#ifndef FILAMENT_UTILS_TRACK_ENTITIES +#define FILAMENT_UTILS_TRACK_ENTITIES false +#endif + +#if FILAMENT_UTILS_TRACK_ENTITIES +#include +#include +#endif + namespace utils { class UTILS_PUBLIC EntityManager { @@ -34,9 +43,8 @@ public: class Listener { public: virtual void onEntitiesDestroyed(size_t n, Entity const* entities) noexcept = 0; - virtual void onAllEntitiesDestroyed() noexcept = 0; protected: - ~Listener() noexcept = default; + ~Listener() noexcept; }; @@ -90,6 +98,11 @@ public: EntityManager(const EntityManager& rhs) = delete; EntityManager& operator=(const EntityManager& rhs) = delete; +#if FILAMENT_UTILS_TRACK_ENTITIES + std::vector getActiveEntities() const; + void dumpActiveEntities(utils::io::ostream& out) const; +#endif + private: friend class EntityManagerImpl; EntityManager(); diff --git a/libs/utils/src/EntityManager.cpp b/libs/utils/src/EntityManager.cpp index 6ed41cb2b0..733eb4ec72 100644 --- a/libs/utils/src/EntityManager.cpp +++ b/libs/utils/src/EntityManager.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #include "EntityManagerImpl.h" namespace utils { @@ -28,6 +30,8 @@ EntityManager::~EntityManager() { delete [] mGens; } +EntityManager::Listener::~Listener() noexcept = default; + EntityManager& EntityManager::get() noexcept { // note: we leak the EntityManager because it's more important that it survives everything else // the leak is really not a problem because the process is terminating anyways. @@ -51,4 +55,15 @@ void EntityManager::unregisterListener(EntityManager::Listener* l) noexcept { static_cast(this)->unregisterListener(l); } +#if FILAMENT_UTILS_TRACK_ENTITIES +std::vector EntityManager::getActiveEntities() const { + return static_cast(this)->getActiveEntities(); +} + +void EntityManager::dumpActiveEntities(utils::io::ostream& out) const { + static_cast(this)->dumpActiveEntities(out); +} + +#endif + } // namespace utils diff --git a/libs/utils/src/EntityManagerImpl.h b/libs/utils/src/EntityManagerImpl.h index b93279a4f4..4916716888 100644 --- a/libs/utils/src/EntityManagerImpl.h +++ b/libs/utils/src/EntityManagerImpl.h @@ -22,9 +22,14 @@ #include #include #include +#include #include +#if FILAMENT_UTILS_TRACK_ENTITIES +#include +#endif + #include #include // for std::lock_guard #include @@ -73,6 +78,9 @@ public: index = currentIndex++; } entities[i] = Entity{ makeIdentity(gens[index], index) }; +#if FILAMENT_UTILS_TRACK_ENTITIES + mDebugActiveEntities.emplace(entities[i], CallStack::unwind(5)); +#endif } mCurrentIndex = currentIndex; } @@ -103,6 +111,10 @@ public: // true a little longer than expected in some other threads. // We do need a memory fence though, it is provided by the mFreeListLock.unlock() below. gens[index]++; + +#if FILAMENT_UTILS_TRACK_ENTITIES + mDebugActiveEntities.erase(entities[i]); +#endif } } lock.unlock(); @@ -135,6 +147,25 @@ public: return result; // the c++ standard guarantees a move } +#if FILAMENT_UTILS_TRACK_ENTITIES + std::vector getActiveEntities() const { + std::vector result(mDebugActiveEntities.size()); + auto p = result.begin(); + for (auto i : mDebugActiveEntities) { + *p++ = i.first; + } + return result; + } + + void dumpActiveEntities(utils::io::ostream& out) const { + for (auto i : mDebugActiveEntities) { + out << "*** Entity " << i.first.getId() << " was allocated at:\n"; + out << i.second; + out << io::endl; + } + } +#endif + private: uint32_t mCurrentIndex = 1; @@ -144,6 +175,10 @@ private: mutable Mutex mListenerLock; tsl::robin_set mListeners; + +#if FILAMENT_UTILS_TRACK_ENTITIES + tsl::robin_map mDebugActiveEntities; +#endif }; } // namespace utils