dolphin/Source/UnitTests/Core/PageFaultTest.cpp
Martino Fontana a14c88ba67 Remove unused imports
Yellow squiggly lines begone!
Done automatically on .cpp files through `run-clang-tidy`, with manual corrections to the mistakes.
If an import is directly used, but is technically unnecessary since it's recursively imported by something else, it is *not* removed.
The tool doesn't touch .h files, so I did some of them by hand while fixing errors due to old recursive imports.
Not everything is removed, but the cleanup should be substantial enough.
Because this done on Linux, code that isn't used on it is mostly untouched.
(Hopefully no open PR is depending on these imports...)
2026-01-25 16:12:15 +01:00

110 lines
3.5 KiB
C++

// Copyright 2014 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include "Common/CommonTypes.h"
#include "Common/ScopeGuard.h"
#include "Core/Core.h"
#include "Core/MemTools.h"
#include "Core/PowerPC/JitCommon/JitBase.h"
#include "Core/PowerPC/JitInterface.h"
#include "Core/System.h"
// include order is important
#include <gtest/gtest.h> // NOLINT
enum
{
#ifdef _WIN32
PAGE_GRAN = 0x10000
#else
PAGE_GRAN = 0x1000
#endif
};
class PageFaultFakeJit : public JitBase
{
public:
explicit PageFaultFakeJit(Core::System& system) : JitBase(system) {}
// CPUCoreBase methods
void Init() override {}
void Shutdown() override {}
void ClearCache() override {}
void Run() override {}
void SingleStep() override {}
const char* GetName() const override { return nullptr; }
// JitBase methods
JitBaseBlockCache* GetBlockCache() override { return nullptr; }
void Jit(u32 em_address) override {}
void EraseSingleBlock(const JitBlock&) override {}
std::vector<MemoryStats> GetMemoryStats() const override { return {}; }
std::size_t DisassembleNearCode(const JitBlock&, std::ostream&) const override { return 0; }
std::size_t DisassembleFarCode(const JitBlock&, std::ostream&) const override { return 0; }
const CommonAsmRoutinesBase* GetAsmRoutines() override { return nullptr; }
bool HandleFault(uintptr_t access_address, SContext* ctx) override
{
m_pre_unprotect_time = std::chrono::high_resolution_clock::now();
Common::UnWriteProtectMemory(m_data, PAGE_GRAN, /*allowExecute*/ false);
m_post_unprotect_time = std::chrono::high_resolution_clock::now();
return true;
}
void* m_data = nullptr;
std::chrono::time_point<std::chrono::high_resolution_clock> m_pre_unprotect_time,
m_post_unprotect_time;
};
#ifdef _MSC_VER
#define ASAN_DISABLE __declspec(no_sanitize_address)
#else
#define ASAN_DISABLE
#endif
static void ASAN_DISABLE perform_invalid_access(void* data)
{
*(volatile int*)data = 5;
}
TEST(PageFault, PageFault)
{
if (!EMM::IsExceptionHandlerSupported())
GTEST_SKIP() << "Skipping PageFault test because exception handler is unsupported.";
EMM::InstallExceptionHandler();
void* data = Common::AllocateMemoryPages(PAGE_GRAN);
EXPECT_NE(data, nullptr);
Common::WriteProtectMemory(data, PAGE_GRAN, false);
Core::DeclareAsCPUThread();
Common::ScopeGuard cpu_thread_guard([] { Core::UndeclareAsCPUThread(); });
auto& system = Core::System::GetInstance();
auto unique_pfjit = std::make_unique<PageFaultFakeJit>(system);
auto& pfjit = *unique_pfjit;
system.GetJitInterface().SetJit(std::move(unique_pfjit));
pfjit.m_data = data;
auto start = std::chrono::high_resolution_clock::now();
perform_invalid_access(data);
auto end = std::chrono::high_resolution_clock::now();
auto difference_in_nanoseconds = [](auto diff_start, auto diff_end) {
return std::chrono::duration_cast<std::chrono::nanoseconds>(diff_end - diff_start).count();
};
EMM::UninstallExceptionHandler();
fmt::print("page fault timing:\n");
fmt::print("start->HandleFault {} ns\n",
difference_in_nanoseconds(start, pfjit.m_pre_unprotect_time));
fmt::print("UnWriteProtectMemory {} ns\n",
difference_in_nanoseconds(pfjit.m_pre_unprotect_time, pfjit.m_post_unprotect_time));
fmt::print("HandleFault->end {} ns\n",
difference_in_nanoseconds(pfjit.m_post_unprotect_time, end));
fmt::print("total {} ns\n", difference_in_nanoseconds(start, end));
system.GetJitInterface().SetJit(nullptr);
}