From 9f4501acebe91a80045a5927ca89c363825bba37 Mon Sep 17 00:00:00 2001
From: James Rowe <jroweboy@gmail.com>
Date: Sun, 14 Jul 2019 10:20:00 -0600
Subject: [PATCH] Perf: Remove more breakpoint checking in the interpreter.
 Move filtering earlier in the logging chain

---
 src/common/logging/backend.cpp                | 20 ++-------
 src/common/logging/backend.h                  |  8 ----
 src/common/logging/filter.h                   | 37 ---------------
 src/common/logging/log.h                      | 45 +++++++++++++++++++
 .../arm/dyncom/arm_dyncom_interpreter.cpp     |  6 +++
 src/core/arm/skyeye_common/armstate.cpp       |  5 ++-
 6 files changed, 59 insertions(+), 62 deletions(-)

diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 90608157e..a4a62713d 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -26,6 +26,10 @@
 
 namespace Log {
 
+Filter filter;
+void SetGlobalFilter(const Filter& f) {
+    filter = f;
+}
 /**
  * Static state as a singleton.
  */
@@ -58,14 +62,6 @@ public:
         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) {
         const auto it =
             std::find_if(backends.begin(), backends.end(),
@@ -283,10 +279,6 @@ const char* GetLevelName(Level log_level) {
     return "Invalid";
 }
 
-void SetGlobalFilter(const Filter& filter) {
-    Impl::Instance().SetGlobalFilter(filter);
-}
-
 void AddBackend(std::unique_ptr<Backend> 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,
                        const fmt::format_args& args) {
     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,
                        fmt::vformat(format, args));
 }
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index a6714ffd0..b0c78937f 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -14,8 +14,6 @@
 
 namespace Log {
 
-class Filter;
-
 /**
  * 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.
@@ -136,10 +134,4 @@ const char* GetLogClassName(Class log_class);
  */
 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
diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h
index bbadbcba1..cb48bcb37 100644
--- a/src/common/logging/filter.h
+++ b/src/common/logging/filter.h
@@ -11,41 +11,4 @@
 
 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
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index a14e2ff37..becdfbeab 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <array>
 #include <fmt/format.h>
 #include "common/common_types.h"
 
@@ -113,6 +114,47 @@ enum class Class : ClassType {
     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
 void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
                        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>
 void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_num,
                    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,
                       fmt::make_format_args(args...));
 }
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index 7ba67320b..72e1ebe06 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -953,6 +953,9 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
 #define INC_PC(l) ptr += sizeof(arm_inst) + l
 #define INC_PC_STUB ptr += sizeof(arm_inst)
 
+#ifdef ANDROID
+#define GDB_BP_CHECK
+#else
 #define GDB_BP_CHECK                                                                               \
     cpu->Cpsr &= ~(1 << 5);                                                                        \
     cpu->Cpsr |= cpu->TFlag << 5;                                                                  \
@@ -965,6 +968,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
             goto END;                                                                              \
         }                                                                                          \
     }
+#endif
 
 // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a
 // clunky switch statement.
@@ -1652,11 +1656,13 @@ DISPATCH : {
             goto END;
     }
 
+#ifndef ANDROID
     // Find breakpoint if one exists within the block
     if (GDBStub::IsConnected()) {
         breakpoint_data =
             GDBStub::GetNextBreakpointFromAddress(cpu->Reg[15], GDBStub::BreakpointType::Execute);
     }
+#endif
 
     inst_base = (arm_inst*)&trans_cache_buf[ptr];
     GOTO_NEXT_INST;
diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp
index 775618a8b..5e773b0e3 100644
--- a/src/core/arm/skyeye_common/armstate.cpp
+++ b/src/core/arm/skyeye_common/armstate.cpp
@@ -182,13 +182,16 @@ void ARMul_State::ResetMPCoreCP15Registers() {
     CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 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) {
     if (GDBStub::IsServerEnabled() && GDBStub::CheckBreakpoint(address, type)) {
         LOG_DEBUG(Debug, "Found memory breakpoint @ {:08x}", address);
         GDBStub::Break(true);
     }
 }
+#endif
 
 u8 ARMul_State::ReadMemory8(u32 address) const {
     CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);