#pragma once #include #include #include #include namespace frostbite2D { class StartupTrace { public: static constexpr bool enabled() { #ifndef NDEBUG return true; #else return false; #endif } static void reset(const char* label = nullptr) { if (!enabled()) { return; } Uint64 now = SDL_GetPerformanceCounter(); std::string line; { std::lock_guard lock(mutex()); startCounter() = now; if (label && label[0] != '\0') { line = std::string("[Startup] reset: ") + label; clearLogFileUnlocked(); writeLineUnlocked(line); } else { clearLogFileUnlocked(); } } if (!line.empty()) { SDL_Log("%s", line.c_str()); } } static double totalElapsedMs() { if (!enabled()) { return 0.0; } Uint64 start = 0; { std::lock_guard lock(mutex()); start = startCounter(); } if (start == 0) { return 0.0; } Uint64 now = SDL_GetPerformanceCounter(); Uint64 frequency = SDL_GetPerformanceFrequency(); if (frequency == 0) { return 0.0; } return static_cast(now - start) * 1000.0 / static_cast(frequency); } static void mark(const char* label) { if (!enabled()) { return; } char buffer[256] = {}; SDL_snprintf(buffer, sizeof(buffer), "[Startup] %s reached at %.2f ms (thread=%u)", label ? label : "", totalElapsedMs(), SDL_ThreadID()); logLine(buffer); SDL_Log("%s", buffer); } static void logLine(const std::string& line) { if (!enabled()) { return; } std::lock_guard lock(mutex()); writeLineUnlocked(line); } private: static Uint64& startCounter() { static Uint64 counter = 0; return counter; } static std::mutex& mutex() { static std::mutex value; return value; } static const char* logFilePath() { return "startup_trace.log"; } static void clearLogFileUnlocked() { std::ofstream stream(logFilePath(), std::ios::trunc); } static void writeLineUnlocked(const std::string& line) { std::ofstream stream(logFilePath(), std::ios::app); if (!stream) { return; } stream << line << '\n'; } }; class ScopedStartupTrace { public: explicit ScopedStartupTrace(const char* label) : label_(label ? label : ""), startCounter_(SDL_GetPerformanceCounter()) {} ~ScopedStartupTrace() { if (!StartupTrace::enabled()) { return; } Uint64 now = SDL_GetPerformanceCounter(); Uint64 frequency = SDL_GetPerformanceFrequency(); double elapsedMs = 0.0; if (frequency != 0) { elapsedMs = static_cast(now - startCounter_) * 1000.0 / static_cast(frequency); } char buffer[256] = {}; SDL_snprintf(buffer, sizeof(buffer), "[Startup] %s took %.2f ms (total %.2f ms, thread=%u)", label_, elapsedMs, StartupTrace::totalElapsedMs(), SDL_ThreadID()); StartupTrace::logLine(buffer); SDL_Log("%s", buffer); } private: const char* label_; Uint64 startCounter_ = 0; }; } // namespace frostbite2D