diff options
Diffstat (limited to 'vm/compiler')
-rw-r--r-- | vm/compiler/Compiler.c | 5 | ||||
-rw-r--r-- | vm/compiler/Compiler.h | 9 | ||||
-rw-r--r-- | vm/compiler/Frontend.c | 112 | ||||
-rw-r--r-- | vm/compiler/Utility.c | 43 | ||||
-rw-r--r-- | vm/compiler/codegen/armv5te/Codegen.c | 2 |
5 files changed, 147 insertions, 24 deletions
diff --git a/vm/compiler/Compiler.c b/vm/compiler/Compiler.c index 9473834a5..f70b9787b 100644 --- a/vm/compiler/Compiler.c +++ b/vm/compiler/Compiler.c @@ -169,6 +169,8 @@ bool dvmCompilerSetupCodeCache(void) memcpy((void *) gDvmJit.codeCache, (void *) dvmCompilerTemplateStart, templateSize); + + gDvmJit.templateSize = templateSize; gDvmJit.codeCacheByteUsed = templateSize; /* Flush dcache and invalidate the icache to maintain coherence */ @@ -224,6 +226,9 @@ bool dvmCompilerStartup(void) goto fail; } + /* Track method-level compilation statistics */ + gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL); + dvmUnlockMutex(&gDvmJit.compilerLock); return true; diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h index 1ab66871b..093d48ace 100644 --- a/vm/compiler/Compiler.h +++ b/vm/compiler/Compiler.h @@ -84,6 +84,13 @@ typedef struct { JitTraceRun trace[]; } JitTraceDescription; +typedef struct CompilerMethodStats { + const Method *method; // Used as hash entry signature + int dalvikSize; // # of bytes for dalvik bytecodes + int compiledDalvikSize; // # of compiled dalvik bytecodes + int nativeSize; // # of bytes for produced native code +} CompilerMethodStats; + bool dvmCompilerSetupCodeCache(void); bool dvmCompilerArchInit(void); void dvmCompilerArchDump(void); @@ -91,7 +98,7 @@ bool dvmCompilerStartup(void); void dvmCompilerShutdown(void); bool dvmCompilerWorkEnqueue(const u2* pc, WorkOrderKind kind, void* info); void *dvmCheckCodeCache(void *method); -void *dvmCompileMethod(Method *method); +void *dvmCompileMethod(const Method *method); void *dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts); void dvmCompilerDumpStats(void); void dvmCompilerDrainQueue(void); diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c index c8f3abc01..76d931207 100644 --- a/vm/compiler/Frontend.c +++ b/vm/compiler/Frontend.c @@ -30,19 +30,9 @@ static inline int parseInsn(const u2 *codePtr, DecodedInstruction *decInsn, OpCode opcode = instr & 0xff; int insnWidth; - // Need to check if this is a real NOP or a pseudo opcode + // Don't parse instruction data if (opcode == OP_NOP && instr != 0) { - if (instr == kPackedSwitchSignature) { - insnWidth = 4 + codePtr[1] * 2; - } else if (instr == kSparseSwitchSignature) { - insnWidth = 2 + codePtr[1] * 4; - } else if (instr == kArrayDataSignature) { - int width = codePtr[1]; - int size = codePtr[2] | (codePtr[3] << 16); - // The plus 1 is to round up for odd size and width - insnWidth = 4 + ((size * width) + 1) / 2; - } - insnWidth = 0; + return 0; } else { insnWidth = gDvm.instrWidth[opcode]; if (insnWidth < 0) { @@ -88,7 +78,7 @@ static inline bool findBlockBoundary(const Method *caller, MIR *insn, const Method *calleeMethod = caller->clazz->super->vtable[mIndex]; - if (!dvmIsNativeMethod(calleeMethod)) { + if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) { *target = (unsigned int) calleeMethod->insns; } *isInvoke = true; @@ -100,7 +90,7 @@ static inline bool findBlockBoundary(const Method *caller, MIR *insn, const Method *calleeMethod = caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB]; - if (!dvmIsNativeMethod(calleeMethod)) { + if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) { *target = (unsigned int) calleeMethod->insns; } *isInvoke = true; @@ -112,7 +102,7 @@ static inline bool findBlockBoundary(const Method *caller, MIR *insn, const Method *calleeMethod = caller->clazz->super->vtable[insn->dalvikInsn.vB]; - if (!dvmIsNativeMethod(calleeMethod)) { + if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) { *target = (unsigned int) calleeMethod->insns; } *isInvoke = true; @@ -123,7 +113,7 @@ static inline bool findBlockBoundary(const Method *caller, MIR *insn, case OP_INVOKE_DIRECT_RANGE: { const Method *calleeMethod = caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB]; - if (!dvmIsNativeMethod(calleeMethod)) { + if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) { *target = (unsigned int) calleeMethod->insns; } *isInvoke = true; @@ -179,6 +169,72 @@ static inline bool isUnconditionalBranch(MIR *insn) } /* + * dvmHashTableLookup() callback + */ +static int compareMethod(const CompilerMethodStats *m1, + const CompilerMethodStats *m2) +{ + return (int) m1->method - (int) m2->method; +} + +/* + * Analyze each method whose traces are ever compiled. Collect a variety of + * statistics like the ratio of exercised vs overall code and code bloat + * ratios. + */ +static CompilerMethodStats *analyzeMethodBody(const Method *method) +{ + const DexCode *dexCode = dvmGetMethodCode(method); + const u2 *codePtr = dexCode->insns; + const u2 *codeEnd = dexCode->insns + dexCode->insnsSize; + int insnSize = 0; + int hashValue = dvmComputeUtf8Hash(method->name); + + CompilerMethodStats dummyMethodEntry; // For hash table lookup + CompilerMethodStats *realMethodEntry; // For hash table storage + + /* For lookup only */ + dummyMethodEntry.method = method; + realMethodEntry = dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue, + &dummyMethodEntry, + (HashCompareFunc) compareMethod, + false); + + /* Part of this method has been compiled before - just return the entry */ + if (realMethodEntry != NULL) { + return realMethodEntry; + } + + /* + * First time to compile this method - set up a new entry in the hash table + */ + realMethodEntry = + (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats)); + realMethodEntry->method = method; + + dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue, + realMethodEntry, + (HashCompareFunc) compareMethod, + true); + + /* Count the number of instructions */ + while (codePtr < codeEnd) { + DecodedInstruction dalvikInsn; + int width = parseInsn(codePtr, &dalvikInsn, false); + + /* Terminate when the data section is seen */ + if (width == 0) + break; + + insnSize += width; + codePtr += width; + } + + realMethodEntry->dalvikSize = insnSize * 2; + return realMethodEntry; +} + +/* * Main entry point to start trace compilation. Basic blocks are constructed * first and they will be passed to the codegen routines to convert Dalvik * bytecode into machine code. @@ -190,15 +246,19 @@ void *dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts) unsigned int curOffset = currRun->frag.startOffset; unsigned int numInsts = currRun->frag.numInsts; const u2 *codePtr = dexCode->insns + curOffset; - int traceSize = 0; + int traceSize = 0; // # of half-words const u2 *startCodePtr = codePtr; BasicBlock *startBB, *curBB, *lastBB; int numBlocks = 0; static int compilationId; CompilationUnit cUnit; - memset(&cUnit, 0, sizeof(CompilationUnit)); + CompilerMethodStats *methodStats; compilationId++; + memset(&cUnit, 0, sizeof(CompilationUnit)); + + /* Locate the entry to store compilation statistics for this method */ + methodStats = analyzeMethodBody(desc->method); cUnit.registerScoreboard.nullCheckedRegs = dvmAllocBitVector(desc->method->registersSize, false); @@ -292,6 +352,9 @@ void *dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts) insn = dvmCompilerNew(sizeof(MIR),false); insn->offset = curOffset; width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe); + + /* The trace should never incude instruction data */ + assert(width); insn->width = width; traceSize += width; dvmCompilerAppendMIR(curBB, insn); @@ -320,6 +383,9 @@ void *dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts) } } + /* Convert # of half-word to bytes */ + methodStats->compiledDalvikSize += traceSize * 2; + /* * Now scan basic blocks containing real code to connect the * taken/fallthrough links. Also create chaining cells for code not included @@ -478,6 +544,7 @@ void *dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts) * translation's entry point. */ if (!cUnit.halveInstCount) { + methodStats->nativeSize += cUnit.totalSize; return cUnit.baseAddr + cUnit.headerSize; /* Halve the instruction count and retry again */ @@ -493,7 +560,7 @@ void *dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts) * TODO: implementation will be revisited when the trace builder can provide * whole-method traces. */ -void *dvmCompileMethod(Method *method) +void *dvmCompileMethod(const Method *method) { const DexCode *dexCode = dvmGetMethodCode(method); const u2 *codePtr = dexCode->insns; @@ -520,6 +587,9 @@ void *dvmCompileMethod(Method *method) const Method *callee; insn->width = width; + /* Terminate when the data section is seen */ + if (width == 0) + break; dvmCompilerAppendMIR(firstBlock, insn); /* * Check whether this is a block ending instruction and whether it @@ -590,6 +660,7 @@ void *dvmCompileMethod(Method *method) BasicBlock *newBB = dvmCompilerNewBB(DALVIK_BYTECODE); newBB->id = blockID++; newBB->firstMIRInsn = insn; + newBB->startOffset = insn->offset; newBB->lastMIRInsn = curBB->lastMIRInsn; curBB->lastMIRInsn = insn->prev; insn->prev->next = NULL; @@ -645,7 +716,8 @@ void *dvmCompileMethod(Method *method) } } - if (j == numBlocks) { + /* Don't create dummy block for the callee yet */ + if (j == numBlocks && !isInvoke) { LOGE("Target not found for insn %x: expect target %x\n", curBB->lastMIRInsn->offset, target); dvmAbort(); diff --git a/vm/compiler/Utility.c b/vm/compiler/Utility.c index 54f6971da..b0c40e649 100644 --- a/vm/compiler/Utility.c +++ b/vm/compiler/Utility.c @@ -154,17 +154,56 @@ void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit) } /* + * dvmHashForeach callback. + */ +static int dumpMethodStats(void *compilerMethodStats, void *totalMethodStats) +{ + CompilerMethodStats *methodStats = + (CompilerMethodStats *) compilerMethodStats; + CompilerMethodStats *totalStats = + (CompilerMethodStats *) totalMethodStats; + const Method *method = methodStats->method; + + totalStats->dalvikSize += methodStats->dalvikSize; + totalStats->compiledDalvikSize += methodStats->compiledDalvikSize; + totalStats->nativeSize += methodStats->nativeSize; + + int limit = (methodStats->dalvikSize >> 2) * 3; + + /* If over 3/4 of the Dalvik code is compiled, print something */ + if (methodStats->compiledDalvikSize >= limit) { + LOGD("Method stats: %s%s, %d/%d (compiled/total Dalvik), %d (native)", + method->clazz->descriptor, method->name, + methodStats->compiledDalvikSize, + methodStats->dalvikSize, + methodStats->nativeSize); + } + return 0; +} + +/* * Dump the current stats of the compiler, including number of bytes used in * the code cache, arena size, and work queue length, and various JIT stats. */ void dvmCompilerDumpStats(void) { - LOGD("%d compilations using %d bytes", - gDvmJit.numCompilations, gDvmJit.codeCacheByteUsed); + CompilerMethodStats totalMethodStats; + + memset(&totalMethodStats, 0, sizeof(CompilerMethodStats)); + LOGD("%d compilations using %d + %d bytes", + gDvmJit.numCompilations, + gDvmJit.templateSize, + gDvmJit.codeCacheByteUsed - gDvmJit.templateSize); LOGD("Compiler arena uses %d blocks (%d bytes each)", numArenaBlocks, ARENA_DEFAULT_SIZE); LOGD("Compiler work queue length is %d/%d", gDvmJit.compilerQueueLength, gDvmJit.compilerMaxQueued); dvmJitStats(); dvmCompilerArchDump(); + dvmHashForeach(gDvmJit.methodStatsTable, dumpMethodStats, + &totalMethodStats); + LOGD("Code size stats: %d/%d (compiled/total Dalvik), %d (native)", + totalMethodStats.compiledDalvikSize, + totalMethodStats.dalvikSize, + totalMethodStats.nativeSize); } diff --git a/vm/compiler/codegen/armv5te/Codegen.c b/vm/compiler/codegen/armv5te/Codegen.c index b272e4827..10589e1a1 100644 --- a/vm/compiler/codegen/armv5te/Codegen.c +++ b/vm/compiler/codegen/armv5te/Codegen.c @@ -3228,7 +3228,7 @@ void dvmCompilerArchDump(void) } } if (strlen(buf)) { - LOGD("dalvik.vm.jitop = %s", buf); + LOGD("dalvik.vm.jit.op = %s", buf); } } |