From 04cac6cd33be679d92f898bd53628299ddd56231 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 19 May 2021 14:30:39 +0300 Subject: [PATCH] logs.hpp: refactoring (logs::message) Make .error/.warning/... callable objects which can be pointed to. Make .always() more hard to access. Memory layout optimizations. --- rpcs3/Emu/RSX/VK/vkutils/device.cpp | 2 +- rpcs3/main.cpp | 26 +++----- rpcs3/main_application.cpp | 2 +- rpcs3/rpcs3qt/gui_settings.cpp | 2 +- rpcs3/rpcs3qt/gui_settings.h | 2 +- rpcs3/rpcs3qt/log_frame.cpp | 14 ++--- rpcs3/util/logs.cpp | 20 +++++-- rpcs3/util/logs.hpp | 92 ++++++++++++++++++----------- rpcs3/util/types.hpp | 4 ++ 9 files changed, 95 insertions(+), 69 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/vkutils/device.cpp b/rpcs3/Emu/RSX/VK/vkutils/device.cpp index 9ac49b1949..fdb28b0322 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/device.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/device.cpp @@ -70,7 +70,7 @@ namespace vk vkGetPhysicalDeviceMemoryProperties(pdev, &memory_properties); get_physical_device_features(allow_extensions); - rsx_log.always("Found vulkan-compatible GPU: '%s' running on driver %s", get_name(), get_driver_version()); + rsx_log.always()("Found vulkan-compatible GPU: '%s' running on driver %s", get_name(), get_driver_version()); if (get_driver_vendor() == driver_vendor::RADV && get_name().find("LLVM 8.0.0") != umax) { diff --git a/rpcs3/main.cpp b/rpcs3/main.cpp index daa71528e9..99eafd3398 100644 --- a/rpcs3/main.cpp +++ b/rpcs3/main.cpp @@ -187,7 +187,7 @@ struct fatal_error_listener final : logs::listener void log(u64 /*stamp*/, const logs::message& msg, const std::string& prefix, const std::string& text) override { - if (msg.sev == logs::level::fatal) + if (msg == logs::level::fatal) { std::string _msg = "RPCS3: "; @@ -197,9 +197,9 @@ struct fatal_error_listener final : logs::listener _msg += ": "; } - if (msg.ch && '\0' != *msg.ch->name) + if (msg->name && '\0' != *msg->name) { - _msg += msg.ch->name; + _msg += msg->name; _msg += ": "; } @@ -446,31 +446,19 @@ int main(int argc, char** argv) { // Write RPCS3 version - logs::stored_message ver; - ver.m.ch = nullptr; - ver.m.sev = logs::level::always; - ver.stamp = 0; + logs::stored_message ver{sys_log.always()}; ver.text = fmt::format("RPCS3 v%s | %s", rpcs3::get_version().to_string(), rpcs3::get_branch()); // Write System information - logs::stored_message sys; - sys.m.ch = nullptr; - sys.m.sev = logs::level::always; - sys.stamp = 0; + logs::stored_message sys{sys_log.always()}; sys.text = utils::get_system_info(); // Write OS version - logs::stored_message os; - os.m.ch = nullptr; - os.m.sev = logs::level::always; - os.stamp = 0; + logs::stored_message os{sys_log.always()}; os.text = utils::get_OS_version(); // Write Qt version - logs::stored_message qt; - qt.m.ch = nullptr; - qt.m.sev = (strcmp(QT_VERSION_STR, qVersion()) != 0) ? logs::level::error : logs::level::notice; - qt.stamp = 0; + logs::stored_message qt{(strcmp(QT_VERSION_STR, qVersion()) != 0) ? sys_log.error : sys_log.notice}; qt.text = fmt::format("Qt version: Compiled against Qt %s | Run-time uses Qt %s", QT_VERSION_STR, qVersion()); logs::set_init({std::move(ver), std::move(sys), std::move(os), std::move(qt)}); diff --git a/rpcs3/main_application.cpp b/rpcs3/main_application.cpp index 6b776f3e8c..f491709a7f 100644 --- a/rpcs3/main_application.cpp +++ b/rpcs3/main_application.cpp @@ -43,7 +43,7 @@ void main_application::InitializeEmulator(const std::string& user, bool show_gui // Log Firmware Version after Emu was initialized const std::string firmware_version = utils::get_firmware_version(); const std::string firmware_string = firmware_version.empty() ? "Missing Firmware" : ("Firmware version: " + firmware_version); - sys_log.always("%s", firmware_string); + sys_log.always()("%s", firmware_string); } /** RPCS3 emulator has functions it desires to call from the GUI at times. Initialize them in here. */ diff --git a/rpcs3/rpcs3qt/gui_settings.cpp b/rpcs3/rpcs3qt/gui_settings.cpp index 9eaf43d443..ac7deafa6b 100644 --- a/rpcs3/rpcs3qt/gui_settings.cpp +++ b/rpcs3/rpcs3qt/gui_settings.cpp @@ -254,7 +254,7 @@ void gui_settings::SaveCurrentConfig(const QString& config_name) logs::level gui_settings::GetLogLevel() const { - return logs::level{GetValue(gui::l_level).toUInt()}; + return logs::level(GetValue(gui::l_level).toUInt()); } bool gui_settings::GetGamelistColVisibility(int col) const diff --git a/rpcs3/rpcs3qt/gui_settings.h b/rpcs3/rpcs3qt/gui_settings.h index 900636ce1c..5bcd4fbc17 100644 --- a/rpcs3/rpcs3qt/gui_settings.h +++ b/rpcs3/rpcs3qt/gui_settings.h @@ -178,7 +178,7 @@ namespace gui const gui_save fs_dev_usb000_list = gui_save(fs, "dev_usb000_list", QStringList()); const gui_save l_tty = gui_save(logger, "TTY", true); - const gui_save l_level = gui_save(logger, "level", static_cast(logs::level::success)); + const gui_save l_level = gui_save(logger, "level", static_cast(logs::level::success)); const gui_save l_prefix = gui_save(logger, "prefix_on", false); const gui_save l_stack = gui_save(logger, "stack", true); const gui_save l_stack_tty = gui_save(logger, "TTY_stack", false); diff --git a/rpcs3/rpcs3qt/log_frame.cpp b/rpcs3/rpcs3qt/log_frame.cpp index fdee34e5ef..c564d7c76f 100644 --- a/rpcs3/rpcs3qt/log_frame.cpp +++ b/rpcs3/rpcs3qt/log_frame.cpp @@ -26,7 +26,7 @@ constexpr auto qstr = QString::fromStdString; struct gui_listener : logs::listener { - atomic_t enabled{logs::level{UINT_MAX}}; + atomic_t enabled{logs::level{UCHAR_MAX}}; struct packet_t { @@ -55,10 +55,10 @@ struct gui_listener : logs::listener { Q_UNUSED(stamp) - if (msg.sev <= enabled) + if (msg <= enabled) { packet_t p,* _new = &p; - _new->sev = msg.sev; + _new->sev = msg; if (show_prefix && !prefix.empty()) { @@ -67,12 +67,12 @@ struct gui_listener : logs::listener _new->msg += "} "; } - if (msg.ch && '\0' != *msg.ch->name) + if (msg->name && '\0' != *msg->name) { - _new->msg += msg.ch->name; - _new->msg += msg.sev == logs::level::todo ? " TODO: " : ": "; + _new->msg += msg->name; + _new->msg += msg == logs::level::todo ? " TODO: " : ": "; } - else if (msg.sev == logs::level::todo) + else if (msg == logs::level::todo) { _new->msg += "TODO: "; } diff --git a/rpcs3/util/logs.cpp b/rpcs3/util/logs.cpp index b3327f9d44..b4d9ec2213 100644 --- a/rpcs3/util/logs.cpp +++ b/rpcs3/util/logs.cpp @@ -65,6 +65,14 @@ void fmt_class_string::format(std::string& out, u64 arg) namespace logs { + static_assert(std::is_empty_v && sizeof(message) == 1); + static_assert(sizeof(channel) == alignof(channel)); + static_assert(uchar(level::always) == 0); + static_assert(uchar(level::fatal) == 1); + static_assert(uchar(level::trace) == 7); + static_assert((offsetof(channel, fatal) & 7) == 1); + static_assert((offsetof(channel, trace) & 7) == 7); + // Memory-mapped buffer size constexpr u64 s_log_size = 32 * 1024 * 1024; @@ -618,7 +626,7 @@ void logs::file_listener::log(u64 stamp, const logs::message& msg, const std::st text.reserve(50000); // Used character: U+00B7 (Middle Dot) - switch (msg.sev) + switch (msg) { case level::always: text = reinterpret_cast(u8"·A "); break; case level::fatal: text = reinterpret_cast(u8"·F "); break; @@ -637,7 +645,7 @@ void logs::file_listener::log(u64 stamp, const logs::message& msg, const std::st const u64 frac = (stamp % 1'000'000); fmt::append(text, "%u:%02u:%02u.%06u ", hours, mins, secs, frac); - if (msg.ch == nullptr && stamp == 0) + if (stamp == 0) { // Workaround for first special messages to keep backward compatibility text.clear(); @@ -650,12 +658,12 @@ void logs::file_listener::log(u64 stamp, const logs::message& msg, const std::st text += "} "; } - if (msg.ch && '\0' != *msg.ch->name) + if (msg->name && '\0' != *msg->name) { - text += msg.ch->name; - text += msg.sev == level::todo ? " TODO: " : ": "; + text += msg->name; + text += msg == level::todo ? " TODO: " : ": "; } - else if (msg.sev == level::todo) + else if (msg == level::todo) { text += "TODO: "; } diff --git a/rpcs3/util/logs.hpp b/rpcs3/util/logs.hpp index 61f894a340..2dc9ab4d6f 100644 --- a/rpcs3/util/logs.hpp +++ b/rpcs3/util/logs.hpp @@ -10,16 +10,16 @@ namespace logs { - enum class level : unsigned + enum class level : unsigned char { - always, // Highest log severity (cannot be disabled) - fatal, - error, - todo, - success, - warning, - notice, - trace, // Lowest severity (usually disabled) + always = 0, // Highest log severity (cannot be disabled) + fatal = 1, + error = 2, + todo = 3, + success = 4, + warning = 5, + notice = 6, + trace = 7, // Lowest severity (usually disabled) }; struct channel; @@ -27,8 +27,27 @@ namespace logs // Message information struct message { - channel* ch; - level sev; + // Default constructor + consteval message() = default; + + // Cannot be moved because it relies on its location + message(const message&) = delete; + + message& operator =(const message&) = delete; + + // Send log message to the given channel with severity + template + void operator()(const const_str& fmt, const Args&... args) const; + + operator level() const + { + return level(reinterpret_cast(this) & 7); + } + + const channel* operator->() const + { + return reinterpret_cast(reinterpret_cast(this) & -16); + } private: // Send log message to global logger instance @@ -39,7 +58,7 @@ namespace logs struct stored_message { - message m; + const message& m; u64 stamp; std::string prefix; std::string text; @@ -67,7 +86,7 @@ namespace logs void broadcast(const stored_message&) const; }; - struct channel + struct alignas(16) channel : private message { // Channel prefix (added to every log message) const char* const name; @@ -76,31 +95,22 @@ namespace logs atomic_t enabled; // Initialize channel - constexpr channel(const char* name) noexcept - : name(name) + consteval channel(const char* name) noexcept + : message{} + , name(name) , enabled(level::notice) { } -#define GEN_LOG_METHOD(_sev)\ - const message msg_##_sev{this, level::_sev};\ - template \ - void _sev(const const_str& fmt, const Args&... args)\ - {\ - if (level::_sev <= enabled.observe()) [[unlikely]]\ - {\ - if constexpr (sizeof...(Args) > 0)\ - {\ - msg_##_sev.broadcast(fmt, fmt::type_info_v, u64{fmt_unveil::get(args)}...);\ - }\ - else\ - {\ - msg_##_sev.broadcast(fmt, nullptr);\ - }\ - }\ - }\ + // Special access to "always visible" channel which shouldn't be used + const message& always() const + { + return *this; + } + +#define GEN_LOG_METHOD(_sev)\ + const message _sev{};\ - GEN_LOG_METHOD(always) GEN_LOG_METHOD(fatal) GEN_LOG_METHOD(error) GEN_LOG_METHOD(todo) @@ -112,6 +122,22 @@ namespace logs #undef GEN_LOG_METHOD }; + template + FORCE_INLINE SAFE_BUFFERS(void) message::operator()(const const_str& fmt, const Args&... args) const + { + if (*this < (*this)->enabled) [[unlikely]] + { + if constexpr (sizeof...(Args) > 0) + { + broadcast(fmt, fmt::type_info_v, u64{fmt_unveil::get(args)}...); + } + else + { + broadcast(fmt, nullptr); + } + } + } + struct registerer { registerer(channel& _ch); diff --git a/rpcs3/util/types.hpp b/rpcs3/util/types.hpp index fb21075d3c..6c60f6e139 100644 --- a/rpcs3/util/types.hpp +++ b/rpcs3/util/types.hpp @@ -73,6 +73,10 @@ namespace std } #endif +#if defined(__INTELLISENSE__) +#define consteval constexpr +#endif + using schar = signed char; using uchar = unsigned char; using ushort = unsigned short;