From 22dc52009a0d54250840bb1023e819aac9b597da Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 24 Jun 2026 20:24:56 +0000 Subject: [PATCH] [common/logging] Add thread names Signed-off-by: lizzie --- src/common/logging.cpp | 24 +++++++++++++++++++----- src/common/logging.h | 21 --------------------- src/common/thread.cpp | 14 +++++++++++++- src/common/thread.h | 3 ++- 4 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/common/logging.cpp b/src/common/logging.cpp index ccf509f451..c2af2a3563 100644 --- a/src/common/logging.cpp +++ b/src/common/logging.cpp @@ -41,6 +41,19 @@ namespace Common::Log { namespace { +/// @brief A log entry. Log entries are store in a structured format to permit more varied output +/// formatting on different frontends, as well as facilitating filtering and aggregation. +struct Entry { + std::string_view thread_name; + std::string message; + std::chrono::microseconds timestamp; + Class log_class{}; + Level log_level{}; + const char* filename = nullptr; + const char* function = nullptr; + unsigned int line_num = 0; +}; + /// @brief Returns the name of the passed log class as a C-string. Subclasses are separated by periods /// instead of underscores as in the enumeration. /// @note GetClassName is a macro defined by Windows.h, grrr... @@ -79,7 +92,7 @@ std::string FormatLogMessage(const Entry& entry) noexcept { auto const time_fractional = uint32_t(entry.timestamp.count() % 1000000); auto const class_name = GetLogClassName(entry.log_class); auto const level_name = GetLevelName(entry.log_level); - return fmt::format("[{:4d}.{:06d}] {} <{}> {}:{}:{}: {}", time_seconds, time_fractional, class_name, level_name, entry.filename, entry.line_num, entry.function, entry.message); + return fmt::format("[{:4d}.{:06d}] {} <{}> (eden:{}) {}:{}:{}: {}", time_seconds, time_fractional, class_name, level_name, entry.thread_name.data(), entry.filename, entry.line_num, entry.function, entry.message); } namespace { @@ -165,7 +178,7 @@ struct Backend { }; /// @brief Formatting specifier (to use with printf) of the equivalent fmt::format() expression -#define CCB_PRINTF_FMT "[%4d.%06d] %s <%s> %s:%u:%s: %s" +#define CCB_PRINTF_FMT "[%4d.%06d] %s <%s> (eden:%s) %s:%u:%s: %s" /// @brief Instead of using fmt::format() just use the system's formatting capabilities directly struct DirectFormatArgs { @@ -208,7 +221,7 @@ struct ColorConsoleBackend final : public Backend { }()); SetConsoleTextAttribute(console_handle, color); auto const df = GetDirectFormatArgs(entry); - std::fprintf(stdout, CCB_PRINTF_FMT "\n", df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message.c_str()); + std::fprintf(stdout, CCB_PRINTF_FMT "\n", df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.thread_name.data(), entry.filename, entry.line_num, entry.function, entry.message.c_str()); } } void Flush() noexcept override {} @@ -234,7 +247,7 @@ struct ColorConsoleBackend final : public Backend { } }(); auto const df = GetDirectFormatArgs(entry); - std::fprintf(stdout, color_str, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message.c_str()); + std::fprintf(stdout, color_str, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.thread_name.data(), entry.filename, entry.line_num, entry.function, entry.message.c_str()); #undef ESC } } @@ -338,7 +351,7 @@ struct LogcatBackend : public Backend { } }(); auto const df = GetDirectFormatArgs(entry); - __android_log_print(android_log_priority, "YuzuNative", CCB_PRINTF_FMT, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message.c_str()); + __android_log_print(android_log_priority, "YuzuNative", CCB_PRINTF_FMT, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.thread_name.data(), entry.filename, entry.line_num, entry.function, entry.message.c_str()); } void Flush() noexcept override {} }; @@ -421,6 +434,7 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, u auto const flush = ::Settings::values.log_flush_line.GetValue(); logging_instance->ForEachBackend([=](Backend& backend) { backend.Write(Entry{ + .thread_name = Common::GetCurrentThreadName(), .message = fmt::vformat(format, args), .timestamp = std::chrono::duration_cast(std::chrono::steady_clock::now() - logging_instance->time_origin), .log_class = log_class, diff --git a/src/common/logging.h b/src/common/logging.h index 2d5a2cfa93..d273eb0c49 100644 --- a/src/common/logging.h +++ b/src/common/logging.h @@ -140,25 +140,4 @@ void Stop(); void SetGlobalFilter(const Filter& filter); void SetColorConsoleBackendEnabled(bool enabled); -/// @brief A log entry. Log entries are store in a structured format to permit more varied output -/// formatting on different frontends, as well as facilitating filtering and aggregation. -struct Entry { - std::string message; - std::chrono::microseconds timestamp; - Class log_class{}; - Level log_level{}; - const char* filename = nullptr; - const char* function = nullptr; - unsigned int line_num = 0; -}; - -/// Formats a log entry into the provided text buffer. -std::string FormatLogMessage(const Entry& entry) noexcept; - -/// Prints the same message as `PrintMessage`, but colored according to the severity level. -void PrintColoredMessage(const Entry& entry) noexcept; - -/// Formats and prints a log entry to the android logcat. -void PrintMessageToLogcat(const Entry& entry) noexcept; - } // namespace Common::Log diff --git a/src/common/thread.cpp b/src/common/thread.cpp index c947c88373..1208a394b7 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp @@ -52,6 +52,13 @@ namespace Common { +// The use of TLS is justified as it is faster than using pthread_* functions +// and generally will be better long term... yeah %fs/%gs reloads aren't great +// but it's better than doing a potential call-stack-fuckery... +thread_local struct { + std::string name{}; +} per_thread_data = {}; + void SetCurrentThreadPriority(ThreadPriority new_priority) { #ifdef _WIN32 int windows_priority = [&]() { @@ -96,7 +103,7 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) { #endif } -void SetCurrentThreadName(const char* name) { +void SetCurrentThreadName(const char* name) noexcept { #ifdef _MSC_VER // Sets the debugger-visible name of the current thread. if (auto pf = (decltype(&SetThreadDescription))(void*)GetProcAddress(GetModuleHandle(TEXT("KernelBase.dll")), "SetThreadDescription"); pf) @@ -130,6 +137,11 @@ void SetCurrentThreadName(const char* name) { #else pthread_setname_np(pthread_self(), name); #endif + per_thread_data.name = std::string{name}; +} + +std::string_view GetCurrentThreadName() noexcept { + return per_thread_data.name; } void PinCurrentThreadToPerformanceCore(size_t core_id) { diff --git a/src/common/thread.h b/src/common/thread.h index a75e342802..18cddac014 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -100,7 +100,8 @@ enum class ThreadPriority : u32 { }; void SetCurrentThreadPriority(ThreadPriority new_priority); -void SetCurrentThreadName(const char* name); +void SetCurrentThreadName(const char* name) noexcept; +std::string_view GetCurrentThreadName() noexcept; void PinCurrentThreadToPerformanceCore(size_t core_id); } // namespace Common