Perf: Remove more breakpoint checking in the interpreter. Move filtering earlier in the logging chain
This commit is contained in:
		| @@ -26,6 +26,10 @@ | |||||||
|  |  | ||||||
| namespace Log { | namespace Log { | ||||||
|  |  | ||||||
|  | Filter filter; | ||||||
|  | void SetGlobalFilter(const Filter& f) { | ||||||
|  |     filter = f; | ||||||
|  | } | ||||||
| /** | /** | ||||||
|  * Static state as a singleton. |  * Static state as a singleton. | ||||||
|  */ |  */ | ||||||
| @@ -58,14 +62,6 @@ public: | |||||||
|         backends.erase(it, backends.end()); |         backends.erase(it, backends.end()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const Filter& GetGlobalFilter() const { |  | ||||||
|         return filter; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void SetGlobalFilter(const Filter& f) { |  | ||||||
|         filter = f; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     Backend* GetBackend(std::string_view backend_name) { |     Backend* GetBackend(std::string_view backend_name) { | ||||||
|         const auto it = |         const auto it = | ||||||
|             std::find_if(backends.begin(), backends.end(), |             std::find_if(backends.begin(), backends.end(), | ||||||
| @@ -283,10 +279,6 @@ const char* GetLevelName(Level log_level) { | |||||||
|     return "Invalid"; |     return "Invalid"; | ||||||
| } | } | ||||||
|  |  | ||||||
| void SetGlobalFilter(const Filter& filter) { |  | ||||||
|     Impl::Instance().SetGlobalFilter(filter); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void AddBackend(std::unique_ptr<Backend> backend) { | void AddBackend(std::unique_ptr<Backend> backend) { | ||||||
|     Impl::Instance().AddBackend(std::move(backend)); |     Impl::Instance().AddBackend(std::move(backend)); | ||||||
| } | } | ||||||
| @@ -303,10 +295,6 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, | |||||||
|                        unsigned int line_num, const char* function, const char* format, |                        unsigned int line_num, const char* function, const char* format, | ||||||
|                        const fmt::format_args& args) { |                        const fmt::format_args& args) { | ||||||
|     auto& instance = Impl::Instance(); |     auto& instance = Impl::Instance(); | ||||||
|     const auto& filter = instance.GetGlobalFilter(); |  | ||||||
|     if (!filter.CheckMessage(log_class, log_level)) |  | ||||||
|         return; |  | ||||||
|  |  | ||||||
|     instance.PushEntry(log_class, log_level, filename, line_num, function, |     instance.PushEntry(log_class, log_level, filename, line_num, function, | ||||||
|                        fmt::vformat(format, args)); |                        fmt::vformat(format, args)); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -14,8 +14,6 @@ | |||||||
|  |  | ||||||
| namespace Log { | namespace Log { | ||||||
|  |  | ||||||
| class Filter; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * A log entry. Log entries are store in a structured format to permit more varied output |  * 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. |  * formatting on different frontends, as well as facilitating filtering and aggregation. | ||||||
| @@ -136,10 +134,4 @@ const char* GetLogClassName(Class log_class); | |||||||
|  */ |  */ | ||||||
| const char* GetLevelName(Level log_level); | const char* GetLevelName(Level log_level); | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * The global filter will prevent any messages from even being processed if they are filtered. Each |  | ||||||
|  * backend can have a filter, but if the level is lower than the global filter, the backend will |  | ||||||
|  * never get the message |  | ||||||
|  */ |  | ||||||
| void SetGlobalFilter(const Filter& filter); |  | ||||||
| } // namespace Log | } // namespace Log | ||||||
|   | |||||||
| @@ -11,41 +11,4 @@ | |||||||
|  |  | ||||||
| namespace Log { | namespace Log { | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Implements a log message filter which allows different log classes to have different minimum |  | ||||||
|  * severity levels. The filter can be changed at runtime and can be parsed from a string to allow |  | ||||||
|  * editing via the interface or loading from a configuration file. |  | ||||||
|  */ |  | ||||||
| class Filter { |  | ||||||
| public: |  | ||||||
|     /// Initializes the filter with all classes having `default_level` as the minimum level. |  | ||||||
|     explicit Filter(Level default_level = Level::Info); |  | ||||||
|  |  | ||||||
|     /// Resets the filter so that all classes have `level` as the minimum displayed level. |  | ||||||
|     void ResetAll(Level level); |  | ||||||
|     /// Sets the minimum level of `log_class` (and not of its subclasses) to `level`. |  | ||||||
|     void SetClassLevel(Class log_class, Level level); |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Parses a filter string and applies it to this filter. |  | ||||||
|      * |  | ||||||
|      * A filter string consists of a space-separated list of filter rules, each of the format |  | ||||||
|      * `<class>:<level>`. `<class>` is a log class name, with subclasses separated using periods. |  | ||||||
|      * `*` is allowed as a class name and will reset all filters to the specified level. `<level>` |  | ||||||
|      * a severity level name which will be set as the minimum logging level of the matched classes. |  | ||||||
|      * Rules are applied left to right, with each rule overriding previous ones in the sequence. |  | ||||||
|      * |  | ||||||
|      * A few examples of filter rules: |  | ||||||
|      *  - `*:Info` -- Resets the level of all classes to Info. |  | ||||||
|      *  - `Service:Info` -- Sets the level of Service to Info. |  | ||||||
|      *  - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace. |  | ||||||
|      */ |  | ||||||
|     void ParseFilterString(std::string_view filter_view); |  | ||||||
|  |  | ||||||
|     /// Matches class/level combination against the filter, returning true if it passed. |  | ||||||
|     bool CheckMessage(Class log_class, Level level) const; |  | ||||||
|  |  | ||||||
| private: |  | ||||||
|     std::array<Level, static_cast<std::size_t>(Class::Count)> class_levels; |  | ||||||
| }; |  | ||||||
| } // namespace Log | } // namespace Log | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|  | #include <array> | ||||||
| #include <fmt/format.h> | #include <fmt/format.h> | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  |  | ||||||
| @@ -113,6 +114,47 @@ enum class Class : ClassType { | |||||||
|     Count              ///< Total number of logging classes |     Count              ///< Total number of logging classes | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Implements a log message filter which allows different log classes to have different minimum | ||||||
|  |  * severity levels. The filter can be changed at runtime and can be parsed from a string to allow | ||||||
|  |  * editing via the interface or loading from a configuration file. | ||||||
|  |  */ | ||||||
|  | class Filter { | ||||||
|  | public: | ||||||
|  |     /// Initializes the filter with all classes having `default_level` as the minimum level. | ||||||
|  |     explicit Filter(Level default_level = Level::Info); | ||||||
|  |  | ||||||
|  |     /// Resets the filter so that all classes have `level` as the minimum displayed level. | ||||||
|  |     void ResetAll(Level level); | ||||||
|  |     /// Sets the minimum level of `log_class` (and not of its subclasses) to `level`. | ||||||
|  |     void SetClassLevel(Class log_class, Level level); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Parses a filter string and applies it to this filter. | ||||||
|  |      * | ||||||
|  |      * A filter string consists of a space-separated list of filter rules, each of the format | ||||||
|  |      * `<class>:<level>`. `<class>` is a log class name, with subclasses separated using periods. | ||||||
|  |      * `*` is allowed as a class name and will reset all filters to the specified level. `<level>` | ||||||
|  |      * a severity level name which will be set as the minimum logging level of the matched classes. | ||||||
|  |      * Rules are applied left to right, with each rule overriding previous ones in the sequence. | ||||||
|  |      * | ||||||
|  |      * A few examples of filter rules: | ||||||
|  |      *  - `*:Info` -- Resets the level of all classes to Info. | ||||||
|  |      *  - `Service:Info` -- Sets the level of Service to Info. | ||||||
|  |      *  - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace. | ||||||
|  |      */ | ||||||
|  |     void ParseFilterString(std::string_view filter_view); | ||||||
|  |  | ||||||
|  |     /// Matches class/level combination against the filter, returning true if it passed. | ||||||
|  |     bool CheckMessage(Class log_class, Level level) const; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     std::array<Level, static_cast<std::size_t>(Class::Count)> class_levels; | ||||||
|  | }; | ||||||
|  | extern Filter filter; | ||||||
|  |  | ||||||
|  | void SetGlobalFilter(const Filter& f); | ||||||
|  |  | ||||||
| /// Logs a message to the global logger, using fmt | /// Logs a message to the global logger, using fmt | ||||||
| void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, | void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, | ||||||
|                        unsigned int line_num, const char* function, const char* format, |                        unsigned int line_num, const char* function, const char* format, | ||||||
| @@ -121,6 +163,9 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, | |||||||
| template <typename... Args> | template <typename... Args> | ||||||
| void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_num, | void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_num, | ||||||
|                    const char* function, const char* format, const Args&... args) { |                    const char* function, const char* format, const Args&... args) { | ||||||
|  |     if (!filter.CheckMessage(log_class, log_level)) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|     FmtLogMessageImpl(log_class, log_level, filename, line_num, function, format, |     FmtLogMessageImpl(log_class, log_level, filename, line_num, function, format, | ||||||
|                       fmt::make_format_args(args...)); |                       fmt::make_format_args(args...)); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -953,6 +953,9 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||||||
| #define INC_PC(l) ptr += sizeof(arm_inst) + l | #define INC_PC(l) ptr += sizeof(arm_inst) + l | ||||||
| #define INC_PC_STUB ptr += sizeof(arm_inst) | #define INC_PC_STUB ptr += sizeof(arm_inst) | ||||||
|  |  | ||||||
|  | #ifdef ANDROID | ||||||
|  | #define GDB_BP_CHECK | ||||||
|  | #else | ||||||
| #define GDB_BP_CHECK                                                                               \ | #define GDB_BP_CHECK                                                                               \ | ||||||
|     cpu->Cpsr &= ~(1 << 5);                                                                        \ |     cpu->Cpsr &= ~(1 << 5);                                                                        \ | ||||||
|     cpu->Cpsr |= cpu->TFlag << 5;                                                                  \ |     cpu->Cpsr |= cpu->TFlag << 5;                                                                  \ | ||||||
| @@ -965,6 +968,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||||||
|             goto END;                                                                              \ |             goto END;                                                                              \ | ||||||
|         }                                                                                          \ |         }                                                                                          \ | ||||||
|     } |     } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a | // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a | ||||||
| // clunky switch statement. | // clunky switch statement. | ||||||
| @@ -1652,11 +1656,13 @@ DISPATCH : { | |||||||
|             goto END; |             goto END; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | #ifndef ANDROID | ||||||
|     // Find breakpoint if one exists within the block |     // Find breakpoint if one exists within the block | ||||||
|     if (GDBStub::IsConnected()) { |     if (GDBStub::IsConnected()) { | ||||||
|         breakpoint_data = |         breakpoint_data = | ||||||
|             GDBStub::GetNextBreakpointFromAddress(cpu->Reg[15], GDBStub::BreakpointType::Execute); |             GDBStub::GetNextBreakpointFromAddress(cpu->Reg[15], GDBStub::BreakpointType::Execute); | ||||||
|     } |     } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|     inst_base = (arm_inst*)&trans_cache_buf[ptr]; |     inst_base = (arm_inst*)&trans_cache_buf[ptr]; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|   | |||||||
| @@ -182,13 +182,16 @@ void ARMul_State::ResetMPCoreCP15Registers() { | |||||||
|     CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000; |     CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000; | ||||||
|     CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000; |     CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000; | ||||||
| } | } | ||||||
|  | #ifdef ANDROID | ||||||
|  | static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type) {} | ||||||
|  | #else | ||||||
| static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type) { | static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type) { | ||||||
|     if (GDBStub::IsServerEnabled() && GDBStub::CheckBreakpoint(address, type)) { |     if (GDBStub::IsServerEnabled() && GDBStub::CheckBreakpoint(address, type)) { | ||||||
|         LOG_DEBUG(Debug, "Found memory breakpoint @ {:08x}", address); |         LOG_DEBUG(Debug, "Found memory breakpoint @ {:08x}", address); | ||||||
|         GDBStub::Break(true); |         GDBStub::Break(true); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| u8 ARMul_State::ReadMemory8(u32 address) const { | u8 ARMul_State::ReadMemory8(u32 address) const { | ||||||
|     CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); |     CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user