Minor cleanups for the new virtual memory alloc/reserve system:

* Moved VIF dynamic recompiler buffers to the recompilers section of PCSX2.
 * Using RecompiledCodeReserve for the VIF SSE functions.
 * Minor bugfixes to VirtualMemory class implementations.
 * Improved error handling and error message display.
 * [TODO] : implement a call to cpuShutdown() to clean up VIF unpack/SSE reserves.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4169 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-12-30 06:21:07 +00:00
parent e089cee4b9
commit f76e901c64
12 changed files with 148 additions and 39 deletions

View File

@ -130,7 +130,7 @@ class VirtualMemoryReserve
protected:
wxString m_name;
// Default size of the reserve, in bytes. Can be specified when the object is contructed.
// Default size of the reserve, in bytes. Can be specified when the object is constructed.
// Is used as the reserve size when Reserve() is called, unless an override is specified
// in the Reserve parameters.
size_t m_defsize;
@ -140,13 +140,19 @@ protected:
// reserved memory (in pages).
uptr m_pages_reserved;
// Protection mode to be applied to committed blocks.
PageProtectionMode m_prot_mode;
// Records the number of pages committed to memory.
// (metric for analysis of buffer usage)
uptr m_pages_commited;
// Protection mode to be applied to committed blocks.
PageProtectionMode m_prot_mode;
// Controls write access to the entire reserve. When true (the default), the reserve
// operates normally. When set to false, all committed blocks are re-protected with
// write disabled, and accesses to uncommitted blocks (read or write) will cause a GPF
// as well.
bool m_allow_writes;
public:
VirtualMemoryReserve( const wxString& name=wxEmptyString, size_t size = 0 );
virtual ~VirtualMemoryReserve() throw()
@ -164,6 +170,9 @@ public:
virtual void Release();
virtual bool TryResize( uint newsize );
virtual bool Commit();
virtual void ForbidModification();
virtual void AllowModification();
bool IsOk() const { return m_baseptr != NULL; }
wxString GetName() const { return m_name; }
@ -200,6 +209,8 @@ public:
return *((u8*)m_baseptr + idx);
}
protected:
virtual void ReprotectCommittedBlocks( const PageProtectionMode& newmode );
};
// --------------------------------------------------------------------------------------
@ -231,6 +242,12 @@ public:
void OnPageFaultEvent( const PageFaultInfo& info, bool& handled );
virtual uptr SetBlockSize( uptr bytes )
{
m_blocksize = (bytes + __pagesize - 1) / __pagesize;
return m_blocksize * __pagesize;
}
protected:
// This function is called from OnPageFaultEvent after the address has been translated
@ -298,7 +315,8 @@ public:
SpatialArrayReserve& SetBlockCount( uint blocks );
SpatialArrayReserve& SetBlockSizeInPages( uint bytes );
uint SetBlockSize( uint bytes );
uptr SetBlockSize( uptr bytes );
operator void*() { return m_baseptr; }
operator const void*() const { return m_baseptr; }
@ -309,6 +327,7 @@ public:
using _parent::operator[];
protected:
void ReprotectCommittedBlocks( const PageProtectionMode& newmode );
void DoCommitAndProtect( uptr page );
uint _calcBlockBitArrayLength() const;
};

View File

@ -218,8 +218,8 @@ wxString Exception::OutOfMemory::FormatDisplayMessage() const
FastFormatUnicode retmsg;
retmsg.Write( L"%s", _("Oh noes! Out of memory!") );
if (!m_message_diag.IsEmpty())
retmsg.Write(L"\n\n%s", m_message_diag.c_str());
if (!m_message_user.IsEmpty())
retmsg.Write(L"\n\n%s", m_message_user.c_str());
return retmsg;
}

View File

@ -405,7 +405,8 @@ void Threading::pxThread::RethrowException() const
// after.
ScopedExcept ptr( const_cast<pxThread*>(this)->m_except.DetachPtr() );
if( ptr ) ptr->Rethrow();
if (ptr)
ptr->Rethrow();
}
static bool m_BlockDeletions = false;

View File

