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 <philiprideout@gmail.com>

Co-authored-by: Philip Rideout <philiprideout@gmail.com>
This commit is contained in:
Mathias Agopian
2020-05-12 17:55:39 -07:00
committed by GitHub
co-authored by Philip Rideout
parent d08a4e8bd9
commit ee3c3d0965
3 changed files with 65 additions and 2 deletions
+15 -2
View File
@@ -23,6 +23,15 @@
#include <utils/Entity.h>
#include <utils/compiler.h>
#ifndef FILAMENT_UTILS_TRACK_ENTITIES
#define FILAMENT_UTILS_TRACK_ENTITIES false
#endif
#if FILAMENT_UTILS_TRACK_ENTITIES
#include <utils/ostream.h>
#include <vector>
#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<Entity> getActiveEntities() const;
void dumpActiveEntities(utils::io::ostream& out) const;
#endif
private:
friend class EntityManagerImpl;
EntityManager();
+15
View File
@@ -14,6 +14,8 @@
* limitations under the License.
*/
#include <utils/EntityManager.h>
#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<EntityManagerImpl *>(this)->unregisterListener(l);
}
#if FILAMENT_UTILS_TRACK_ENTITIES
std::vector<Entity> EntityManager::getActiveEntities() const {
return static_cast<EntityManagerImpl const *>(this)->getActiveEntities();
}
void EntityManager::dumpActiveEntities(utils::io::ostream& out) const {
static_cast<EntityManagerImpl const *>(this)->dumpActiveEntities(out);
}
#endif
} // namespace utils
+35
View File
@@ -22,9 +22,14 @@
#include <utils/compiler.h>
#include <utils/Entity.h>
#include <utils/Mutex.h>
#include <utils/CallStack.h>
#include <tsl/robin_set.h>
#if FILAMENT_UTILS_TRACK_ENTITIES
#include <tsl/robin_map.h>
#endif
#include <deque>
#include <mutex> // for std::lock_guard
#include <vector>
@@ -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<Entity> getActiveEntities() const {
std::vector<Entity> 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<Listener*> mListeners;
#if FILAMENT_UTILS_TRACK_ENTITIES
tsl::robin_map<Entity, CallStack> mDebugActiveEntities;
#endif
};
} // namespace utils