From 4d610cc30e04584a6c25819653b87dd78d571bad Mon Sep 17 00:00:00 2001 From: comex Date: Sun, 19 Oct 2014 20:31:15 -0400 Subject: [PATCH] Add a test for page fault handling. This both tests that they work correctly and prints timing information if you run it manually. --- Source/UnitTests/Core/CMakeLists.txt | 1 + Source/UnitTests/Core/PageFaultTest.cpp | 77 +++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 Source/UnitTests/Core/PageFaultTest.cpp diff --git a/Source/UnitTests/Core/CMakeLists.txt b/Source/UnitTests/Core/CMakeLists.txt index 93f635a3ea..5bb809d9df 100644 --- a/Source/UnitTests/Core/CMakeLists.txt +++ b/Source/UnitTests/Core/CMakeLists.txt @@ -1 +1,2 @@ add_dolphin_test(MMIOTest MMIOTest.cpp) +add_dolphin_test(PageFaultTest PageFaultTest.cpp) 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 + +#include "Common/CommonTypes.h" +#include "Common/Timer.h" +#include "Core/MemTools.h" +#include "Core/PowerPC/JitCommon/JitBase.h" + +// include order is important +#include + +#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 + 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(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