@ -79,6 +79,7 @@ VirtualMemoryReserve::VirtualMemoryReserve( const wxString& name, size_t size )
m_pages_reserved = 0;
m_baseptr = NULL;
m_prot_mode = PageAccess_None();
m_allow_writes = true;
}
VirtualMemoryReserve& VirtualMemoryReserve::SetName( const wxString& newname )
@ -162,12 +163,18 @@ void* VirtualMemoryReserve::Reserve( size_t size, uptr base, uptr upper_bounds )
return m_baseptr;
}
void VirtualMemoryReserve::ReprotectCommittedBlocks( const PageProtectionMode& newmode )
{
if (!m_pages_commited) return;
HostSys::MemProtect(m_baseptr, m_pages_commited*__pagesize, newmode);
}
// Clears all committed blocks, restoring the allocation to a reserve only.
void VirtualMemoryReserve::Reset()
{
if (!m_pages_commited) return;
HostSys::MemProtect(m_baseptr, m_pages_commited*__pagesize, PageAccess_None());
ReprotectCommittedBlocks(PageAccess_None());
HostSys::MmapResetPtr(m_baseptr, m_pages_commited*__pagesize);
m_pages_commited = 0;
}
@ -186,6 +193,18 @@ bool VirtualMemoryReserve::Commit()
return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved*__pagesize, m_prot_mode);
}
void VirtualMemoryReserve::AllowModification()
{
m_allow_writes = true;
HostSys::MemProtect(m_baseptr, m_pages_commited*__pagesize, m_prot_mode);
}
void VirtualMemoryReserve::ForbidModification()
{
m_allow_writes = false;
HostSys::MemProtect(m_baseptr, m_pages_commited*__pagesize, PageProtectionMode(m_prot_mode).Write(false));
}
// If growing the array, or if shrinking the array to some point that's still *greater* than the
// committed memory range, then attempt a passive "on-the-fly" resize that maps/unmaps some portion
@ -273,6 +292,16 @@ void BaseVmReserveListener::OnPageFaultEvent(const PageFaultInfo& info, bool& ha
sptr offset = (info.addr - (uptr)m_baseptr) / __pagesize;
if ((offset < 0) || ((uptr)offset >= m_pages_reserved)) return;
if (!m_allow_writes)
{
pxFailRel( pxsFmt(
L"Memory Protection Fault @ %s (%s)\n"
L"Modification of this reserve has been disabled (m_allow_writes == false).",
pxsPtr(info.addr), m_name.c_str())
);
return;
}
// Linux Note! the SIGNAL handler is very limited in what it can do, and not only can't
// we let the C++ exception try to unwind the stack, we may not be able to log it either.
// (but we might as well try -- kernel/posix rules says not to do it, but Linux kernel
@ -336,23 +365,26 @@ void* SpatialArrayReserve::Reserve( size_t size, uptr base, uptr upper_bounds )
return addr;
}
void SpatialArrayReserve::ReprotectCommittedBlocks( const PageProtectionMode& newmode )
{
if (!m_pages_commited) return;
u8* curptr = GetPtr();
const uint blockBytes = m_blocksize * __pagesize;
for (uint i=0; i<m_numblocks; ++i, curptr+=blockBytes)
{
uint thisbit = 1 << (i & 7);
if (!(m_blockbits[i/8] & thisbit)) continue;
HostSys::MemProtect(curptr, blockBytes, newmode);
HostSys::MmapResetPtr(curptr, blockBytes);
}
}
// Resets/clears the spatial array, reducing the memory commit pool overhead to zero (0).
void SpatialArrayReserve::Reset()
{
if (m_pages_commited)
{
u8* curptr = GetPtr();
const uint blockBytes = m_blocksize * __pagesize;
for (uint i=0; i<m_numblocks; ++i, curptr+=blockBytes)
{
uint thisbit = 1 << (i & 7);
if (!(m_blockbits[i/8] & thisbit)) continue;
HostSys::MemProtect(curptr, blockBytes, PageAccess_None());
HostSys::MmapResetPtr(curptr, blockBytes);
}
}
ReprotectCommittedBlocks( PageAccess_None() );
memzero_sse_a(m_blockbits.GetPtr(), _calcBlockBitArrayLength());
}

View File

@ -46,6 +46,15 @@ void hwInit()
hwInitialized = true;
}
void hwShutdown()
{
if (!hwInitialized) return;
VifUnpackSSE_Destroy();
hwInitialized = false;
}
void hwReset()
{
hwInit();

View File

@ -378,6 +378,7 @@ union tGS_SMODE2
};
extern void hwReset();
extern void hwShutdown();
extern const int rdram_devices;
extern int rdram_sdevid;

View File

@ -96,6 +96,11 @@ void cpuReset()
LastELF = L"";
}
void cpuShutdown()
{
hwShutdown();
}
__ri void cpuException(u32 code, u32 bd)
{
bool errLevel2, checkStatus;

View File

@ -400,7 +400,7 @@ void SysMainMemory::ResetAll()
m_ee.Reset();
m_iop.Reset();
m_vu.Reset();
// Note: newVif is reset as part of other VIF structures.
}
@ -472,6 +472,12 @@ SysCpuProviderPack::SysCpuProviderPack()
}
// hmm! : VU0 and VU1 pre-allocations should do sVU and mVU separately? Sounds complicated. :(
if (newVifDynaRec)
{
dVifReserve(0);
dVifReserve(1);
}
}
bool SysCpuProviderPack::IsRecAvailable_MicroVU0() const { return CpuProviders->microVU0.IsAvailable(); }
@ -491,6 +497,12 @@ void SysCpuProviderPack::CleanupMess() throw()
{
psxRec.Shutdown();
recCpu.Shutdown();
if (newVifDynaRec)
{
dVifRelease(0);
dVifRelease(1);
}
}
DESTRUCTOR_CATCHALL
}
@ -558,8 +570,11 @@ void SysClearExecutionCache()
CpuVU0->Reset();
CpuVU1->Reset();
resetNewVif(0);
resetNewVif(1);
if (newVifDynaRec)
{
dVifReset(0);
dVifReset(1);
}
}
// Maps a block of memory for use as a recompiled code buffer, and ensures that the

