#pragma once #if FC_PROFILER #include "types.h" #include #include #include #include #include #ifndef __PRETTY_FUNCTION__ #ifdef _MSC_VER #define __PRETTY_FUNCTION__ __FUNCSIG__ #else #define __PRETTY_FUNCTION__ __func__ #endif #endif #define FC_PROFILE_SCOPE_RESERVE_SIZE 128 #define FC_PROFILE_HISTORY_MAX_SIZE 512 namespace fc_profiler { struct ProfileSection { ProfileSection() : function(nullptr) , file(nullptr) , line(0) , scope(0) { } ProfileSection(const char* _function, const char* _file, u32 _line, u32 _scope) : function(_function) , file(_file) , line(_line) , scope(_scope) { } const char* function; const char* file; u32 line; u32 scope; std::chrono::high_resolution_clock::time_point start; std::chrono::high_resolution_clock::time_point end; }; struct ProfileThread { ProfileThread() { startTicks = std::chrono::high_resolution_clock::now(); level = 0; historyIdx = 0; cachedTime = 0.0; scopes.reserve(FC_PROFILE_SCOPE_RESERVE_SIZE); memset(history, 0, sizeof(history)); } std::vector scopes; std::chrono::high_resolution_clock::time_point startTicks; std::chrono::high_resolution_clock::time_point endTicks; double history[FC_PROFILE_HISTORY_MAX_SIZE]; u32 level; u32 historyIdx; std::thread::id threadId; std::string threadName; struct ResultNode { ResultNode() : parent(nullptr) {} ProfileSection section; ResultNode* parent; std::vector children; }; double cachedTime; std::vector cachedResultTree; static std::vector s_allThreads; static std::recursive_mutex s_allThreadsLock; }; struct ProfileScope { ProfileScope(const char* function, const char* file, int line) : sectionIdx(0) { if (s_thread) { ProfileSection section(function, file, line, s_thread->level++); section.start = std::chrono::high_resolution_clock::now(); sectionIdx = s_thread->scopes.size(); s_thread->scopes.push_back(section); } } ~ProfileScope() { if (s_thread) { s_thread->scopes[sectionIdx].end = std::chrono::high_resolution_clock::now(); s_thread->level--; } } size_t sectionIdx; static thread_local ProfileThread* s_thread; }; void startThread(const std::string& threadName); void endThread(double warningTime = 0.0); void drawGUI(const std::vector& results); void drawGraph(const ProfileThread& profileThread); void outputTTY(const std::vector& results); } #define FC_PROFILE_SCOPE \ fc_profiler::ProfileScope __profile__scope(__PRETTY_FUNCTION__, __FILE__, __LINE__); #define FC_PROFILE_SCOPE_NAMED(name) \ fc_profiler::ProfileScope __profile__scope(name, __FILE__, __LINE__); #else namespace fc_profiler { inline static void startThread(const std::string& threadName) {} inline static void endThread(float warningTime = 0.0) {} } #define FC_PROFILE_SCOPE #define FC_PROFILE_SCOPE_NAMED(name) #endif