mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-14 01:00:43 +02:00
Creates a pool allocator for OpcodeDispatcher and IRCompaction that shares memory allocations between threads in a pool and supports reclaiming stale allocations from participating threads. A thread will use a heuristic to keep its claimed memory allocation around if it is allocating a lot of code. If it slows down then it will start putting the memory allocation back in to the thread pool. Additionally if the allocation has been "disowned" and gone to sleep while still retaining the allocation, then another thread can inspect these stale allocations and reclaim it from the idling thread. Saving further memory. This needs some more work and cleanup but this is an interesting concept that saves a decent amount of memory even in a basic test. Causes teeworlds' title screen to go from 754MB to 599MB in my simple test. 79.4% the memory usage is a good start.
104 lines
2.2 KiB
C++
104 lines
2.2 KiB
C++
/*
|
|
$info$
|
|
tags: ir|opts
|
|
$end_info$
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <FEXCore/Config/Config.h>
|
|
#include <FEXCore/Utils/ThreadPoolAllocator.h>
|
|
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace FEXCore::HLE {
|
|
class SyscallHandler;
|
|
}
|
|
|
|
namespace FEXCore::IR {
|
|
class PassManager;
|
|
class IREmitter;
|
|
|
|
using ShouldExitHandler = std::function<void(void)>;
|
|
|
|
class Pass {
|
|
public:
|
|
virtual ~Pass() = default;
|
|
virtual bool Run(IREmitter *IREmit) = 0;
|
|
|
|
void RegisterPassManager(PassManager *_Manager) {
|
|
Manager = _Manager;
|
|
}
|
|
|
|
protected:
|
|
PassManager *Manager;
|
|
};
|
|
|
|
class PassManager final {
|
|
friend class SyscallOptimization;
|
|
public:
|
|
void AddDefaultPasses(FEXCore::Context::Context *ctx, bool InlineConstants, bool StaticRegisterAllocation);
|
|
void AddDefaultValidationPasses();
|
|
Pass* InsertPass(std::unique_ptr<Pass> Pass, std::string Name = "") {
|
|
Pass->RegisterPassManager(this);
|
|
auto PassPtr = Passes.emplace_back(std::move(Pass)).get();
|
|
|
|
if (!Name.empty()) {
|
|
NameToPassMaping[Name] = PassPtr;
|
|
}
|
|
return PassPtr;
|
|
}
|
|
|
|
void InsertRegisterAllocationPass(bool OptimizeSRA);
|
|
|
|
bool Run(IREmitter *IREmit);
|
|
|
|
void RegisterExitHandler(ShouldExitHandler Handler) {
|
|
ExitHandler = std::move(Handler);
|
|
}
|
|
|
|
bool HasPass(std::string Name) const {
|
|
return NameToPassMaping.contains(Name);
|
|
}
|
|
|
|
template<typename T>
|
|
T* GetPass(std::string Name) {
|
|
return dynamic_cast<T*>(NameToPassMaping[Name]);
|
|
}
|
|
|
|
Pass* GetPass(std::string Name) {
|
|
return NameToPassMaping[Name];
|
|
}
|
|
|
|
void RegisterSyscallHandler(FEXCore::HLE::SyscallHandler *Handler) {
|
|
SyscallHandler = Handler;
|
|
}
|
|
|
|
protected:
|
|
ShouldExitHandler ExitHandler;
|
|
FEXCore::HLE::SyscallHandler *SyscallHandler;
|
|
|
|
private:
|
|
std::vector<std::unique_ptr<Pass>> Passes;
|
|
std::unordered_map<std::string, Pass*> NameToPassMaping;
|
|
|
|
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
|
|
std::vector<std::unique_ptr<Pass>> ValidationPasses;
|
|
void InsertValidationPass(std::unique_ptr<Pass> Pass, std::string Name = "") {
|
|
Pass->RegisterPassManager(this);
|
|
auto PassPtr = ValidationPasses.emplace_back(std::move(Pass)).get();
|
|
|
|
if (!Name.empty()) {
|
|
NameToPassMaping[Name] = PassPtr;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE);
|
|
};
|
|
}
|
|
|