| Ben Cheng | ba4fc8b | 2009-06-01 13:00:29 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2009 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "Dalvik.h" |
| 18 | #include "CompilerInternals.h" |
| 19 | |
| 20 | static ArenaMemBlock *arenaHead, *currentArena; |
| 21 | static int numArenaBlocks; |
| 22 | |
| 23 | /* Allocate the initial memory block for arena-based allocation */ |
| 24 | bool dvmCompilerHeapInit(void) |
| 25 | { |
| 26 | assert(arenaHead == NULL); |
| 27 | arenaHead = |
| 28 | (ArenaMemBlock *) malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE); |
| 29 | if (arenaHead == NULL) { |
| 30 | LOGE("No memory left to create compiler heap memory\n"); |
| 31 | return false; |
| 32 | } |
| 33 | currentArena = arenaHead; |
| 34 | currentArena->bytesAllocated = 0; |
| 35 | currentArena->next = NULL; |
| 36 | numArenaBlocks = 1; |
| 37 | |
| 38 | return true; |
| 39 | } |
| 40 | |
| 41 | /* Arena-based malloc for compilation tasks */ |
| 42 | void * dvmCompilerNew(size_t size, bool zero) |
| 43 | { |
| 44 | size = (size + 3) & ~3; |
| 45 | retry: |
| 46 | /* Normal case - space is available in the current page */ |
| 47 | if (size + currentArena->bytesAllocated <= ARENA_DEFAULT_SIZE) { |
| 48 | void *ptr; |
| 49 | ptr = ¤tArena->ptr[currentArena->bytesAllocated]; |
| 50 | currentArena->bytesAllocated += size; |
| 51 | if (zero) { |
| 52 | memset(ptr, 0, size); |
| 53 | } |
| 54 | return ptr; |
| 55 | } else { |
| 56 | /* |
| 57 | * See if there are previously allocated arena blocks before the last |
| 58 | * reset |
| 59 | */ |
| 60 | if (currentArena->next) { |
| 61 | currentArena = currentArena->next; |
| 62 | goto retry; |
| 63 | } |
| 64 | /* |
| 65 | * If we allocate really large variable-sized data structures that |
| 66 | * could go above the limit we need to enhance the allocation |
| 67 | * mechanism. |
| 68 | */ |
| 69 | if (size > ARENA_DEFAULT_SIZE) { |
| 70 | LOGE("Requesting %d bytes which exceed the maximal size allowed\n", |
| 71 | size); |
| 72 | return NULL; |
| 73 | } |
| 74 | /* Time to allocate a new arena */ |
| 75 | ArenaMemBlock *newArena = (ArenaMemBlock *) |
| 76 | malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE); |
| 77 | newArena->bytesAllocated = 0; |
| 78 | newArena->next = NULL; |
| 79 | currentArena->next = newArena; |
| 80 | currentArena = newArena; |
| 81 | numArenaBlocks++; |
| Ben Cheng | e9695e5 | 2009-06-16 16:11:47 -0700 | [diff] [blame] | 82 | LOGD("Total arena pages for JIT: %d", numArenaBlocks); |
| Ben Cheng | ba4fc8b | 2009-06-01 13:00:29 -0700 | [diff] [blame] | 83 | goto retry; |
| 84 | } |
| 85 | return NULL; |
| 86 | } |
| 87 | |
| 88 | /* Reclaim all the arena blocks allocated so far */ |
| 89 | void dvmCompilerArenaReset(void) |
| 90 | { |
| 91 | ArenaMemBlock *block; |
| 92 | |
| 93 | for (block = arenaHead; block; block = block->next) { |
| 94 | block->bytesAllocated = 0; |
| 95 | } |
| 96 | currentArena = arenaHead; |
| 97 | } |
| 98 | |
| 99 | /* Growable List initialization */ |
| 100 | void dvmInitGrowableList(GrowableList *gList, size_t initLength) |
| 101 | { |
| 102 | gList->numAllocated = initLength; |
| 103 | gList->numUsed = 0; |
| 104 | gList->elemList = (void **) dvmCompilerNew(sizeof(void *) * initLength, |
| 105 | true); |
| 106 | } |
| 107 | |
| 108 | /* Expand the capacity of a growable list */ |
| 109 | static void expandGrowableList(GrowableList *gList) |
| 110 | { |
| 111 | int newLength = gList->numAllocated; |
| 112 | if (newLength < 128) { |
| 113 | newLength <<= 1; |
| 114 | } else { |
| 115 | newLength += 128; |
| 116 | } |
| 117 | void *newArray = dvmCompilerNew(sizeof(void *) * newLength, true); |
| 118 | memcpy(newArray, gList->elemList, sizeof(void *) * gList->numAllocated); |
| 119 | gList->numAllocated = newLength; |
| 120 | gList->elemList = newArray; |
| 121 | } |
| 122 | |
| 123 | /* Insert a new element into the growable list */ |
| 124 | void dvmInsertGrowableList(GrowableList *gList, void *elem) |
| 125 | { |
| 126 | if (gList->numUsed == gList->numAllocated) { |
| 127 | expandGrowableList(gList); |
| 128 | } |
| 129 | gList->elemList[gList->numUsed++] = elem; |
| 130 | } |
| 131 | |
| 132 | /* Debug Utility - dump a compilation unit */ |
| 133 | void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit) |
| 134 | { |
| 135 | int i; |
| 136 | BasicBlock *bb; |
| 137 | LOGD("%d blocks in total\n", cUnit->numBlocks); |
| 138 | |
| 139 | for (i = 0; i < cUnit->numBlocks; i++) { |
| 140 | bb = cUnit->blockList[i]; |
| 141 | LOGD("Block %d (insn %04x - %04x%s)\n", |
| 142 | bb->id, bb->startOffset, |
| 143 | bb->lastMIRInsn ? bb->lastMIRInsn->offset : bb->startOffset, |
| 144 | bb->lastMIRInsn ? "" : " empty"); |
| 145 | if (bb->taken) { |
| 146 | LOGD(" Taken branch: block %d (%04x)\n", |
| 147 | bb->taken->id, bb->taken->startOffset); |
| 148 | } |
| 149 | if (bb->fallThrough) { |
| 150 | LOGD(" Fallthrough : block %d (%04x)\n", |
| 151 | bb->fallThrough->id, bb->fallThrough->startOffset); |
| 152 | } |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | /* |
| Ben Cheng | 8b258bf | 2009-06-24 17:27:07 -0700 | [diff] [blame] | 157 | * dvmHashForeach callback. |
| 158 | */ |
| 159 | static int dumpMethodStats(void *compilerMethodStats, void *totalMethodStats) |
| 160 | { |
| 161 | CompilerMethodStats *methodStats = |
| 162 | (CompilerMethodStats *) compilerMethodStats; |
| 163 | CompilerMethodStats *totalStats = |
| 164 | (CompilerMethodStats *) totalMethodStats; |
| 165 | const Method *method = methodStats->method; |
| 166 | |
| 167 | totalStats->dalvikSize += methodStats->dalvikSize; |
| 168 | totalStats->compiledDalvikSize += methodStats->compiledDalvikSize; |
| 169 | totalStats->nativeSize += methodStats->nativeSize; |
| 170 | |
| 171 | int limit = (methodStats->dalvikSize >> 2) * 3; |
| 172 | |
| 173 | /* If over 3/4 of the Dalvik code is compiled, print something */ |
| 174 | if (methodStats->compiledDalvikSize >= limit) { |
| 175 | LOGD("Method stats: %s%s, %d/%d (compiled/total Dalvik), %d (native)", |
| 176 | method->clazz->descriptor, method->name, |
| 177 | methodStats->compiledDalvikSize, |
| 178 | methodStats->dalvikSize, |
| 179 | methodStats->nativeSize); |
| 180 | } |
| 181 | return 0; |
| 182 | } |
| 183 | |
| 184 | /* |
| Ben Cheng | ba4fc8b | 2009-06-01 13:00:29 -0700 | [diff] [blame] | 185 | * Dump the current stats of the compiler, including number of bytes used in |
| 186 | * the code cache, arena size, and work queue length, and various JIT stats. |
| 187 | */ |
| 188 | void dvmCompilerDumpStats(void) |
| 189 | { |
| Ben Cheng | 8b258bf | 2009-06-24 17:27:07 -0700 | [diff] [blame] | 190 | CompilerMethodStats totalMethodStats; |
| 191 | |
| 192 | memset(&totalMethodStats, 0, sizeof(CompilerMethodStats)); |
| 193 | LOGD("%d compilations using %d + %d bytes", |
| 194 | gDvmJit.numCompilations, |
| 195 | gDvmJit.templateSize, |
| 196 | gDvmJit.codeCacheByteUsed - gDvmJit.templateSize); |
| Ben Cheng | ba4fc8b | 2009-06-01 13:00:29 -0700 | [diff] [blame] | 197 | LOGD("Compiler arena uses %d blocks (%d bytes each)", |
| 198 | numArenaBlocks, ARENA_DEFAULT_SIZE); |
| 199 | LOGD("Compiler work queue length is %d/%d", gDvmJit.compilerQueueLength, |
| 200 | gDvmJit.compilerMaxQueued); |
| 201 | dvmJitStats(); |
| 202 | dvmCompilerArchDump(); |
| Ben Cheng | 8b258bf | 2009-06-24 17:27:07 -0700 | [diff] [blame] | 203 | dvmHashForeach(gDvmJit.methodStatsTable, dumpMethodStats, |
| 204 | &totalMethodStats); |
| 205 | LOGD("Code size stats: %d/%d (compiled/total Dalvik), %d (native)", |
| 206 | totalMethodStats.compiledDalvikSize, |
| 207 | totalMethodStats.dalvikSize, |
| 208 | totalMethodStats.nativeSize); |
| Ben Cheng | ba4fc8b | 2009-06-01 13:00:29 -0700 | [diff] [blame] | 209 | } |