mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 17:00:19 +02:00
Merge pull request #1155 from Sonicadvance1/improve_startup_time
Switch some memory allocations over to mmap
This commit is contained in:
5 files changed
+57
-23
No files matched your search
+26
-16
@@ -16,6 +16,7 @@ $end_info$
|
||||
#include <FEXCore/Debug/X86Tables.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <set>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace FEXCore::Frontend {
|
||||
using namespace FEXCore::X86Tables;
|
||||
@@ -122,7 +123,16 @@ static uint32_t MapModRMToReg(uint8_t REX, uint8_t bits, bool HighBits, bool Has
|
||||
|
||||
Decoder::Decoder(FEXCore::Context::Context *ctx)
|
||||
: CTX {ctx} {
|
||||
DecodedBuffer.resize(DefaultDecodedBufferSize);
|
||||
// Using mmap is a start-up time optimization
|
||||
// Take advantage of page faulting to reduce startup time for minimal runtime cost
|
||||
DecodedBuffer =
|
||||
reinterpret_cast<FEXCore::X86Tables::DecodedInst *>(
|
||||
::mmap(0, sizeof(FEXCore::X86Tables::DecodedInst) * DefaultDecodedBufferSize,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
}
|
||||
|
||||
Decoder::~Decoder() {
|
||||
::munmap(DecodedBuffer, sizeof(FEXCore::X86Tables::DecodedInst) * DefaultDecodedBufferSize);
|
||||
}
|
||||
|
||||
uint8_t Decoder::ReadByte() {
|
||||
@@ -214,28 +224,28 @@ void Decoder::DecodeModRM_16(X86Tables::DecodedOperand *Operand, X86Tables::ModR
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_RDI},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_RSI},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_RDI},
|
||||
{FEXCore::X86State::REG_RSI, 255},
|
||||
{FEXCore::X86State::REG_RDI, 255},
|
||||
{255, 255},
|
||||
{FEXCore::X86State::REG_RBX, 255},
|
||||
{FEXCore::X86State::REG_RSI, FEXCore::X86State::REG_INVALID},
|
||||
{FEXCore::X86State::REG_RDI, FEXCore::X86State::REG_INVALID},
|
||||
{FEXCore::X86State::REG_INVALID, FEXCore::X86State::REG_INVALID},
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_INVALID},
|
||||
// Mod = 0b01
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_RSI},
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_RDI},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_RSI},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_RDI},
|
||||
{FEXCore::X86State::REG_RSI, 255},
|
||||
{FEXCore::X86State::REG_RDI, 255},
|
||||
{FEXCore::X86State::REG_RBP, 255},
|
||||
{FEXCore::X86State::REG_RBX, 255},
|
||||
{FEXCore::X86State::REG_RSI, FEXCore::X86State::REG_INVALID},
|
||||
{FEXCore::X86State::REG_RDI, FEXCore::X86State::REG_INVALID},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_INVALID},
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_INVALID},
|
||||
// Mod = 0b10
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_RSI},
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_RDI},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_RSI},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_RDI},
|
||||
{FEXCore::X86State::REG_RSI, 255},
|
||||
{FEXCore::X86State::REG_RDI, 255},
|
||||
{FEXCore::X86State::REG_RBP, 255},
|
||||
{FEXCore::X86State::REG_RBX, 255},
|
||||
{FEXCore::X86State::REG_RSI, FEXCore::X86State::REG_INVALID},
|
||||
{FEXCore::X86State::REG_RDI, FEXCore::X86State::REG_INVALID},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_INVALID},
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_INVALID},
|
||||
}};
|
||||
|
||||
uint8_t LookupIndex = ModRM.mod << 3 | ModRM.rm;
|
||||
@@ -929,7 +939,7 @@ bool Decoder::DecodeInstruction(uint64_t PC) {
|
||||
}
|
||||
|
||||
if (DecodeInst->Dest.IsGPR()) {
|
||||
assert(DecodeInst->Dest.Data.GPR.GPR != 255);
|
||||
assert(DecodeInst->Dest.Data.GPR.GPR != FEXCore::X86State::REG_INVALID);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1091,7 +1101,7 @@ bool Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC)
|
||||
}
|
||||
|
||||
if (DecodedSize >= CTX->Config.MaxInstPerBlock ||
|
||||
DecodedSize >= DecodedBuffer.size()) {
|
||||
DecodedSize >= DefaultDecodedBufferSize) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1108,7 +1118,7 @@ bool Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC)
|
||||
|
||||
// Copy over only the number of instructions we decoded
|
||||
CurrentBlockDecoding.NumInstructions = BlockNumberOfInstructions;
|
||||
CurrentBlockDecoding.DecodedInstructions = &DecodedBuffer.at(BlockStartOffset);
|
||||
CurrentBlockDecoding.DecodedInstructions = &DecodedBuffer[BlockStartOffset];
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-1
@@ -24,6 +24,7 @@ public:
|
||||
};
|
||||
|
||||
Decoder(FEXCore::Context::Context *ctx);
|
||||
~Decoder();
|
||||
bool DecodeInstructionsAtEntry(uint8_t const* InstStream, uint64_t PC);
|
||||
|
||||
std::vector<DecodedBlocks> const *GetDecodedBlocks() const {
|
||||
@@ -50,7 +51,7 @@ private:
|
||||
bool NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op);
|
||||
|
||||
static constexpr size_t DefaultDecodedBufferSize = 0x10000;
|
||||
std::vector<FEXCore::X86Tables::DecodedInst> DecodedBuffer;
|
||||
FEXCore::X86Tables::DecodedInst *DecodedBuffer{};
|
||||
size_t DecodedSize {};
|
||||
|
||||
uint8_t const *InstStream;
|
||||
|
||||
@@ -12,6 +12,7 @@ $end_info$
|
||||
|
||||
#include <iterator>
|
||||
#include <unordered_set>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define SRA_DEBUG(...) // printf(__VA_ARGS__)
|
||||
|
||||
@@ -177,6 +178,7 @@ namespace {
|
||||
};
|
||||
|
||||
static_assert(sizeof(RegisterNode) == 128 * 4);
|
||||
constexpr size_t REGISTER_NODES_PER_PAGE = FEXCore::Core::PAGE_SIZE / sizeof(RegisterNode);
|
||||
|
||||
struct RegisterSet {
|
||||
std::vector<RegisterClass> Classes;
|
||||
@@ -204,8 +206,8 @@ namespace {
|
||||
struct RegisterGraph {
|
||||
std::unique_ptr<FEXCore::IR::RegisterAllocationData, FEXCore::IR::RegisterAllocationDataDeleter> AllocData;
|
||||
RegisterSet Set;
|
||||
std::vector<RegisterNode> Nodes;
|
||||
uint32_t NodeCount;
|
||||
RegisterNode *Nodes{};
|
||||
uint32_t NodeCount{};
|
||||
std::vector<SpillStackUnit> SpillStack;
|
||||
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> BlockPredecessors;
|
||||
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> VisitedNodePredecessors;
|
||||
@@ -254,15 +256,30 @@ namespace {
|
||||
}
|
||||
|
||||
void FreeRegisterGraph(RegisterGraph *Graph) {
|
||||
if (Graph->Nodes) {
|
||||
::munmap(Graph->Nodes, Graph->NodeCount * sizeof(RegisterNode));
|
||||
}
|
||||
delete Graph;
|
||||
}
|
||||
|
||||
void ResetRegisterGraph(RegisterGraph *Graph, uint64_t NodeCount) {
|
||||
NodeCount = AlignUp(NodeCount, sizeof(uint64_t));
|
||||
Graph->Nodes.clear();
|
||||
Graph->Nodes.resize(NodeCount);
|
||||
NodeCount = AlignUp(NodeCount, REGISTER_NODES_PER_PAGE);
|
||||
if (Graph->NodeCount < NodeCount) {
|
||||
if (Graph->Nodes) {
|
||||
// If the needed node count is smaller than what we currently have allocated
|
||||
// then unmap it so we can remap a larger memory space
|
||||
::munmap(Graph->Nodes, Graph->NodeCount * sizeof(RegisterNode));
|
||||
}
|
||||
|
||||
// We don't have a mapping, allocate a space that gives us a default zero mapping
|
||||
Graph->Nodes = reinterpret_cast<RegisterNode *>(::mmap(0, NodeCount * sizeof(RegisterNode), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
}
|
||||
else {
|
||||
// If we already have an allocation then zero out how many nodes we need
|
||||
memset(Graph->Nodes, 0, NodeCount * sizeof(RegisterNode));
|
||||
}
|
||||
|
||||
Graph->VisitedNodePredecessors.clear();
|
||||
Graph->AllocData.reset();
|
||||
Graph->AllocData.reset((FEXCore::IR::RegisterAllocationData*)FEXCore::Allocator::malloc(FEXCore::IR::RegisterAllocationData::Size(NodeCount)));
|
||||
memset(&Graph->AllocData->Map[0], INVALID_REGCLASS.Raw, NodeCount);
|
||||
Graph->AllocData->MapCount = NodeCount;
|
||||
|
||||
@@ -84,3 +84,6 @@ time_test
|
||||
# The behaviour of this changes depending on if you have asserts enabled or not
|
||||
# siginfo_t with unsynchronized context
|
||||
pause_test
|
||||
|
||||
# ARMv8.4 periodically flakes on this one
|
||||
rtsignal_test
|
||||
@@ -170,3 +170,6 @@ stat_times_test
|
||||
# The behaviour of this changes depending on if you have asserts enabled or not
|
||||
# siginfo_t with unsynchronized context
|
||||
pause_test
|
||||
|
||||
# ARMv8.4 periodically flakes on this one
|
||||
rtsignal_test
|
||||
Reference in new issue
Block a user