Merge pull request #4647 from degasus/jitcache

JitCache: Clean up block id handling.
This commit is contained in:
Matthew Parlane 2017-01-13 09:00:46 +13:00 committed by GitHub
commit 356619642b
8 changed files with 105 additions and 135 deletions

View File

@ -140,8 +140,7 @@ void CachedInterpreter::Jit(u32 address)
return; return;
} }
int block_num = m_block_cache.AllocateBlock(PC); JitBlock* b = m_block_cache.AllocateBlock(PC);
JitBlock* b = m_block_cache.GetBlock(block_num);
js.blockStart = PC; js.blockStart = PC;
js.firstFPInstructionFound = false; js.firstFPInstructionFound = false;
@ -212,7 +211,7 @@ void CachedInterpreter::Jit(u32 address)
b->codeSize = (u32)(GetCodePtr() - b->checkedEntry); b->codeSize = (u32)(GetCodePtr() - b->checkedEntry);
b->originalSize = code_block.m_num_instructions; b->originalSize = code_block.m_num_instructions;
m_block_cache.FinalizeBlock(block_num, jo.enableBlocklink, b->checkedEntry); m_block_cache.FinalizeBlock(*b, jo.enableBlocklink, b->checkedEntry);
} }
void CachedInterpreter::ClearCache() void CachedInterpreter::ClearCache()

View File

@ -589,9 +589,8 @@ void Jit64::Jit(u32 em_address)
return; return;
} }
int block_num = blocks.AllocateBlock(em_address); JitBlock* b = blocks.AllocateBlock(em_address);
JitBlock* b = blocks.GetBlock(block_num); blocks.FinalizeBlock(*b, jo.enableBlocklink, DoJit(em_address, &code_buffer, b, nextPC));
blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b, nextPC));
} }
const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC) const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC)

View File

@ -507,9 +507,8 @@ void JitIL::Jit(u32 em_address)
return; return;
} }
int block_num = blocks.AllocateBlock(em_address); JitBlock* b = blocks.AllocateBlock(em_address);
JitBlock* b = blocks.GetBlock(block_num); blocks.FinalizeBlock(*b, jo.enableBlocklink, DoJit(em_address, &code_buffer, b, nextPC));
blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b, nextPC));
} }
const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC) const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC)

View File

@ -398,10 +398,9 @@ void JitArm64::Jit(u32)
return; return;
} }
int block_num = blocks.AllocateBlock(em_address); JitBlock* b = blocks.AllocateBlock(em_address);
JitBlock* b = blocks.GetBlock(block_num);
const u8* BlockPtr = DoJit(em_address, &code_buffer, b, nextPC); const u8* BlockPtr = DoJit(em_address, &code_buffer, b, nextPC);
blocks.FinalizeBlock(block_num, jo.enableBlocklink, BlockPtr); blocks.FinalizeBlock(*b, jo.enableBlocklink, BlockPtr);
} }
const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC) const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC)

View File

