Files
NS_unknown_game/Frostbite2D/include/frostbite2D/utils/startup_trace.h
T
2026-06-08 19:58:35 +08:00

153 lines
3.2 KiB
C++

#pragma once
#include <SDL2/SDL.h>
#include <fstream>
#include <mutex>
#include <string>
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<std::mutex> 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<std::mutex> 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<double>(now - start) * 1000.0 /
static_cast<double>(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 : "<unnamed>", totalElapsedMs(), SDL_ThreadID());
logLine(buffer);
SDL_Log("%s", buffer);
}
static void logLine(const std::string& line) {
if (!enabled()) {
return;
}
std::lock_guard<std::mutex> 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 : "<unnamed>"),
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<double>(now - startCounter_) * 1000.0 /
static_cast<double>(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