View File

@ -39,6 +39,7 @@ extern void dVifReset (int idx);
extern void dVifClose (int idx);
extern void dVifRelease (int idx);
extern void VifUnpackSSE_Init();
extern void VifUnpackSSE_Destroy();
_vifT extern void dVifUnpack (const u8* data, bool isFill);

View File

@ -32,24 +32,29 @@ void dVifReserve(int idx)
void dVifReset(int idx) {
if( !nVif[idx].vifBlocks )
pxAssumeDev(nVif[idx].recReserve, "Dynamic VIF recompiler reserve must be created prior to VIF use or reset!");
if (!nVif[idx].vifBlocks)
nVif[idx].vifBlocks = new HashBucket<_tParams>();
else
nVif[idx].vifBlocks->clear();
nVif[idx].recReserve->Reset();
nVif[idx].numBlocks = 0;
nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr();
}
void dVifClose(int idx) {
nVif[idx].numBlocks = 0;
nVif[idx].recReserve->Reset();
if (nVif[idx].recReserve)
nVif[idx].recReserve->Reset();
safe_delete(nVif[idx].vifBlocks);
}
void dVifRelease(int idx) {
dVifClose(idx);
safe_delete(nVif[idx].recReserve);
}
@ -227,7 +232,9 @@ _vifT static __fi u8* dVifsetVUptr(uint cl, uint wl, bool isFill) {
// it clears the buffer only.
static __fi void dVifRecLimit(int idx) {
if (nVif[idx].recWritePtr > (nVif[idx].recReserve->GetPtrEnd() - _256kb)) {
DevCon.WriteLn("nVif Recompiler Cache Reset! [0x%08x > 0x%08x]", nVif[idx].recWritePtr, nVif[idx].recReserve->GetPtrEnd());
DevCon.WriteLn(L"nVif Recompiler Cache Reset! [%s > %s]",
pxsPtr(nVif[idx].recWritePtr), pxsPtr(nVif[idx].recReserve->GetPtrEnd())
);
nVif[idx].recReserve->Reset();
nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr();
}

View File

@ -80,7 +80,6 @@ nVifStruct::nVifStruct()
void reserveNewVif(int idx)
{
if (newVifDynaRec) dVifReserve(idx);
}
void resetNewVif(int idx)
@ -96,11 +95,9 @@ void resetNewVif(int idx)
}
void closeNewVif(int idx) {
if (newVifDynaRec) dVifClose(idx);
}
void releaseNewVif(int idx) {
if (newVifDynaRec) dVifRelease(idx);
}
static __fi u8* getVUptr(uint idx, int offset) {

View File

@ -22,7 +22,9 @@
#define xMOV64(regX, loc) xMOVUPS(regX, loc)
#define xMOV128(regX, loc) xMOVUPS(regX, loc)
static __pagealigned u8 nVifUpkExec[__pagesize*4];
//static __pagealigned u8 nVifUpkExec[__pagesize*4];
static RecompiledCodeReserve* nVifUpkExec = NULL;
// Merges xmm vectors without modifying source reg
void mergeVectors(xRegisterSSE dest, xRegisterSSE src, xRegisterSSE temp, int xyzw) {
@ -288,17 +290,23 @@ static void nVifGen(int usn, int mask, int curCycle) {
vpugen.xUnpack(i);
vpugen.xMovDest();
xRET();
pxAssert( ((uptr)xGetPtr() - (uptr)nVifUpkExec) < sizeof(nVifUpkExec) );
}
}
void VifUnpackSSE_Init()
{
HostSys::MemProtectStatic(nVifUpkExec, PageAccess_ReadWrite());
memset8<0xcc>( nVifUpkExec );
if (nVifUpkExec) return;
xSetPtr( nVifUpkExec );
DevCon.WriteLn( "Generating SSE-optimized unpacking functions for VIF interpreters..." );
nVifUpkExec = new RecompiledCodeReserve(L"VIF SSE-optimized Unpacking Functions");
nVifUpkExec->SetProfilerName("iVIF-SSE");
nVifUpkExec->SetBlockSize( 1 );
nVifUpkExec->Reserve( _64kb );
nVifUpkExec->ThrowIfNotOk();
xSetPtr( *nVifUpkExec );
for (int a = 0; a < 2; a++) {
for (int b = 0; b < 2; b++) {
@ -306,5 +314,19 @@ void VifUnpackSSE_Init()
nVifGen(a, b, c);
}}}
HostSys::MemProtectStatic(nVifUpkExec, PageAccess_ExecOnly());
nVifUpkExec->ForbidModification();
DevCon.WriteLn( "Unpack function generation complete. Generated function statistics:" );
DevCon.Indent().WriteLn(
L"Reserved buffer : %u bytes @ %s\n"
L"x86 code generated : %u bytes\n",
(uint)nVifUpkExec->GetCommittedBytes(),
pxsPtr(nVifUpkExec->GetPtr()),
(uint)(nVifUpkExec->GetPtr() - xGetPtr())
);
}
void VifUnpackSSE_Destroy()
{
safe_delete( nVifUpkExec );
}