Skip to content
This repository has been archived by the owner on Jul 10, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1646 from reicast/skmp/fault-based-code-discard
Browse files Browse the repository at this point in the history
JIT: Fault based code discard
  • Loading branch information
skmp committed Jul 11, 2019
2 parents 201bf15 + 974653e commit 40971b6
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 11 deletions.
102 changes: 100 additions & 2 deletions core/hw/sh4/dyna/blockmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
//#include "../tmu.h"
#include "hw/sh4/sh4_mem.h"

#define printf_bm printf

#if FEAT_SHREC != DYNAREC_NONE

Expand All @@ -31,6 +32,9 @@ typedef set<RuntimeBlockInfo*> bm_List;
bm_List all_blocks;
bm_List del_blocks;

bm_List page_blocks[RAM_SIZE/PAGE_SIZE];
bool page_has_data[RAM_SIZE/PAGE_SIZE];

std::map<void*, RuntimeBlockInfo*> blkmap;
u32 bm_gc_luc,bm_gcf_luc;

Expand Down Expand Up @@ -99,7 +103,7 @@ RuntimeBlockInfo* bm_GetStaleBlock(void* dynarec_code)
return 0;
}

void bm_AddBlock(RuntimeBlockInfo* blk)
void bm_AddBlock(RuntimeBlockInfo* blk, bool lockRam)
{
auto iter = blkmap.find((void*)blk->code);
if (iter != blkmap.end()) {
Expand All @@ -111,6 +115,19 @@ void bm_AddBlock(RuntimeBlockInfo* blk)

verify((void*)bm_GetCode(blk->addr)==(void*)ngen_FailedToFindBlock);
FPCA(blk->addr) = (DynarecCodeEntryPtr)CC_RW2RX(blk->code);

u32 code_ram_page_base = (blk->addr&RAM_MASK)/PAGE_SIZE;
u32 code_ram_page_top = ((blk->addr+blk->sh4_code_size-1)&RAM_MASK)/PAGE_SIZE;

for (u32 ram_page=code_ram_page_base; ram_page<=code_ram_page_top; ram_page++)
{
page_blocks[ram_page].insert(blk);

if (lockRam)
{
mem_b.LockRegion(ram_page * PAGE_SIZE, PAGE_SIZE);
}
}
}

void bm_DiscardBlock(RuntimeBlockInfo* blk)
Expand All @@ -131,6 +148,14 @@ void bm_DiscardBlock(RuntimeBlockInfo* blk)
verify((void*)bm_GetCode(blk->addr)==(void*)blk->code);
FPCA(blk->addr) = (DynarecCodeEntryPtr)ngen_FailedToFindBlock;
verify((void*)bm_GetCode(blk->addr)==(void*)ngen_FailedToFindBlock);

u32 code_ram_page_base = (blk->addr&RAM_MASK)/PAGE_SIZE;
u32 code_ram_page_top = ((blk->addr+blk->sh4_code_size-1)&RAM_MASK)/PAGE_SIZE;

for (u32 ram_page=code_ram_page_base; ram_page<=code_ram_page_top; ram_page++)
{
page_blocks[ram_page].erase(blk);
}
}

void bm_DiscardAddress(u32 codeaddr)
Expand Down Expand Up @@ -159,9 +184,27 @@ void bm_vmem_pagefill(void** ptr, u32 size_bytes)

void bm_Reset()
{
// reset ngen
ngen_ResetBlocks();

// reset lookup table via vmem
_vmem_bm_reset();


// clear page/block lists
memset(page_has_data, 0, sizeof(page_has_data));

for (auto i=0; i<RAM_SIZE/PAGE_SIZE; i++)
{
if (i * PAGE_SIZE < 65536)
{
page_has_data[i] = true;
}

page_blocks[i].clear();
}

// clear all blocks
for (auto it=all_blocks.begin(); it!=all_blocks.end(); it++)
{
(*it)->relink_data=0;
Expand All @@ -170,13 +213,14 @@ void bm_Reset()
(*it)->Relink();
}

// mark blocks for deletion
del_blocks.insert(all_blocks.begin(),all_blocks.end());

// clear all remaining block lists
all_blocks.clear();
blkmap.clear();
}


