153 lines
3.2 KiB
C++
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
|