- Kill programs if they haven't been used in ~7 seconds.
- Only kill 1/4 (instead of all) of total programs if all slots are full.
- Make sure programs are searched from oldest to newest. (this is needed to ensure that new programs don't 'evolve' into old programs and repetitively clone themselves.)

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1470 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
cottonvibes 2009-07-06 08:26:13 +00:00
parent f24be5c352
commit 7f5827cee6
4 changed files with 109 additions and 129 deletions

View File

@ -40,15 +40,16 @@ microVUt(void) mVUinit(VURegs* vuRegsPtr, int vuIndex) {
microVU* mVU = mVUx;
memset(&mVU->prog, 0, sizeof(mVU->prog));
mVU->regs = vuRegsPtr;
mVU->index = vuIndex;
mVU->vuMemSize = (vuIndex ? 0x4000 : 0x1000);
mVU->microMemSize = (vuIndex ? 0x4000 : 0x1000);
mVU->progSize = (vuIndex ? 0x4000 : 0x1000) / 4;
mVU->cache = NULL;
mVU->cacheSize = mVUcacheSize;
mVU->prog.max = mMaxProg - 1;
mVU->prog.prog = (microProgram*)_aligned_malloc(sizeof(microProgram)*(mVU->prog.max+1), 64);
mVU->regs = vuRegsPtr;
mVU->index = vuIndex;
mVU->vuMemSize = (vuIndex ? 0x4000 : 0x1000);
mVU->microMemSize = (vuIndex ? 0x4000 : 0x1000);
mVU->progSize = (vuIndex ? 0x4000 : 0x1000) / 4;
mVU->cache = NULL;
mVU->cacheSize = mVUcacheSize;
mVU->prog.max = mMaxProg - 1;
mVU->prog.prog = (microProgram*)_aligned_malloc(sizeof(microProgram)*(mVU->prog.max+1), 64);
mVU->prog.progList = new int[mMaxProg];
mVUprint((vuIndex) ? "microVU1: init" : "microVU0: init");
mVU->cache = SysMmapEx((vuIndex ? 0x5f240000 : 0x5e240000), mVU->cacheSize + 0x1000, 0, (vuIndex ? "Micro VU1" : "Micro VU0"));
@ -69,18 +70,18 @@ microVUt(void) mVUinit(VURegs* vuRegsPtr, int vuIndex) {
microVUt(void) mVUreset(mV) {
mVUprint((mVU->index) ? "microVU1: reset" : "microVU0: reset");
mVUclose(mVU, 1);
// Clear All Program Data
//memset(&mVU->prog, 0, sizeof(mVU->prog));
memset(&mVU->prog.lpState, 0, sizeof(mVU->prog.lpState));
// Program Variables
mVU->prog.cleared = 1;
mVU->prog.isSame = -1;
mVU->prog.cur = -1;
mVU->prog.total = -1;
mVU->prog.max = mMaxProg - 1;
mVU->prog.cleared = 1;
mVU->prog.isSame = -1;
mVU->prog.cur = -1;
mVU->prog.total = -1;
mVU->prog.curFrame = 0;
mVU->prog.max = mMaxProg - 1;
// Setup Dynarec Cache Limits for Each Program
u8* z = (mVU->cache + 0x1000); // Dispatcher Code is in first page of cache
@ -89,20 +90,18 @@ microVUt(void) mVUreset(mV) {
mVU->prog.x86end = (u8*)((uptr)z + (uptr)(mVU->cacheSize - (mVU->cacheSize*.05)));
for (int i = 0; i <= mVU->prog.max; i++) {
for (int j = 0; j <= mVU->prog.prog[i].ranges.max; j++) {
mVU->prog.prog[i].ranges.range[j][0] = -1; // Set range to
mVU->prog.prog[i].ranges.range[j][1] = -1; // indeterminable status
mVU->prog.prog[i].ranges.total = -1;
}
if (!mVU->index) mVUclearProg<0>(i);
else mVUclearProg<1>(i);
mVU->prog.progList[i] = i;
}
}
// Free Allocated Resources
microVUt(void) mVUclose(mV, bool isReset) {
microVUt(void) mVUclose(mV) {
mVUprint((mVU->index) ? "microVU1: close" : "microVU0: close");
if (!isReset && mVU->cache) { HostSys::Munmap(mVU->cache, mVU->cacheSize); mVU->cache = NULL; }
if (mVU->cache) { HostSys::Munmap(mVU->cache, mVU->cacheSize); mVU->cache = NULL; }
// Delete Programs and Block Managers
if (mVU->prog.prog) {
@ -111,8 +110,9 @@ microVUt(void) mVUclose(mV, bool isReset) {
microBlockManager::Delete(mVU->prog.prog[i].block[j]);
}
}
if (!isReset) safe_aligned_free(mVU->prog.prog);
safe_aligned_free(mVU->prog.prog);
}
safe_delete(mVU->prog.progList);
}
// Clears Block Data in specified range
@ -127,18 +127,18 @@ microVUt(void) mVUclear(mV, u32 addr, u32 size) {
// Micro VU - Private Functions
//------------------------------------------------------------------
// Clears program data (Sets used to 1 because calling this function implies the program will be used at least once)
// Clears program data
microVUf(void) mVUclearProg(int progIndex) {
microVU* mVU = mVUx;
mVUprogI.used = 1;
mVUprogI.last_used = 3;
mVUprogI.used = 0;
mVUprogI.isDead = 1;
mVUprogI.frame = mVU->prog.curFrame;
for (int j = 0; j <= mVUprogI.ranges.max; j++) {
mVUprogI.ranges.range[j][0] = -1; // Set range to
mVUprogI.ranges.range[j][1] = -1; // indeterminable status
mVUprogI.ranges.total = -1;
}
for (u32 i = 0; i < (mVU->progSize / 2); i++) {
//if (mVUprogI.block[i]) { mVUprogI.block[i]->reset(); }
microBlockManager::Delete(mVUprogI.block[i]);
}
}
@ -150,85 +150,66 @@ microVUf(void) mVUcacheProg(int progIndex) {
mVUdumpProg(progIndex);
}
#define aWrap(x, nMax) ((x > nMax) ? 0 : x)
// Sorts the program list (Moves progIndex to Beginning of ProgList)
microVUt(void) mVUsortProg(mV, int progIndex) {
int* temp = new int[mVU->prog.max+1];
int offset = 0;
for (int i = 0; i <= (mVU->prog.max-1); i++) {
if (progIndex == mVU->prog.progList[i]) offset = 1;
temp[i+1] = mVU->prog.progList[i+offset];
}
temp[0] = progIndex;
delete mVU->prog.progList;
mVU->prog.progList = temp;
}
// Finds the least used program, (if program list full clears and returns an old program; if not-full, returns free program)
microVUf(int) mVUfindLeastUsedProg() {
microVU* mVU = mVUx;
if (mVU->prog.total < mVU->prog.max) {
mVU->prog.total++;
mVUcacheProg<vuIndex>(mVU->prog.total); // Cache Micro Program
mVU->prog.prog[mVU->prog.total].used = 1;
mVU->prog.prog[mVU->prog.total].last_used = 3;
Console::Notice("microVU%d: Cached MicroPrograms = %d", params vuIndex, mVU->prog.total+1);
return mVU->prog.total;
}
else {
/*
const int pMax = mVU->prog.max;
int smallidx = aWrap((mVU->prog.cur+1), pMax);
u64 smallval = mVU->prog.prog[smallidx].used;
for (int i = 1, j = aWrap((smallidx+1), pMax); i <= pMax; i++, aWrap((j+1), pMax)) {
if (smallval > mVU->prog.prog[j].used) {
smallval = mVU->prog.prog[j].used;
smallidx = j;
}
}
//smallidx = rand() % 200;
mVUclearProg<vuIndex>(smallidx); // Clear old data if overwriting old program
mVUcacheProg<vuIndex>(smallidx); // Cache Micro Program
//Console::Notice("microVU%d: Overwriting existing program in slot %d [%d times used]", params vuIndex, smallidx, smallval);
return smallidx;
*/
/*
static int smallidx = 0;
const int pMax = mVU->prog.max;
smallidx = aWrap((smallidx+1), pMax);
mVUclearProg<vuIndex>(smallidx); // Clear old data if overwriting old program
mVUcacheProg<vuIndex>(smallidx); // Cache Micro Program
//Console::Notice("microVU%d: Overwriting existing program in slot %d [%d times used]", params vuIndex, smallidx, smallval);
return smallidx;
*/
//mVUreset(mVU);
mVU->prog.x86ptr = mVU->prog.x86start;
for (int z = 0; z <= mVU->prog.max; z++) {
mVUclearProg<vuIndex>(z);
mVU->prog.prog[z].used = 0;
mVU->prog.prog[z].last_used = 0;
}
mVU->prog.total = 0;
mVUcacheProg<vuIndex>(mVU->prog.total); // Cache Micro Program
mVU->prog.prog[mVU->prog.total].used = 1;
mVU->prog.prog[mVU->prog.total].last_used = 3;
Console::Notice("microVU%d: Cached MicroPrograms = %d", params vuIndex, mVU->prog.total+1);
return mVU->prog.total;
}
}
// mVUvsyncUpdate -->
// This should be run at 30fps intervals from Counters.cpp (or 60fps works too, but 30fps is
// probably all we need for accurate results)
//
// To fix the program cache to more efficiently dispose of "obsolete" programs, we need to use a
// frame-based decrementing system in combination with a program-execution-based incrementing
// system. In English: if last_used >= 2 it means the program has been used for the current
// or prev frame. if it's 0, the program hasn't been used for a while.
microVUt(void) mVUvsyncUpdate(mV) {
if (mVU->prog.total < mVU->prog.max) return;
for (int i = 0; i <= mVU->prog.max; i++) {
if (mVU->prog.prog[i].last_used != 0) {
if (mVU->prog.prog[i].last_used >= 3) {
mVU->prog.prog[i].used += 0x200; // give 'weighted' bonus
}
mVU->prog.prog[i].last_used--;
if (mVU->prog.prog[i].isDead) {
mVU->prog.total++;
mVUcacheProg<vuIndex>(i); // Cache Micro Program
mVU->prog.prog[i].isDead = 0;
mVU->prog.prog[i].used = 1;
mVUsortProg(mVU, i);
Console::Notice("microVU%d: Cached MicroPrograms = [%03d] [%03d]", params vuIndex, i+1, mVU->prog.total+1);
return i;
}
else mVU->prog.prog[i].used /= 2; // penalize unused programs.
}
static int clearIdx = 0;
int pIdx = clearIdx;
for (int i = 0; i < ((mVU->prog.max+1)/4); i++) {
mVUclearProg<vuIndex>(clearIdx);
clearIdx = aWrap(clearIdx+1, mVU->prog.max);
}
mVU->prog.total -= ((mVU->prog.max+1)/4)-1;
mVUcacheProg<vuIndex>(pIdx); // Cache Micro Program
mVU->prog.prog[pIdx].isDead = 0;
mVU->prog.prog[pIdx].used = 1;
mVUsortProg(mVU, pIdx);
Console::Notice("microVU%d: Cached MicroPrograms = [%03d] [%03d]", params vuIndex, pIdx+1, mVU->prog.total+1);
return pIdx;
}
// Finds and Kills Programs if they haven't been used in a while.
microVUt(void) mVUvsyncUpdate(mV) {
for (int i = 0; i <= mVU->prog.max; i++) {
if (mVU->prog.prog[i].isDead) continue;
if (mVU->prog.prog[i].used) {
mVU->prog.prog[i].used = 0;
mVU->prog.prog[i].frame = mVU->prog.curFrame;
}
if((mVU->prog.curFrame - mVU->prog.prog[i].frame) >= (60 * 7)) {
mVU->prog.total--;
if (!mVU->index) mVUclearProg<0>(i);
else mVUclearProg<1>(i);
DevCon::Status("microVU%d: Killing Dead Program [%03d]", params mVU->index, i+1);
}
}
mVU->prog.curFrame++;
}
microVUf(bool) mVUcmpPartial(int progIndex) {
@ -244,16 +225,15 @@ microVUf(bool) mVUcmpPartial(int progIndex) {
}
// Compare Cached microProgram to mVU->regs->Micro
microVUf(bool) mVUcmpProg(int progIndex, bool progUsed, const bool cmpWholeProg) {
microVUf(bool) mVUcmpProg(int progIndex, const bool cmpWholeProg) {
microVU* mVU = mVUx;
if (progUsed) {
if (!mVUprogI.isDead) {
if ((cmpWholeProg && !memcmp_mmx((u8*)mVUprogI.data, mVU->regs->Micro, mVU->microMemSize))
|| (!cmpWholeProg && mVUcmpPartial<vuIndex>(progIndex))) {
mVU->prog.cur = progIndex;
mVU->prog.cleared = 0;
mVU->prog.isSame = cmpWholeProg ? 1 : -1;
mVU->prog.prog[progIndex].last_used = 3;
mVU->prog.prog[progIndex].used++; // increment 'used'
mVU->prog.prog[progIndex].used = 1;
return 1;
}
}
@ -263,23 +243,17 @@ microVUf(bool) mVUcmpProg(int progIndex, bool progUsed, const bool cmpWholeProg)
// Searches for Cached Micro Program and sets prog.cur to it (returns 1 if program found, else returns 0)
microVUf(int) mVUsearchProg() {
microVU* mVU = mVUx;
if (mVU->prog.cleared) { // If cleared, we need to search for new program
for (int i = 0; i <= mVU->prog.total; i++) {
if (mVUcmpProg<vuIndex>(i, !!mVU->prog.prog[i].used, 0))
return 1; // Check Recently Used Programs
}
for (int i = 0; i <= mVU->prog.total; i++) {
if (mVUcmpProg<vuIndex>(i, !mVU->prog.prog[i].used, 0))
return 1; // Check Older Programs
for (int i = mVU->prog.max; i >= 0; i--) {
if (mVUcmpProg<vuIndex>(mVU->prog.progList[i], 0))
return 1;
}
mVU->prog.cur = mVUfindLeastUsedProg<vuIndex>(); // If cleared and program not found, make a new program instance
mVU->prog.cleared = 0;
mVU->prog.isSame = 1;
return 0;
}
mVU->prog.prog[mVU->prog.cur].used++;
mVU->prog.prog[mVU->prog.cur].last_used = 3;
mVU->prog.prog[mVU->prog.cur].used = 1;
return 1; // If !cleared, then we're still on the same program as last-time ;)
}
@ -288,7 +262,7 @@ microVUf(int) mVUsearchProg() {
//------------------------------------------------------------------
void initVUrec (VURegs* vuRegs, const int vuIndex) { mVUinit(vuRegs, vuIndex); }
void closeVUrec(const int vuIndex) { mVUclose(mVUx, 0); }
void closeVUrec(const int vuIndex) { mVUclose(mVUx); }
void resetVUrec(const int vuIndex) { mVUreset(mVUx); }
void vsyncVUrec(const int vuIndex) { mVUvsyncUpdate(mVUx); }

View File

@ -114,23 +114,26 @@ struct microProgram {
u32 data [mProgSize]; // Holds a copy of the VU microProgram
microBlockManager* block[mProgSize/2]; // Array of Block Managers
microRange ranges; // The ranges of the microProgram that have already been recompiled
u64 used; // Number of times its been used
u32 last_used; // Counters # of frames since last use (starts at 3 and counts backwards to 0 for each 30fps vSync)
u32 frame; // Frame # the program was last used on
u32 used; // Program was used this frame?
bool isDead; // Program is dead?
};
#define mMaxProg ((mVU->index)?400:8) // The amount of Micro Programs Recs will 'remember' (For n = 1, 2, 4, 8, 16, etc...)
struct microProgManager {
microIR<mProgSize> allocInfo; // IR information
microProgram* prog; // Store MicroPrograms in memory
int max; // Max Number of MicroPrograms minus 1
int total; // Total Number of valid MicroPrograms minus 1
int cur; // Index to Current MicroProgram thats running (-1 = uncached)
int isSame; // Current cached microProgram is Exact Same program as mVU->regs->Micro (-1 = unknown, 0 = No, 1 = Yes)
int cleared; // Micro Program is Indeterminate so must be searched for (and if no matches are found then recompile a new one)
u8* x86ptr; // Pointer to program's recompilation code
u8* x86start; // Start of program's rec-cache
u8* x86end; // Limit of program's rec-cache
microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution)
microIR<mProgSize> allocInfo; // IR information
microProgram* prog; // Store MicroPrograms in memory
int* progList; // List of program indexes ordered by age (ordered from newest to oldest)
int max; // Max Number of MicroPrograms minus 1
int total; // Total Number of valid MicroPrograms minus 1
int cur; // Index to Current MicroProgram thats running (-1 = uncached)
int isSame; // Current cached microProgram is Exact Same program as mVU->regs->Micro (-1 = unknown, 0 = No, 1 = Yes)
int cleared; // Micro Program is Indeterminate so must be searched for (and if no matches are found then recompile a new one)
u32 curFrame; // Frame Counter
u8* x86ptr; // Pointer to program's recompilation code
u8* x86start; // Start of program's rec-cache
u8* x86end; // Limit of program's rec-cache
microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution)
};
#define mVUcacheSize (mMaxProg * (0x100000 * 0.5)) // 0.5mb per program
@ -175,7 +178,7 @@ extern int mVUdebugNow;
// Main Functions
microVUt(void) mVUinit(VURegs*, int);
microVUt(void) mVUreset(mV);
microVUt(void) mVUclose(mV, bool isReset);
microVUt(void) mVUclose(mV);
microVUt(void) mVUclear(mV, u32, u32);
microVUt(void*) mVUblockFetch(microVU* mVU, u32 startPC, uptr pState);
microVUx(void*) __fastcall mVUcompileJIT(u32 startPC, uptr pState);
@ -187,6 +190,8 @@ mVUop(mVUopU);
mVUop(mVUopL);
// Private Functions
microVUt(void) mVUsortProg(mV, int progIndex);
microVUf(void) mVUclearProg(int progIndex);
microVUf(int) mVUfindLeastUsedProg(microVU* mVU);
microVUf(int) mVUsearchProg();
microVUf(void) mVUcacheProg(int progIndex);

View File

@ -70,7 +70,7 @@
#define doLowerOp() { incPC(-1); mVUopL(mVU, 1); incPC(1); }
#define doSwapOp() { doBackupVF1(); mVUopL(mVU, 1); doBackupVF2(); incPC(1); doUpperOp(); doBackupVF3(); }
#define doIbit() { if (mVUup.iBit) { incPC(-1); MOV32ItoM((uptr)&mVU->regs->VI[REG_I].UL, curI); incPC(1); } }
#define blockCreate(addr) { if (!mVUblocks[addr]) mVUblocks[addr] = new microBlockManager();/*microBlockManager::AlignedNew();*/ }
#define blockCreate(addr) { if (!mVUblocks[addr]) mVUblocks[addr] = new microBlockManager(); }
//------------------------------------------------------------------
// Helper Functions

View File

@ -219,6 +219,7 @@ typedef u32 (__fastcall *mVUCall)(void*, void*);
#define cmpOffset(x) ((u8*)&(((u8*)x)[mVUprogI.ranges.range[i][0]]))
#define Rmem (uptr)&mVU->regs->VI[REG_R].UL
#define Roffset (uptr)&mVU->regs->VI[9].UL
#define aWrap(x, m) ((x > m) ? 0 : x)
// Flag Info
#define __Status (mVUflagInfo & (0xf<<0))