void bm_Init()
{

Expand Down Expand Up @@ -221,6 +265,11 @@ void RuntimeBlockInfo::Discard()

(*it)->Relink();
}

pBranchBlock = nullptr;
pNextBlock = nullptr;

Relink();
//die("Discard not implemented");
}

Expand Down Expand Up @@ -257,5 +306,54 @@ void bm_sh4_jitsym(FILE* out)
die("bm_sh4_jitsym is noop");
}

bool bm_LockedWrite(u8* addy)
{
ptrdiff_t offset=addy-virt_ram_base;

//printf_bm("BM_LW: Checking @ %p %08X\n", addy, offset);


if (offset > 0 && offset <= 0xFFFFFFFF && IsOnRam((u32)offset))
{
u32 ram_offset = offset & RAM_MASK;
u32 ram_page = ram_offset / PAGE_SIZE;
u32 ram_obase = ram_page * PAGE_SIZE;

printf_bm("BM_LW: Pagefault @ %p %08X %08X\n", addy, ram_offset, ram_page);

page_has_data[ram_page] = true;

// Make a local copy so we can remove from the page_blocks list while iterating
auto list = page_blocks[ram_page];

for (auto it = list.begin(); it != list.end(); it++)
{
bm_DiscardBlock(*it);
}


mem_b.UnLockRegion(ram_obase, PAGE_SIZE);

return true;
}
else
return false;
}

bool bm_RamPageHasData(u32 guest_addr, u32 len)
{
auto page_base = (guest_addr & RAM_MASK)/PAGE_SIZE;
auto page_top = ((guest_addr + len - 1) & RAM_MASK)/PAGE_SIZE;

bool rv = false;

for (auto i = page_base; i <= page_top; i++)
{
rv |= page_has_data[i];
}

return rv;
}

#endif

6 changes: 4 additions & 2 deletions core/hw/sh4/dyna/blockmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ RuntimeBlockInfo* bm_GetBlock(void* dynarec_code);
RuntimeBlockInfo* bm_GetStaleBlock(void* dynarec_code);
RuntimeBlockInfo* DYNACALL bm_GetBlock(u32 addr);

void bm_AddBlock(RuntimeBlockInfo* blk);
void bm_AddBlock(RuntimeBlockInfo* blk, bool lockRam);
void bm_DiscardBlock(RuntimeBlockInfo* blk);

void bm_Reset();
Expand All @@ -113,4 +113,6 @@ void bm_Term();

void bm_vmem_pagefill(void** ptr,u32 PAGE_SZ);

void bm_sh4_jitsym(FILE* out);
void bm_sh4_jitsym(FILE* out);
bool bm_LockedWrite(u8* addy);
bool bm_RamPageHasData(u32 guest_addr, u32 len);
20 changes: 17 additions & 3 deletions core/hw/sh4/dyna/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,21 @@ u32 emit_FreeSpace()
}


