/* Setup the Jit-to-interpreter entry points */
interpState.jitToInterpEntries = jitToInterpEntries;
+
+ /*
+ * Initialize the threshold filter [don't bother to zero out the
+ * actual table. We're looking for matches, and an occasional
+ * false positive is acceptible.
+ */
+ interpState.lastThreshFilter = 0;
#endif
/*
* for handling 1-to-many mappings like virtual method call and
* packed switch.
* 3) dvmJitToInterpPunt: use the fast interpreter to execute the next
- * instruction(s) and stay there as long as it is appropriate to return
+ * instruction(s) and stay there as long as it is appropriate to return
* to the compiled land. This is used when the jit'ed code is about to
* throw an exception.
* 4) dvmJitToInterpSingleStep: use the portable interpreter to execute the
void *dvmJitToInterpSingleStep;
void *dvmJitToTraceSelect;
};
+
+#define JIT_TRACE_THRESH_FILTER_SIZE 16
#endif
/*
const u2* currTraceHead; // Start of the trace we're building
const u2* currRunHead; // Start of run we're building
int currRunLen; // Length of run in 16-bit words
+ int lastThreshFilter;
+ u2* threshFilter[JIT_TRACE_THRESH_FILTER_SIZE];
JitTraceRun trace[MAX_JIT_RUN_LEN];
#endif
#include "compiler/CompilerIR.h"
#include <errno.h>
-/*
- * Reset profile counts. Note that we could easily lose
- * one or more of these write because of threading. Because these
- * counts are considered hints, absolute correctness is not a
- * problem and the cost of synchronizing would be prohibitive.
- * NOTE: Experimental - 5/21/09. Keep rough track of the last
- * time the counts were reset to allow trace builder to ignore
- * stale thresholds. This is just a hint, and the only penalty
- * for getting it wrong is a slight performance hit (far less than
- * the cost of synchronization).
- */
-static u8 lastProfileResetTimeUsec;
-static void resetProfileCounts() {
- int i;
- unsigned char *pJitProfTable = gDvmJit.pProfTable;
- lastProfileResetTimeUsec = dvmGetRelativeTimeUsec();
- if (pJitProfTable != NULL) {
- for (i=0; i < JIT_PROF_SIZE; i++) {
- pJitProfTable[i] = gDvmJit.threshold;
- }
- }
-}
-
int dvmJitStartup(void)
{
unsigned int i;
}
/* Is chain field wide enough for termination pattern? */
assert(pJitTable[0].chain == gDvm.maxJitTableEntries);
- resetProfileCounts();
done:
gDvmJit.pJitEntryTable = pJitTable;
#endif
/* Dumps profile info for a single trace */
-void dvmCompilerDumpTraceProfile(struct JitEntry *p)
+int dvmCompilerDumpTraceProfile(struct JitEntry *p)
{
ChainCellCounts* pCellCounts;
char* traceBase;
if (p->codeAddress == NULL) {
LOGD("TRACEPROFILE 0x%08x 0 NULL 0 0", (int)traceBase);
- return;
+ return 0;
}
pExecutionCount = (u4*) (traceBase);
*pExecutionCount, method->clazz->descriptor, method->name,
desc->trace[0].frag.startOffset,
desc->trace[0].frag.numInsts);
+ return *pExecutionCount;
}
/* Dumps debugging & tuning stats to the log */
gDvmJit.invokeNoOpt, gDvmJit.invokeChain, gDvmJit.returnOp);
#endif
if (gDvmJit.profile) {
+ int numTraces = 0;
+ long counts = 0;
for (i=0; i < (int) gDvmJit.jitTableSize; i++) {
if (gDvmJit.pJitEntryTable[i].dPC != 0) {
- dvmCompilerDumpTraceProfile( &gDvmJit.pJitEntryTable[i] );
+ counts += dvmCompilerDumpTraceProfile( &gDvmJit.pJitEntryTable[i] );
+ numTraces++;
}
}
+ if (numTraces == 0)
+ numTraces = 1;
+ LOGD("JIT: Average execution count -> %d",(int)(counts / numTraces));
}
}
}
#define PROFILE_STALENESS_THRESHOLD 100000LL
bool dvmJitCheckTraceRequest(Thread* self, InterpState* interpState)
{
- bool res = false; /* Assume success */
+ bool res = false; /* Assume success */
+ int i;
if (gDvmJit.pJitEntryTable != NULL) {
- u8 delta = dvmGetRelativeTimeUsec() - lastProfileResetTimeUsec;
+ /* Two-level filtering scheme */
+ for (i=0; i< JIT_TRACE_THRESH_FILTER_SIZE; i++) {
+ if (interpState->pc == interpState->threshFilter[i]) {
+ break;
+ }
+ }
+ if (i == JIT_TRACE_THRESH_FILTER_SIZE) {
+ /*
+ * Use random replacement policy - otherwise we could miss a large
+ * loop that contains more traces than the size of our filter array.
+ */
+ i = rand() % JIT_TRACE_THRESH_FILTER_SIZE;
+ interpState->threshFilter[i] = interpState->pc;
+ res = true;
+ }
/*
* If the compiler is backlogged, or if a debugger or profiler is
* active, cancel any JIT actions
*/
- if ( (gDvmJit.compilerQueueLength >= gDvmJit.compilerHighWater) ||
+ if ( res || (gDvmJit.compilerQueueLength >= gDvmJit.compilerHighWater) ||
gDvm.debuggerActive || self->suspendCount
#if defined(WITH_PROFILER)
|| gDvm.activeProfilers
if (interpState->jitState != kJitOff) {
interpState->jitState = kJitNormal;
}
- } else if (delta > PROFILE_STALENESS_THRESHOLD) {
- resetProfileCounts();
- res = true; /* Stale profile - abort */
} else if (interpState->jitState == kJitTSelectRequest) {
u4 chainEndMarker = gDvmJit.jitTableSize;
u4 idx = dvmJitHash(interpState->pc);
#include "InterpDefs.h"
-#define JIT_PROF_SIZE 4096
+#define JIT_PROF_SIZE 512
#define JIT_MAX_TRACE_LEN 100
common_updateProfile:
eor r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
- lsl r3,r3,#20 @ shift out excess 4095
- ldrb r1,[r0,r3,lsr #20] @ get counter
+ lsl r3,r3,#23 @ shift out excess 511
+ ldrb r1,[r0,r3,lsr #23] @ get counter
GET_INST_OPCODE(ip)
subs r1,r1,#1 @ decrement counter
- strb r1,[r0,r3,lsr #20] @ and store it
+ strb r1,[r0,r3,lsr #23] @ and store it
GOTO_OPCODE_IFNE(ip) @ if not threshold, fallthrough otherwise */
/*
* jump to it now).
*/
mov r1,#255
- strb r1,[r0,r3,lsr #20] @ reset counter
+ strb r1,[r0,r3,lsr #23] @ reset counter
EXPORT_PC()
mov r0,rPC
bl dvmJitGetCodeAddr @ r0<- dvmJitGetCodeAddr(rPC)
common_updateProfile:
eor r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
- lsl r3,r3,#20 @ shift out excess 4095
- ldrb r1,[r0,r3,lsr #20] @ get counter
+ lsl r3,r3,#23 @ shift out excess 511
+ ldrb r1,[r0,r3,lsr #23] @ get counter
GET_INST_OPCODE(ip)
subs r1,r1,#1 @ decrement counter
- strb r1,[r0,r3,lsr #20] @ and store it
+ strb r1,[r0,r3,lsr #23] @ and store it
GOTO_OPCODE_IFNE(ip) @ if not threshold, fallthrough otherwise */
/*
* jump to it now).
*/
mov r1,#255
- strb r1,[r0,r3,lsr #20] @ reset counter
+ strb r1,[r0,r3,lsr #23] @ reset counter
EXPORT_PC()
mov r0,rPC
bl dvmJitGetCodeAddr @ r0<- dvmJitGetCodeAddr(rPC)
common_updateProfile:
eor r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
- lsl r3,r3,#20 @ shift out excess 4095
- ldrb r1,[r0,r3,lsr #20] @ get counter
+ lsl r3,r3,#23 @ shift out excess 511
+ ldrb r1,[r0,r3,lsr #23] @ get counter
GET_INST_OPCODE(ip)
subs r1,r1,#1 @ decrement counter
- strb r1,[r0,r3,lsr #20] @ and store it
+ strb r1,[r0,r3,lsr #23] @ and store it
GOTO_OPCODE_IFNE(ip) @ if not threshold, fallthrough otherwise */
/*
* jump to it now).
*/
mov r1,#255
- strb r1,[r0,r3,lsr #20] @ reset counter
+ strb r1,[r0,r3,lsr #23] @ reset counter
EXPORT_PC()
mov r0,rPC
bl dvmJitGetCodeAddr @ r0<- dvmJitGetCodeAddr(rPC)
common_updateProfile:
eor r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
- lsl r3,r3,#20 @ shift out excess 4095
- ldrb r1,[r0,r3,lsr #20] @ get counter
+ lsl r3,r3,#23 @ shift out excess 511
+ ldrb r1,[r0,r3,lsr #23] @ get counter
GET_INST_OPCODE(ip)
subs r1,r1,#1 @ decrement counter
- strb r1,[r0,r3,lsr #20] @ and store it
+ strb r1,[r0,r3,lsr #23] @ and store it
GOTO_OPCODE_IFNE(ip) @ if not threshold, fallthrough otherwise */
/*
* jump to it now).
*/
mov r1,#255
- strb r1,[r0,r3,lsr #20] @ reset counter
+ strb r1,[r0,r3,lsr #23] @ reset counter
EXPORT_PC()
mov r0,rPC
bl dvmJitGetCodeAddr @ r0<- dvmJitGetCodeAddr(rPC)