summaryrefslogtreecommitdiff
path: root/Source/UnitTests/Core/PageFaultTest.cpp
diff options
context:
space:
mode:
authorcomex <comexk@gmail.com>2014-10-19 20:31:15 -0400
committercomex <comexk@gmail.com>2014-10-19 20:41:52 -0400
commit4d610cc30e04584a6c25819653b87dd78d571bad (patch)
tree54e4fae5fcccfbdca4e59142331d93e6175c0dfa /Source/UnitTests/Core/PageFaultTest.cpp
parent536b8d6695fdcbf868628eb23a6814cadb24165e (diff)
Add a test for page fault handling.
This both tests that they work correctly and prints timing information if you run it manually.
Diffstat (limited to 'Source/UnitTests/Core/PageFaultTest.cpp')
-rw-r--r--Source/UnitTests/Core/PageFaultTest.cpp77
1 files changed, 77 insertions, 0 deletions
diff --git a/Source/UnitTests/Core/PageFaultTest.cpp b/Source/UnitTests/Core/PageFaultTest.cpp
new file mode 100644
index 0000000000..62a3e4bffa
--- /dev/null
+++ b/Source/UnitTests/Core/PageFaultTest.cpp
@@ -0,0 +1,77 @@
+#include <chrono>
+
+#include "Common/CommonTypes.h"
+#include "Common/Timer.h"
+#include "Core/MemTools.h"
+#include "Core/PowerPC/JitCommon/JitBase.h"
+
+// include order is important
+#include <gtest/gtest.h>
+
+#if _M_X86_64 || _M_ARM_32
+enum
+{
+#ifdef _WIN32
+ PAGE_GRAN = 0x10000
+#else
+ PAGE_GRAN = 0x1000
+#endif
+};
+
+class PageFaultFakeJit : public JitBase
+{
+public:
+ // CPUCoreBase methods
+ void Init() override {}
+ void Shutdown() override {}
+ void ClearCache() override {}
+ void Run() override {}
+ void SingleStep() override {}
+ const char *GetName() override { return nullptr; }
+
+ // JitBase methods
+ JitBaseBlockCache *GetBlockCache() override { return nullptr; }
+ void Jit(u32 em_address) override {}
+ const CommonAsmRoutinesBase *GetAsmRoutines() override { return nullptr; }
+
+ virtual bool HandleFault(uintptr_t access_address, SContext* ctx) override
+ {
+ m_pre_unprotect_time = std::chrono::high_resolution_clock::now();
+ UnWriteProtectMemory(m_data, PAGE_GRAN, /*allowExecute*/ false);
+ m_post_unprotect_time = std::chrono::high_resolution_clock::now();
+ return true;
+ }
+
+ void* m_data;
+ std::chrono::time_point<std::chrono::high_resolution_clock>
+ m_pre_unprotect_time, m_post_unprotect_time;
+};
+
+
+TEST(PageFault, PageFault)
+{
+ EMM::InstallExceptionHandler();
+ void* data = AllocateMemoryPages(PAGE_GRAN);
+ EXPECT_NE(data, nullptr);
+ WriteProtectMemory(data, PAGE_GRAN, false);
+
+ PageFaultFakeJit pfjit;
+ jit = &pfjit;
+ pfjit.m_data = data;
+
+ auto start = std::chrono::high_resolution_clock::now();
+ *(volatile int*) data = 5;
+ auto end = std::chrono::high_resolution_clock::now();
+
+ #define AS_NS(diff) ((unsigned long long)std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count())
+
+ EMM::UninstallExceptionHandler();
+ jit = nullptr;
+
+ printf("page fault timing:\n");
+ printf("start->HandleFault %llu ns\n", AS_NS(pfjit.m_pre_unprotect_time - start));
+ printf("UnWriteProtectMemory %llu ns\n", AS_NS(pfjit.m_post_unprotect_time - pfjit.m_pre_unprotect_time));
+ printf("HandleFault->end %llu ns\n", AS_NS(end - pfjit.m_post_unprotect_time));
+ printf("total %llu ns\n", AS_NS(end - start));
+}
+#endif