summaryrefslogtreecommitdiff
path: root/Source/UnitTests/Core/PageFaultTest.cpp
diff options
context:
space:
mode:
authorJules Blok <jules.blok@gmail.com>2015-06-10 00:00:12 +0200
committerJules Blok <jules.blok@gmail.com>2015-06-10 00:00:12 +0200
commit7dfced21a2e5aac7195e0e1ad76468e30306766b (patch)
treebd671b639d3d911460b767caabad8fc8a759a6bf /Source/UnitTests/Core/PageFaultTest.cpp
parentc25be031fc1031d795157d8344b87b7841145197 (diff)
parent7b0a65e295c784f9d573f2ef52d4e2a7b9bb2889 (diff)
Merge branch 'master' into stable
Diffstat (limited to 'Source/UnitTests/Core/PageFaultTest.cpp')
-rw-r--r--Source/UnitTests/Core/PageFaultTest.cpp81
1 files changed, 81 insertions, 0 deletions
diff --git a/Source/UnitTests/Core/PageFaultTest.cpp b/Source/UnitTests/Core/PageFaultTest.cpp
new file mode 100644
index 0000000000..002b5ec866
--- /dev/null
+++ b/Source/UnitTests/Core/PageFaultTest.cpp
@@ -0,0 +1,81 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#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> // NOLINT
+
+#if _M_X86_64
+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