@ -71,7 +71,7 @@ void JitBaseBlockCache::Clear()
m_jit.js.pairedQuantizeAddresses.clear(); m_jit.js.pairedQuantizeAddresses.clear();
for (int i = 1; i < num_blocks; i++) for (int i = 1; i < num_blocks; i++)
{ {
DestroyBlock(i, false); DestroyBlock(blocks[i], false);
} }
links_to.clear(); links_to.clear();
block_map.clear(); block_map.clear();
@ -96,12 +96,7 @@ void JitBaseBlockCache::SchedulateClearCacheThreadSafe()
bool JitBaseBlockCache::IsFull() const bool JitBaseBlockCache::IsFull() const
{ {
return GetNumBlocks() >= MAX_NUM_BLOCKS - 1; return num_blocks >= MAX_NUM_BLOCKS - 1;
}
JitBlock* JitBaseBlockCache::GetBlock(int no)
{
return &blocks[no];
} }
JitBlock* JitBaseBlockCache::GetBlocks() JitBlock* JitBaseBlockCache::GetBlocks()
@ -109,17 +104,18 @@ JitBlock* JitBaseBlockCache::GetBlocks()
return blocks.data(); return blocks.data();
} }
int JitBaseBlockCache::GetNumBlocks() const
{
return num_blocks;
}
int* JitBaseBlockCache::GetICache() int* JitBaseBlockCache::GetICache()
{ {
return iCache.data(); return iCache.data();
} }
int JitBaseBlockCache::AllocateBlock(u32 em_address) void JitBaseBlockCache::RunOnBlocks(std::function<void(const JitBlock&)> f)
{
for (int i = 0; i < num_blocks; i++)
f(blocks[i]);
}
JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address)
{ {
JitBlock& b = blocks[num_blocks]; JitBlock& b = blocks[num_blocks];
b.invalid = false; b.invalid = false;
@ -128,48 +124,47 @@ int JitBaseBlockCache::AllocateBlock(u32 em_address)
b.msrBits = MSR & JitBlock::JIT_CACHE_MSR_MASK; b.msrBits = MSR & JitBlock::JIT_CACHE_MSR_MASK;
b.linkData.clear(); b.linkData.clear();
num_blocks++; // commit the current block num_blocks++; // commit the current block
return num_blocks - 1; return &b;
} }
void JitBaseBlockCache::FinalizeBlock(int block_num, bool block_link, const u8* code_ptr) void JitBaseBlockCache::FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr)
{ {
JitBlock& b = blocks[block_num]; if (start_block_map.count(block.physicalAddress))
if (start_block_map.count(b.physicalAddress))
{ {
// We already have a block at this address; invalidate the old block. // We already have a block at this address; invalidate the old block.
// This should be very rare. This will only happen if the same block // This should be very rare. This will only happen if the same block
// is called both with DR/IR enabled or disabled. // is called both with DR/IR enabled or disabled.
WARN_LOG(DYNA_REC, "Invalidating compiled block at same address %08x", b.physicalAddress); WARN_LOG(DYNA_REC, "Invalidating compiled block at same address %08x", block.physicalAddress);
int old_block_num = start_block_map[b.physicalAddress]; JitBlock& old_b = *start_block_map[block.physicalAddress];
const JitBlock& old_b = blocks[old_block_num];
block_map.erase( block_map.erase(
std::make_pair(old_b.physicalAddress + 4 * old_b.originalSize - 1, old_b.physicalAddress)); std::make_pair(old_b.physicalAddress + 4 * old_b.originalSize - 1, old_b.physicalAddress));
DestroyBlock(old_block_num, true); DestroyBlock(old_b, true);
} }
start_block_map[b.physicalAddress] = block_num; const int block_num = static_cast<int>(&block - &blocks[0]);
FastLookupEntryForAddress(b.effectiveAddress) = block_num; start_block_map[block.physicalAddress] = &block;
FastLookupEntryForAddress(block.effectiveAddress) = block_num;
u32 pAddr = b.physicalAddress; u32 pAddr = block.physicalAddress;
for (u32 block = pAddr / 32; block <= (pAddr + (b.originalSize - 1) * 4) / 32; ++block) for (u32 addr = pAddr / 32; addr <= (pAddr + (block.originalSize - 1) * 4) / 32; ++addr)
valid_block.Set(block); valid_block.Set(addr);
block_map[std::make_pair(pAddr + 4 * b.originalSize - 1, pAddr)] = block_num; block_map[std::make_pair(pAddr + 4 * block.originalSize - 1, pAddr)] = &block;
if (block_link) if (block_link)
{ {
for (const auto& e : b.linkData) for (const auto& e : block.linkData)
{ {
links_to.emplace(e.exitAddress, block_num); links_to.emplace(e.exitAddress, &block);
} }
LinkBlock(block_num); LinkBlock(block);
} }
JitRegister::Register(b.checkedEntry, b.codeSize, "JIT_PPC_%08x", b.physicalAddress); JitRegister::Register(block.checkedEntry, block.codeSize, "JIT_PPC_%08x", block.physicalAddress);
} }
int JitBaseBlockCache::GetBlockNumberFromStartAddress(u32 addr, u32 msr) JitBlock* JitBaseBlockCache::GetBlockFromStartAddress(u32 addr, u32 msr)
{ {
u32 translated_addr = addr; u32 translated_addr = addr;
if (UReg_MSR(msr).IR) if (UReg_MSR(msr).IR)
@ -177,23 +172,20 @@ int JitBaseBlockCache::GetBlockNumberFromStartAddress(u32 addr, u32 msr)
auto translated = PowerPC::JitCache_TranslateAddress(addr); auto translated = PowerPC::JitCache_TranslateAddress(addr);
if (!translated.valid) if (!translated.valid)
{ {
return -1; return nullptr;
} }
translated_addr = translated.address; translated_addr = translated.address;
} }
auto map_result = start_block_map.find(translated_addr); auto map_result = start_block_map.find(translated_addr);
if (map_result == start_block_map.end()) if (map_result == start_block_map.end())
return -1; return nullptr;
int block_num = map_result->second;
const JitBlock& b = blocks[block_num]; JitBlock* b = map_result->second;
if (b.invalid) if (b->invalid || b->effectiveAddress != addr ||
return -1; b->msrBits != (msr & JitBlock::JIT_CACHE_MSR_MASK))
if (b.effectiveAddress != addr) return nullptr;
return -1; return b;
if (b.msrBits != (msr & JitBlock::JIT_CACHE_MSR_MASK))
return -1;
return block_num;
} }
const u8* JitBaseBlockCache::Dispatch() const u8* JitBaseBlockCache::Dispatch()
@ -235,7 +227,7 @@ void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool for
auto it = block_map.lower_bound(std::make_pair(pAddr, 0)); auto it = block_map.lower_bound(std::make_pair(pAddr, 0));
while (it != block_map.end() && it->first.second < pAddr + length) while (it != block_map.end() && it->first.second < pAddr + length)
{ {
DestroyBlock(it->second, true); DestroyBlock(*it->second, true);
it = block_map.erase(it); it = block_map.erase(it);
} }
@ -269,59 +261,53 @@ void JitBaseBlockCache::WriteDestroyBlock(const JitBlock& block)
// Can be faster by doing a queue for blocks to link up, and only process those // Can be faster by doing a queue for blocks to link up, and only process those
// Should probably be done // Should probably be done
void JitBaseBlockCache::LinkBlockExits(int i) void JitBaseBlockCache::LinkBlockExits(JitBlock& block)
{ {
JitBlock& b = blocks[i]; if (block.invalid)
if (b.invalid)
{ {
// This block is dead. Don't relink it. // This block is dead. Don't relink it.
return; return;
} }
for (auto& e : b.linkData) for (auto& e : block.linkData)
{ {
if (!e.linkStatus) if (!e.linkStatus)
{ {
int destinationBlock = GetBlockNumberFromStartAddress(e.exitAddress, b.msrBits); JitBlock* destinationBlock = GetBlockFromStartAddress(e.exitAddress, block.msrBits);
if (destinationBlock != -1) if (destinationBlock && !destinationBlock->invalid)
{ {
if (!blocks[destinationBlock].invalid) WriteLinkBlock(e, destinationBlock);
{ e.linkStatus = true;
WriteLinkBlock(e, &blocks[destinationBlock]);
e.linkStatus = true;
}
} }
} }
} }
} }
void JitBaseBlockCache::LinkBlock(int i) void JitBaseBlockCache::LinkBlock(JitBlock& block)
{ {
LinkBlockExits(i); LinkBlockExits(block);
const JitBlock& b = blocks[i]; auto ppp = links_to.equal_range(block.effectiveAddress);
auto ppp = links_to.equal_range(b.effectiveAddress);
for (auto iter = ppp.first; iter != ppp.second; ++iter) for (auto iter = ppp.first; iter != ppp.second; ++iter)
{ {
const JitBlock& b2 = blocks[iter->second]; JitBlock& b2 = *iter->second;
if (b.msrBits == b2.msrBits) if (block.msrBits == b2.msrBits)
LinkBlockExits(iter->second); LinkBlockExits(b2);
} }
} }
void JitBaseBlockCache::UnlinkBlock(int i) void JitBaseBlockCache::UnlinkBlock(const JitBlock& block)
{ {
JitBlock& b = blocks[i]; auto ppp = links_to.equal_range(block.effectiveAddress);
auto ppp = links_to.equal_range(b.effectiveAddress);
for (auto iter = ppp.first; iter != ppp.second; ++iter) for (auto iter = ppp.first; iter != ppp.second; ++iter)
{ {
JitBlock& sourceBlock = blocks[iter->second]; JitBlock& sourceBlock = *iter->second;
if (sourceBlock.msrBits != b.msrBits) if (sourceBlock.msrBits != block.msrBits)
continue; continue;
for (auto& e : sourceBlock.linkData) for (auto& e : sourceBlock.linkData)
{ {
if (e.exitAddress == b.effectiveAddress) if (e.exitAddress == block.effectiveAddress)
{ {
WriteLinkBlock(e, nullptr); WriteLinkBlock(e, nullptr);
e.linkStatus = false; e.linkStatus = false;
@ -330,51 +316,45 @@ void JitBaseBlockCache::UnlinkBlock(int i)
} }
} }
void JitBaseBlockCache::DestroyBlock(int block_num, bool invalidate) void JitBaseBlockCache::DestroyBlock(JitBlock& block, bool invalidate)
{ {
if (block_num < 0 || block_num >= num_blocks) if (block.invalid)
{
PanicAlert("DestroyBlock: Invalid block number %d", block_num);
return;
}
JitBlock& b = blocks[block_num];
if (b.invalid)
{ {
if (invalidate) if (invalidate)
PanicAlert("Invalidating invalid block %d", block_num); PanicAlert("Invalidating invalid block %p", &block);
return; return;
} }
b.invalid = true; block.invalid = true;
start_block_map.erase(b.physicalAddress); start_block_map.erase(block.physicalAddress);
FastLookupEntryForAddress(b.effectiveAddress) = 0; FastLookupEntryForAddress(block.effectiveAddress) = 0;
UnlinkBlock(block_num); UnlinkBlock(block);
// Delete linking addresses // Delete linking addresses
auto it = links_to.equal_range(b.effectiveAddress); auto it = links_to.equal_range(block.effectiveAddress);
while (it.first != it.second) while (it.first != it.second)
{ {
if (it.first->second == block_num) if (it.first->second == &block)
it.first = links_to.erase(it.first); it.first = links_to.erase(it.first);
else else
it.first++; it.first++;
} }
// Raise an signal if we are going to call this block again // Raise an signal if we are going to call this block again
WriteDestroyBlock(b); WriteDestroyBlock(block);
} }
void JitBaseBlockCache::MoveBlockIntoFastCache(u32 addr, u32 msr) void JitBaseBlockCache::MoveBlockIntoFastCache(u32 addr, u32 msr)
{ {
int block_num = GetBlockNumberFromStartAddress(addr, msr); JitBlock* block = GetBlockFromStartAddress(addr, msr);
if (block_num < 0) if (!block)
{ {
Jit(addr); Jit(addr);
} }
else else
{ {
FastLookupEntryForAddress(addr) = block_num; FastLookupEntryForAddress(addr) = static_cast<int>(block - &blocks[0]);
LinkBlock(block_num); LinkBlock(*block);
} }
} }

View File

@ -6,6 +6,7 @@
#include <array> #include <array>
#include <bitset> #include <bitset>
#include <functional>
#include <map> #include <map>
#include <memory> #include <memory>
#include <vector> #include <vector>
@ -126,17 +127,17 @@ public:
bool IsFull() const; bool IsFull() const;
// Code Cache // Code Cache
JitBlock* GetBlock(int block_num);
JitBlock* GetBlocks(); JitBlock* GetBlocks();
int GetNumBlocks() const;
int* GetICache(); int* GetICache();
void RunOnBlocks(std::function<void(const JitBlock&)> f);
int AllocateBlock(u32 em_address); JitBlock* AllocateBlock(u32 em_address);
void FinalizeBlock(int block_num, bool block_link, const u8* code_ptr); void FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr);
// Look for the block in the slow but accurate way. // Look for the block in the slow but accurate way.
// This function shall be used if FastLookupEntryForAddress() failed. // This function shall be used if FastLookupEntryForAddress() failed.
int GetBlockNumberFromStartAddress(u32 em_address, u32 msr); // This might return nullptr if there is no such block.
JitBlock* GetBlockFromStartAddress(u32 em_address, u32 msr);
// Get the normal entry for the block associated with the current program // Get the normal entry for the block associated with the current program
// counter. This will JIT code if necessary. (This is the reference // counter. This will JIT code if necessary. (This is the reference
@ -155,10 +156,10 @@ private:
virtual void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) = 0; virtual void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) = 0;
virtual void WriteDestroyBlock(const JitBlock& block); virtual void WriteDestroyBlock(const JitBlock& block);
void LinkBlockExits(int i); void LinkBlockExits(JitBlock& block);
void LinkBlock(int i); void LinkBlock(JitBlock& block);
void UnlinkBlock(int i); void UnlinkBlock(const JitBlock& block);
void DestroyBlock(int block_num, bool invalidate); void DestroyBlock(JitBlock& block, bool invalidate);
void MoveBlockIntoFastCache(u32 em_address, u32 msr); void MoveBlockIntoFastCache(u32 em_address, u32 msr);
@ -172,16 +173,16 @@ private:
// links_to hold all exit points of all valid blocks in a reverse way. // links_to hold all exit points of all valid blocks in a reverse way.
// It is used to query all blocks which links to an address. // It is used to query all blocks which links to an address.
std::multimap<u32, int> links_to; // destination_PC -> number std::multimap<u32, JitBlock*> links_to; // destination_PC -> number
// Map indexed by the physical memory location. // Map indexed by the physical memory location.
// It is used to invalidate blocks based on memory location. // It is used to invalidate blocks based on memory location.
std::map<std::pair<u32, u32>, u32> block_map; // (end_addr, start_addr) -> number std::map<std::pair<u32, u32>, JitBlock*> block_map; // (end_addr, start_addr) -> block
// Map indexed by the physical address of the entry point. // Map indexed by the physical address of the entry point.
// This is used to query the block based on the current PC in a slow way. // This is used to query the block based on the current PC in a slow way.
// TODO: This is redundant with block_map, and both should be a multimap. // TODO: This is redundant with block_map, and both should be a multimap.
std::map<u32, u32> start_block_map; // start_addr -> number std::map<u32, JitBlock*> start_block_map; // start_addr -> block
// This bitsets shows which cachelines overlap with any blocks. // This bitsets shows which cachelines overlap with any blocks.
// It is used to provide a fast way to query if no icache invalidation is needed. // It is used to provide a fast way to query if no icache invalidation is needed.

View File

@ -134,26 +134,23 @@ void GetProfileResults(ProfileStats* prof_stats)
prof_stats->cost_sum = 0; prof_stats->cost_sum = 0;
prof_stats->timecost_sum = 0; prof_stats->timecost_sum = 0;
prof_stats->block_stats.clear(); prof_stats->block_stats.clear();
prof_stats->block_stats.reserve(g_jit->GetBlockCache()->GetNumBlocks());
Core::EState old_state = Core::GetState(); Core::EState old_state = Core::GetState();
if (old_state == Core::CORE_RUN) if (old_state == Core::CORE_RUN)
Core::SetState(Core::CORE_PAUSE); Core::SetState(Core::CORE_PAUSE);
QueryPerformanceFrequency((LARGE_INTEGER*)&prof_stats->countsPerSec); QueryPerformanceFrequency((LARGE_INTEGER*)&prof_stats->countsPerSec);
for (int i = 0; i < g_jit->GetBlockCache()->GetNumBlocks(); i++) g_jit->GetBlockCache()->RunOnBlocks([&prof_stats](const JitBlock& block) {
{
const JitBlock* block = g_jit->GetBlockCache()->GetBlock(i);
// Rough heuristic. Mem instructions should cost more. // Rough heuristic. Mem instructions should cost more.
u64 cost = block->originalSize * (block->runCount / 4); u64 cost = block.originalSize * (block.runCount / 4);
u64 timecost = block->ticCounter; u64 timecost = block.ticCounter;
// Todo: tweak. // Todo: tweak.
if (block->runCount >= 1) if (block.runCount >= 1)
prof_stats->block_stats.emplace_back(i, block->effectiveAddress, cost, timecost, prof_stats->block_stats.emplace_back(block.effectiveAddress, cost, timecost, block.runCount,
block->runCount, block->codeSize); block.codeSize);
prof_stats->cost_sum += cost; prof_stats->cost_sum += cost;
prof_stats->timecost_sum += timecost; prof_stats->timecost_sum += timecost;
} });
sort(prof_stats->block_stats.begin(), prof_stats->block_stats.end()); sort(prof_stats->block_stats.begin(), prof_stats->block_stats.end());
if (old_state == Core::CORE_RUN) if (old_state == Core::CORE_RUN)
@ -168,34 +165,31 @@ int GetHostCode(u32* address, const u8** code, u32* code_size)
return 1; return 1;
} }
int block_num = g_jit->GetBlockCache()->GetBlockNumberFromStartAddress(*address, MSR); JitBlock* block = g_jit->GetBlockCache()->GetBlockFromStartAddress(*address, MSR);
if (block_num < 0) if (!block)
{ {
for (int i = 0; i < 500; i++) for (int i = 0; i < 500; i++)
{ {
block_num = g_jit->GetBlockCache()->GetBlockNumberFromStartAddress(*address - 4 * i, MSR); block = g_jit->GetBlockCache()->GetBlockFromStartAddress(*address - 4 * i, MSR);
if (block_num >= 0) if (block)
break; break;
} }
if (block_num >= 0) if (block)
{ {
JitBlock* block = g_jit->GetBlockCache()->GetBlock(block_num);
if (!(block->effectiveAddress <= *address && if (!(block->effectiveAddress <= *address &&
block->originalSize + block->effectiveAddress >= *address)) block->originalSize + block->effectiveAddress >= *address))
block_num = -1; block = nullptr;
} }
// Do not merge this "if" with the above - block_num changes inside it. // Do not merge this "if" with the above - block_num changes inside it.
if (block_num < 0) if (!block)
{ {
*code_size = 0; *code_size = 0;
return 2; return 2;
} }
} }
JitBlock* block = g_jit->GetBlockCache()->GetBlock(block_num);
*code = block->checkedEntry; *code = block->checkedEntry;
*code_size = block->codeSize; *code_size = block->codeSize;
*address = block->effectiveAddress; *address = block->effectiveAddress;

View File

@ -43,11 +43,10 @@
struct BlockStat struct BlockStat
{ {
BlockStat(int bn, u32 _addr, u64 c, u64 ticks, u64 run, u32 size) BlockStat(u32 _addr, u64 c, u64 ticks, u64 run, u32 size)
: blockNum(bn), addr(_addr), cost(c), tick_counter(ticks), run_count(run), block_size(size) : addr(_addr), cost(c), tick_counter(ticks), run_count(run), block_size(size)
{ {
} }
int blockNum;
u32 addr; u32 addr;
u64 cost; u64 cost;
u64 tick_counter; u64 tick_counter;