diff --git a/apps/benchmarks/detournavigator/navmeshtilescache.cpp b/apps/benchmarks/detournavigator/navmeshtilescache.cpp index 49b079681e..a0c204dc6c 100644 --- a/apps/benchmarks/detournavigator/navmeshtilescache.cpp +++ b/apps/benchmarks/detournavigator/navmeshtilescache.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 006825e3e6..3af60c3420 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -3992,7 +3993,7 @@ namespace MWWorld void World::reportStats(unsigned int frameNumber, osg::Stats& stats) const { - mNavigator->reportStats(frameNumber, stats); + DetourNavigator::reportStats(mNavigator->getStats(), frameNumber, stats); mPhysics->reportStats(frameNumber, stats); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a7b3e87f03..9dc752e4aa 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -316,6 +316,7 @@ add_component_dir(detournavigator recast gettilespositions collisionshapetype + stats ) add_component_dir(loadinglistener diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index f1af3fc614..ea69a9b32e 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -15,7 +15,6 @@ #include -#include #include #include @@ -111,6 +110,11 @@ namespace DetourNavigator static std::atomic_size_t nextJobId {1}; return nextJobId.fetch_add(1); } + + bool isWritingDbJob(const Job& job) + { + return job.mGeneratedNavMeshData != nullptr; + } } std::ostream& operator<<(std::ostream& stream, JobStatus value) @@ -302,9 +306,9 @@ namespace DetourNavigator mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); }); } - AsyncNavMeshUpdater::Stats AsyncNavMeshUpdater::getStats() const + AsyncNavMeshUpdaterStats AsyncNavMeshUpdater::getStats() const { - Stats result; + AsyncNavMeshUpdaterStats result; { const std::lock_guard lock(mMutex); result.mJobs = mJobs.size(); @@ -319,25 +323,6 @@ namespace DetourNavigator return result; } - void reportStats(const AsyncNavMeshUpdater::Stats& stats, unsigned int frameNumber, osg::Stats& out) - { - out.setAttribute(frameNumber, "NavMesh Jobs", static_cast(stats.mJobs)); - out.setAttribute(frameNumber, "NavMesh Waiting", static_cast(stats.mWaiting)); - out.setAttribute(frameNumber, "NavMesh Pushed", static_cast(stats.mPushed)); - out.setAttribute(frameNumber, "NavMesh Processing", static_cast(stats.mProcessing)); - - if (stats.mDb.has_value()) - { - out.setAttribute(frameNumber, "NavMesh DbJobs", static_cast(stats.mDb->mJobs)); - - if (stats.mDb->mGetTileCount > 0) - out.setAttribute(frameNumber, "NavMesh DbCacheHitRate", static_cast(stats.mDbGetTileHits) - / static_cast(stats.mDb->mGetTileCount) * 100.0); - } - - reportStats(stats.mCache, frameNumber, out); - } - void AsyncNavMeshUpdater::process() noexcept { Log(Debug::Debug) << "Start process navigator jobs by thread=" << std::this_thread::get_id(); @@ -690,6 +675,10 @@ namespace DetourNavigator { const std::lock_guard lock(mMutex); insertPrioritizedDbJob(job, mJobs); + if (isWritingDbJob(*job)) + ++mWritingJobs; + else + ++mReadingJobs; mHasJob.notify_all(); } @@ -701,6 +690,10 @@ namespace DetourNavigator return std::nullopt; const JobIt job = mJobs.front(); mJobs.pop_front(); + if (isWritingDbJob(*job)) + --mWritingJobs; + else + --mReadingJobs; return job; } @@ -719,10 +712,10 @@ namespace DetourNavigator mHasJob.notify_all(); } - std::size_t DbJobQueue::size() const + DbJobQueueStats DbJobQueue::getStats() const { const std::lock_guard lock(mMutex); - return mJobs.size(); + return DbJobQueueStats {.mWritingJobs = mWritingJobs, .mReadingJobs = mReadingJobs}; } DbWorker::DbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr&& db, @@ -749,12 +742,12 @@ namespace DetourNavigator mQueue.push(job); } - DbWorker::Stats DbWorker::getStats() const + DbWorkerStats DbWorker::getStats() const { - Stats result; - result.mJobs = mQueue.size(); - result.mGetTileCount = mGetTileCount.load(std::memory_order_relaxed); - return result; + return DbWorkerStats { + .mJobs = mQueue.getStats(), + .mGetTileCount = mGetTileCount.load(std::memory_order_relaxed) + }; } void DbWorker::stop() @@ -809,7 +802,7 @@ namespace DetourNavigator } }; - if (job->mGeneratedNavMeshData != nullptr) + if (isWritingDbJob(*job)) { process([&] (JobIt job) { processWritingJob(job); }); mUpdater.removeJob(job); diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index f9fadde4f6..541e39f18c 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -12,6 +12,7 @@ #include "agentbounds.hpp" #include "guardednavmeshcacheitem.hpp" #include "sharednavmeshcacheitem.hpp" +#include "stats.hpp" #include @@ -88,13 +89,15 @@ namespace DetourNavigator void stop(); - std::size_t size() const; + DbJobQueueStats getStats() const; private: mutable std::mutex mMutex; std::condition_variable mHasJob; std::deque mJobs; bool mShouldStop = false; + std::size_t mWritingJobs = 0; + std::size_t mReadingJobs = 0; }; class AsyncNavMeshUpdater; @@ -102,18 +105,12 @@ namespace DetourNavigator class DbWorker { public: - struct Stats - { - std::size_t mJobs = 0; - std::size_t mGetTileCount = 0; - }; - DbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr&& db, TileVersion version, const RecastSettings& recastSettings, bool writeToDb); ~DbWorker(); - Stats getStats() const; + DbWorkerStats getStats() const; void enqueueJob(JobIt job); @@ -146,17 +143,6 @@ namespace DetourNavigator class AsyncNavMeshUpdater { public: - struct Stats - { - std::size_t mJobs = 0; - std::size_t mWaiting = 0; - std::size_t mPushed = 0; - std::size_t mProcessing = 0; - std::size_t mDbGetTileHits = 0; - std::optional mDb; - NavMeshTilesCache::Stats mCache; - }; - AsyncNavMeshUpdater(const Settings& settings, TileCachedRecastMeshManager& recastMeshManager, OffMeshConnectionsManager& offMeshConnectionsManager, std::unique_ptr&& db); ~AsyncNavMeshUpdater(); @@ -169,7 +155,7 @@ namespace DetourNavigator void stop(); - Stats getStats() const; + AsyncNavMeshUpdaterStats getStats() const; void enqueueJob(JobIt job); @@ -227,8 +213,6 @@ namespace DetourNavigator inline void waitUntilAllJobsDone(); }; - - void reportStats(const AsyncNavMeshUpdater::Stats& stats, unsigned int frameNumber, osg::Stats& out); } #endif diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index 59fa28b908..c110fd3eb2 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -23,15 +23,11 @@ namespace Loading class Listener; } -namespace osg -{ - class Stats; -} - namespace DetourNavigator { struct Settings; struct AgentBounds; + struct Stats; struct ObjectShapes { @@ -181,7 +177,7 @@ namespace DetourNavigator virtual const Settings& getSettings() const = 0; - virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0; + virtual Stats getStats() const = 0; virtual RecastMeshTiles getRecastMeshTiles() const = 0; diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 838ed8c0b7..0211d3dd50 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -1,5 +1,6 @@ #include "navigatorimpl.hpp" #include "settingsutils.hpp" +#include "stats.hpp" #include #include @@ -173,9 +174,9 @@ namespace DetourNavigator return mSettings; } - void NavigatorImpl::reportStats(unsigned int frameNumber, osg::Stats& stats) const + Stats NavigatorImpl::getStats() const { - mNavMeshManager.reportStats(frameNumber, stats); + return mNavMeshManager.getStats(); } RecastMeshTiles NavigatorImpl::getRecastMeshTiles() const diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index ff324280a6..f671c7e9bd 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -58,7 +58,7 @@ namespace DetourNavigator const Settings& getSettings() const override; - void reportStats(unsigned int frameNumber, osg::Stats& stats) const override; + Stats getStats() const override; RecastMeshTiles getRecastMeshTiles() const override; diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index fec6e8f04c..771df43f64 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -3,6 +3,7 @@ #include "navigator.hpp" #include "settings.hpp" +#include "stats.hpp" namespace Loading { @@ -66,7 +67,7 @@ namespace DetourNavigator return mDefaultSettings; } - void reportStats(unsigned int /*frameNumber*/, osg::Stats& /*stats*/) const override {} + Stats getStats() const override { return Stats {}; } RecastMeshTiles getRecastMeshTiles() const override { diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 0e1dc591a3..811e97d826 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -268,9 +268,9 @@ namespace DetourNavigator return mCache; } - void NavMeshManager::reportStats(unsigned int frameNumber, osg::Stats& stats) const + Stats NavMeshManager::getStats() const { - DetourNavigator::reportStats(mAsyncNavMeshUpdater.getStats(), frameNumber, stats); + return Stats {.mUpdater = mAsyncNavMeshUpdater.getStats()}; } RecastMeshTiles NavMeshManager::getRecastMeshTiles() const diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index 7a9a1e2ba4..c479834aa8 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -58,7 +58,7 @@ namespace DetourNavigator std::map getNavMeshes() const; - void reportStats(unsigned int frameNumber, osg::Stats& stats) const; + Stats getStats() const; RecastMeshTiles getRecastMeshTiles() const; diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index a07aa873c4..0f6725cc72 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -1,6 +1,5 @@ #include "navmeshtilescache.hpp" - -#include +#include "stats.hpp" #include @@ -65,9 +64,9 @@ namespace DetourNavigator return Value(*this, iterator); } - NavMeshTilesCache::Stats NavMeshTilesCache::getStats() const + NavMeshTilesCacheStats NavMeshTilesCache::getStats() const { - Stats result; + NavMeshTilesCacheStats result; { const std::lock_guard lock(mMutex); result.mNavMeshCacheSize = mUsedNavMeshDataSize; @@ -79,15 +78,6 @@ namespace DetourNavigator return result; } - void reportStats(const NavMeshTilesCache::Stats& stats, unsigned int frameNumber, osg::Stats& out) - { - out.setAttribute(frameNumber, "NavMesh CacheSize", static_cast(stats.mNavMeshCacheSize)); - out.setAttribute(frameNumber, "NavMesh UsedTiles", static_cast(stats.mUsedNavMeshTiles)); - out.setAttribute(frameNumber, "NavMesh CachedTiles", static_cast(stats.mCachedNavMeshTiles)); - if (stats.mGetCount > 0) - out.setAttribute(frameNumber, "NavMesh CacheHitRate", static_cast(stats.mHitCount) / stats.mGetCount * 100.0); - } - void NavMeshTilesCache::removeLeastRecentlyUsed() { const auto& item = mFreeItems.back(); diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index 572f7fdb4b..458f900854 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -14,11 +14,6 @@ #include #include -namespace osg -{ - class Stats; -} - namespace DetourNavigator { struct RecastMeshData @@ -47,6 +42,8 @@ namespace DetourNavigator < std::tie(rhs.mMesh, rhs.mWater, rhs.mHeightfields, rhs.mFlatHeightfields); } + struct NavMeshTilesCacheStats; + class NavMeshTilesCache { public: @@ -126,15 +123,6 @@ namespace DetourNavigator ItemIterator mIterator; }; - struct Stats - { - std::size_t mNavMeshCacheSize; - std::size_t mUsedNavMeshTiles; - std::size_t mCachedNavMeshTiles; - std::size_t mHitCount; - std::size_t mGetCount; - }; - NavMeshTilesCache(const std::size_t maxNavMeshDataSize); Value get(const AgentBounds& agentBounds, const TilePosition& changedTile, @@ -143,7 +131,7 @@ namespace DetourNavigator Value set(const AgentBounds& agentBounds, const TilePosition& changedTile, const RecastMesh& recastMesh, std::unique_ptr&& value); - Stats getStats() const; + NavMeshTilesCacheStats getStats() const; private: mutable std::mutex mMutex; @@ -162,8 +150,6 @@ namespace DetourNavigator void releaseItem(ItemIterator iterator); }; - - void reportStats(const NavMeshTilesCache::Stats& stats, unsigned int frameNumber, osg::Stats& out); } #endif diff --git a/components/detournavigator/stats.cpp b/components/detournavigator/stats.cpp new file mode 100644 index 0000000000..6150210c16 --- /dev/null +++ b/components/detournavigator/stats.cpp @@ -0,0 +1,40 @@ +#include "stats.hpp" + +#include + +namespace DetourNavigator +{ + namespace + { + void reportStats(const AsyncNavMeshUpdaterStats& stats, unsigned int frameNumber, osg::Stats& out) + { + out.setAttribute(frameNumber, "NavMesh Jobs", static_cast(stats.mJobs)); + out.setAttribute(frameNumber, "NavMesh Waiting", static_cast(stats.mWaiting)); + out.setAttribute(frameNumber, "NavMesh Pushed", static_cast(stats.mPushed)); + out.setAttribute(frameNumber, "NavMesh Processing", static_cast(stats.mProcessing)); + + if (stats.mDb.has_value()) + { + out.setAttribute(frameNumber, "NavMesh DbJobs Write", static_cast(stats.mDb->mJobs.mWritingJobs)); + out.setAttribute(frameNumber, "NavMesh DbJobs Read", static_cast(stats.mDb->mJobs.mReadingJobs)); + + if (stats.mDb->mGetTileCount > 0) + out.setAttribute(frameNumber, "NavMesh DbCacheHitRate", static_cast(stats.mDbGetTileHits) + / static_cast(stats.mDb->mGetTileCount) * 100.0); + } + + out.setAttribute(frameNumber, "NavMesh CacheSize", static_cast(stats.mCache.mNavMeshCacheSize)); + out.setAttribute(frameNumber, "NavMesh UsedTiles", static_cast(stats.mCache.mUsedNavMeshTiles)); + out.setAttribute(frameNumber, "NavMesh CachedTiles", static_cast(stats.mCache.mCachedNavMeshTiles)); + if (stats.mCache.mGetCount > 0) + out.setAttribute(frameNumber, "NavMesh CacheHitRate", static_cast(stats.mCache.mHitCount) + / stats.mCache.mGetCount * 100.0); + } + } + + void reportStats(const Stats& stats, unsigned int frameNumber, osg::Stats& out) + { + if (stats.mUpdater.has_value()) + reportStats(*stats.mUpdater, frameNumber, out); + } +} diff --git a/components/detournavigator/stats.hpp b/components/detournavigator/stats.hpp new file mode 100644 index 0000000000..c644f1db87 --- /dev/null +++ b/components/detournavigator/stats.hpp @@ -0,0 +1,54 @@ +#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_STATS_H +#define OPENMW_COMPONENTS_DETOURNAVIGATOR_STATS_H + +#include +#include + +namespace osg +{ + class Stats; +} + +namespace DetourNavigator +{ + struct DbJobQueueStats + { + std::size_t mWritingJobs = 0; + std::size_t mReadingJobs = 0; + }; + + struct DbWorkerStats + { + DbJobQueueStats mJobs; + std::size_t mGetTileCount = 0; + }; + + struct NavMeshTilesCacheStats + { + std::size_t mNavMeshCacheSize = 0; + std::size_t mUsedNavMeshTiles = 0; + std::size_t mCachedNavMeshTiles = 0; + std::size_t mHitCount = 0; + std::size_t mGetCount = 0; + }; + + struct AsyncNavMeshUpdaterStats + { + std::size_t mJobs = 0; + std::size_t mWaiting = 0; + std::size_t mPushed = 0; + std::size_t mProcessing = 0; + std::size_t mDbGetTileHits = 0; + std::optional mDb; + NavMeshTilesCacheStats mCache; + }; + + struct Stats + { + std::optional mUpdater; + }; + + void reportStats(const Stats& stats, unsigned int frameNumber, osg::Stats& out); +} + +#endif diff --git a/components/resource/stats.cpp b/components/resource/stats.cpp index c5229f491a..b92f9d8bdf 100644 --- a/components/resource/stats.cpp +++ b/components/resource/stats.cpp @@ -439,7 +439,8 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) "NavMesh Waiting", "NavMesh Pushed", "NavMesh Processing", - "NavMesh DbJobs", + "NavMesh DbJobs Write", + "NavMesh DbJobs Read", "NavMesh DbCacheHitRate", "NavMesh CacheSize", "NavMesh UsedTiles",