1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

logs.hpp: refactoring (logs::message)

Make .error/.warning/... callable objects which can be pointed to.
Make .always() more hard to access.
Memory layout optimizations.
This commit is contained in:
Nekotekina 2021-05-19 14:30:39 +03:00
parent 1d0f6eebdc
commit 04cac6cd33
9 changed files with 95 additions and 69 deletions

View File

@ -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)
{

View File

@ -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)});

View File

@ -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. */

View File

@ -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

View File

@ -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<uint>(logs::level::success));
const gui_save l_level = gui_save(logger, "level", static_cast<uchar>(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);

View File

@ -26,7 +26,7 @@ constexpr auto qstr = QString::fromStdString;
struct gui_listener : logs::listener
{
atomic_t<logs::level> enabled{logs::level{UINT_MAX}};
atomic_t<logs::level> 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: ";
}

View File

@ -65,6 +65,14 @@ void fmt_class_string<logs::level>::format(std::string& out, u64 arg)
namespace logs
{
static_assert(std::is_empty_v<message> && 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<const char*>(u8"·A "); break;
case level::fatal: text = reinterpret_cast<const char*>(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: ";
}

View File

@ -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 <typename... Args>
void operator()(const const_str& fmt, const Args&... args) const;
operator level() const
{
return level(reinterpret_cast<uptr>(this) & 7);
}
const channel* operator->() const
{
return reinterpret_cast<const channel*>(reinterpret_cast<uptr>(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<level> 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 <typename... Args>\
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<Args...>, u64{fmt_unveil<Args>::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 <typename... Args>
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<Args...>, u64{fmt_unveil<Args>::get(args)}...);
}
else
{
broadcast(fmt, nullptr);
}
}
}
struct registerer
{
registerer(channel& _ch);

View File

@ -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;