SmcCheckEnum DoCheck(u32 pc)
SmcCheckEnum DoCheck(u32 pc, u32 len)
{
// no need for checks if fault based discard is used for this block
if (!bm_RamPageHasData(pc, len))
{
// printf("FAST CHECK %08X, %d\n", pc, len);

return NoCheck; //FaultCheck; //ValidationCheck;
}
else
{
// printf("SLOW CHECK %08X, %d\n", pc, len);
}

// if no fault based discards, use whatever options
switch (settings.dynarec.SmcCheckLevel) {

// Heuristic-elimintaed FastChecks
Expand Down Expand Up @@ -249,10 +261,12 @@ DynarecCodeEntryPtr rdv_CompilePC()

bool do_opts=((rbi->addr&0x3FFFFFFF)>0x0C010100);
rbi->staging_runs=do_opts?100:-100;
ngen_Compile(rbi,DoCheck(rbi->addr),(pc&0xFFFFFF)==0x08300 || (pc&0xFFFFFF)==0x10000,false,do_opts);
ngen_Compile(rbi,DoCheck(rbi->addr, rbi->sh4_code_size),(pc&0xFFFFFF)==0x08300 || (pc&0xFFFFFF)==0x10000,false,do_opts);
verify(rbi->code!=0);

bm_AddBlock(rbi);
bool doLock = !bm_RamPageHasData(rbi->addr, rbi->sh4_code_size); // && maybe some setting?

bm_AddBlock(rbi, doLock);

if (rbi->BlockType==BET_Cond_0 || rbi->BlockType==BET_Cond_1)
pc=rbi->NextBlock;
Expand Down
2 changes: 1 addition & 1 deletion core/linux/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)

bool dyna_cde = ((unat)CC_RX2RW(ctx.pc) > (unat)CodeCache) && ((unat)CC_RX2RW(ctx.pc) < (unat)(CodeCache + CODE_SIZE));

if (VramLockedWrite((u8*)si->si_addr) || _vmem_bm_LockedWrite((u8*)si->si_addr))
if (VramLockedWrite((u8*)si->si_addr) || _vmem_bm_LockedWrite((u8*)si->si_addr) || bm_LockedWrite((u8*)si->si_addr))
return;
#if FEAT_SHREC == DYNAREC_JIT
#if HOST_CPU==CPU_ARM
Expand Down
2 changes: 1 addition & 1 deletion core/oslib/audiobackend_alsa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ static u32 alsa_push(void* frame, u32 samples, bool wait)
}
else if (rc < 0)
{
fprintf(stderr, "ALSA: error from writei: %s\n", snd_strerror(rc));
//fprintf(stderr, "ALSA: error from writei: %s\n", snd_strerror(rc));
}
else if (rc != samples)
{
Expand Down
15 changes: 14 additions & 1 deletion core/rec-x64/rec_x64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ static void ngen_blockcheckfail(u32 pc) {
rdv_BlockCheckFail(pc);
}

static void ngen_blockcheckfail2(u32 pc) {
printf("****** ERROR********* X64 JIT: SMC invalidation at %08X\n", pc);
rdv_BlockCheckFail(pc);
die("ngen_blockcheckfail2")
}

class BlockCompiler : public Xbyak::CodeGenerator
{
public:
Expand Down Expand Up @@ -1163,6 +1169,7 @@ class BlockCompiler : public Xbyak::CodeGenerator
void CheckBlock(SmcCheckEnum smc_checks, RuntimeBlockInfo* block) {

switch (smc_checks) {
case FaultCheck:
case NoCheck:
return;

Expand All @@ -1179,6 +1186,7 @@ class BlockCompiler : public Xbyak::CodeGenerator
}
break;

case ValidationCheck:
case FullCheck: {
s32 sz=block->sh4_code_size;
u32 sa=block->addr;
Expand Down Expand Up @@ -1210,7 +1218,12 @@ class BlockCompiler : public Xbyak::CodeGenerator
sz -= 2;
sa += 2;
}
jne(reinterpret_cast<const void*>(CC_RX2RW(&ngen_blockcheckfail)));

if (smc_checks == FullCheck)
jne(reinterpret_cast<const void*>(CC_RX2RW(&ngen_blockcheckfail)));
else
jne(reinterpret_cast<const void*>(CC_RX2RW(&ngen_blockcheckfail2)));

ptr = (void*)GetMemPtr(sa, sz > 8 ? 8 : sz);
}
}
Expand Down
4 changes: 3 additions & 1 deletion core/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -603,9 +603,11 @@ struct RegisterStruct
};

enum SmcCheckEnum {
NoCheck = -1,
FullCheck = 0,
FastCheck = 1,
NoCheck = 2
FaultCheck = 2,
ValidationCheck = 3,
};

struct settings_t
Expand Down
5 changes: 5 additions & 0 deletions core/windows/winmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <process.h>

#include "hw/sh4/dyna/ngen.h"
#include "hw/sh4/dyna/blockmanager.h"
#include "hw/mem/_vmem.h"


Expand Down Expand Up @@ -160,6 +161,10 @@ LONG ExeptionHandler(EXCEPTION_POINTERS *ExceptionInfo)
{
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (bm_LockedWrite(address))
{
return EXCEPTION_CONTINUE_EXECUTION;
}
#if FEAT_SHREC == DYNAREC_JIT
#if HOST_CPU == CPU_X86
else if ( ngen_Rewrite((unat&)ep->ContextRecord->Eip,*(unat*)ep->ContextRecord->Esp,ep->ContextRecord->Eax) )
Expand Down

0 comments on commit 40971b6

Please sign in to comment.