diff options
-rw-r--r-- | vm/Thread.c | 13 | ||||
-rw-r--r-- | vm/Thread.h | 1 | ||||
-rw-r--r-- | vm/alloc/CardTable.c | 3 | ||||
-rw-r--r-- | vm/alloc/GC.h | 14 | ||||
-rw-r--r-- | vm/alloc/Heap.c | 100 | ||||
-rw-r--r-- | vm/alloc/HeapInternal.h | 9 | ||||
-rw-r--r-- | vm/alloc/MarkSweep.c | 36 | ||||
-rw-r--r-- | vm/alloc/Verify.c | 14 | ||||
-rw-r--r-- | vm/alloc/Visit.c | 100 | ||||
-rw-r--r-- | vm/alloc/Visit.h | 27 | ||||
-rw-r--r-- | vm/hprof/Hprof.c | 87 | ||||
-rw-r--r-- | vm/hprof/Hprof.h | 8 | ||||
-rw-r--r-- | vm/native/dalvik_system_VMDebug.c | 1 |
13 files changed, 194 insertions, 219 deletions
diff --git a/vm/Thread.c b/vm/Thread.c index a98dbd000..54d0f4bdd 100644 --- a/vm/Thread.c +++ b/vm/Thread.c @@ -534,6 +534,7 @@ static const char* getSuspendCauseStr(SuspendCause why) case SUSPEND_FOR_DEBUG_EVENT: return "debug-event"; case SUSPEND_FOR_STACK_DUMP: return "stack-dump"; case SUSPEND_FOR_VERIFY: return "verify"; + case SUSPEND_FOR_HPROF: return "hprof"; #if defined(WITH_JIT) case SUSPEND_FOR_TBL_RESIZE: return "table-resize"; case SUSPEND_FOR_IC_PATCH: return "inline-cache-patch"; @@ -4180,17 +4181,11 @@ static void gcScanThread(Thread *thread) /* continue anyway */ } - HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_THREAD_OBJECT, thread->threadId); - dvmMarkObject(thread->threadObj); // could be NULL, when constructing - HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_NATIVE_STACK, thread->threadId); - dvmMarkObject(thread->exception); // usually NULL gcScanReferenceTable(&thread->internalLocalRefTable); - HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_LOCAL, thread->threadId); - #ifdef USE_INDIRECT_REF gcScanIndirectRefTable(&thread->jniLocalRefTable); #else @@ -4198,16 +4193,10 @@ static void gcScanThread(Thread *thread) #endif if (thread->jniMonitorRefTable.table != NULL) { - HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_MONITOR, thread->threadId); - gcScanReferenceTable(&thread->jniMonitorRefTable); } - HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JAVA_FRAME, thread->threadId); - gcScanInterpStackReferences(thread); - - HPROF_CLEAR_GC_SCAN_STATE(); } static void gcScanAllThreads() diff --git a/vm/Thread.h b/vm/Thread.h index 5afeefe37..ce53c3391 100644 --- a/vm/Thread.h +++ b/vm/Thread.h @@ -289,6 +289,7 @@ typedef enum SuspendCause { SUSPEND_FOR_STACK_DUMP, SUSPEND_FOR_DEX_OPT, SUSPEND_FOR_VERIFY, + SUSPEND_FOR_HPROF, #if defined(WITH_JIT) SUSPEND_FOR_TBL_RESIZE, // jit-table resize SUSPEND_FOR_IC_PATCH, // polymorphic callsite inline-cache patch diff --git a/vm/alloc/CardTable.c b/vm/alloc/CardTable.c index 240e6575b..4f90371a6 100644 --- a/vm/alloc/CardTable.c +++ b/vm/alloc/CardTable.c @@ -228,7 +228,8 @@ static void dumpReferencesCallback(void *ptr, void *arg) /* * Root visitor that looks for matching references. */ -static void dumpReferencesRootVisitor(void *ptr, void *arg) +static void dumpReferencesRootVisitor(void *ptr, u4 threadId, + RootType type, void *arg) { Object *obj = *(Object **)ptr; Object *lookingFor = *(Object **)arg; diff --git a/vm/alloc/GC.h b/vm/alloc/GC.h index 62e9aa616..c65c807a4 100644 --- a/vm/alloc/GC.h +++ b/vm/alloc/GC.h @@ -138,18 +138,4 @@ void dvmGcMarkJniGlobalRefs(void); */ void dvmGcMarkDebuggerRefs(void); -/* - * Optional heap profiling. - */ -#if WITH_HPROF && !defined(_DALVIK_HPROF_HPROF) -#include "hprof/Hprof.h" -#define HPROF_SET_GC_SCAN_STATE(tag_, thread_) \ - dvmHeapSetHprofGcScanState((tag_), (thread_)) -#define HPROF_CLEAR_GC_SCAN_STATE() \ - dvmHeapSetHprofGcScanState(0, 0) -#else -#define HPROF_SET_GC_SCAN_STATE(tag_, thread_) do {} while (false) -#define HPROF_CLEAR_GC_SCAN_STATE() do {} while (false) -#endif - #endif // _DALVIK_ALLOC_GC diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c index 843ee385a..bd782bd5d 100644 --- a/vm/alloc/Heap.c +++ b/vm/alloc/Heap.c @@ -25,7 +25,6 @@ #include "alloc/DdmHeap.h" #include "alloc/HeapSource.h" #include "alloc/MarkSweep.h" -#include "alloc/Visit.h" #include "utils/threads.h" // need Android thread priorities #define kInvalidPriority 10000 @@ -41,8 +40,7 @@ static const char* GcReasonStr[] = { [GC_FOR_MALLOC] = "GC_FOR_MALLOC", [GC_CONCURRENT] = "GC_CONCURRENT", [GC_EXPLICIT] = "GC_EXPLICIT", - [GC_EXTERNAL_ALLOC] = "GC_EXTERNAL_ALLOC", - [GC_HPROF_DUMP_HEAP] = "GC_HPROF_DUMP_HEAP" + [GC_EXTERNAL_ALLOC] = "GC_EXTERNAL_ALLOC" }; /* @@ -71,10 +69,6 @@ bool dvmHeapStartup() gcHeap->ddmHpsgWhat = 0; gcHeap->ddmNhsgWhen = 0; gcHeap->ddmNhsgWhat = 0; -#if WITH_HPROF - gcHeap->hprofDumpOnGc = false; - gcHeap->hprofContext = NULL; -#endif gDvm.gcHeap = gcHeap; /* Set up the lists and lock we'll use for finalizable @@ -661,46 +655,6 @@ void dvmCollectGarbageInternal(bool clearSoftRefs, GcReason reason) dvmMethodTraceGCBegin(); -#if WITH_HPROF - -/* Set DUMP_HEAP_ON_DDMS_UPDATE to 1 to enable heap dumps - * whenever DDMS requests a heap update (HPIF chunk). - * The output files will appear in /data/misc, which must - * already exist. - * You must define "WITH_HPROF := true" in your buildspec.mk - * and recompile libdvm for this to work. - * - * To enable stack traces for each allocation, define - * "WITH_HPROF_STACK := true" in buildspec.mk. This option slows down - * allocations and also requires 8 additional bytes per object on the - * GC heap. - */ -#define DUMP_HEAP_ON_DDMS_UPDATE 0 -#if DUMP_HEAP_ON_DDMS_UPDATE - gcHeap->hprofDumpOnGc |= (gcHeap->ddmHpifWhen != 0); -#endif - - if (gcHeap->hprofDumpOnGc) { - char nameBuf[128]; - - gcHeap->hprofResult = -1; - - if (gcHeap->hprofFileName == NULL) { - /* no filename was provided; invent one */ - sprintf(nameBuf, "/data/misc/heap-dump-tm%d-pid%d.hprof", - (int) time(NULL), (int) getpid()); - gcHeap->hprofFileName = nameBuf; - } - gcHeap->hprofContext = hprofStartup(gcHeap->hprofFileName, - gcHeap->hprofFd, gcHeap->hprofDirectToDdms); - if (gcHeap->hprofContext != NULL) { - hprofStartHeapDump(gcHeap->hprofContext); - } - gcHeap->hprofDumpOnGc = false; - gcHeap->hprofFileName = NULL; - } -#endif - /* Set up the marking context. */ if (!dvmHeapBeginMarkStep(gcMode)) { @@ -852,16 +806,6 @@ void dvmCollectGarbageInternal(bool clearSoftRefs, GcReason reason) currAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0); currFootprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0); -#if WITH_HPROF - if (gcHeap->hprofContext != NULL) { - hprofFinishHeapDump(gcHeap->hprofContext); -//TODO: write a HEAP_SUMMARY record - if (hprofShutdown(gcHeap->hprofContext)) - gcHeap->hprofResult = 0; /* indicate success */ - gcHeap->hprofContext = NULL; - } -#endif - /* Now that we've freed up the GC heap, return any large * free chunks back to the system. They'll get paged back * in the next time they're used. Don't do it immediately, @@ -963,45 +907,3 @@ void dvmWaitForConcurrentGcToComplete(void) dvmWaitCond(&gDvm.gcHeapCond, &gDvm.gcHeapLock); dvmChangeStatus(self, oldStatus); } - -#if WITH_HPROF -/* - * Perform garbage collection, writing heap information to the specified file. - * - * If "fd" is >= 0, the output will be written to that file descriptor. - * Otherwise, "fileName" is used to create an output file. - * - * If "fileName" is NULL, a suitable name will be generated automatically. - * (TODO: remove this when the SIGUSR1 feature goes away) - * - * If "directToDdms" is set, the other arguments are ignored, and data is - * sent directly to DDMS. - * - * Returns 0 on success, or an error code on failure. - */ -int hprofDumpHeap(const char* fileName, int fd, bool directToDdms) -{ - int result; - - dvmLockMutex(&gDvm.gcHeapLock); - - gDvm.gcHeap->hprofDumpOnGc = true; - gDvm.gcHeap->hprofFileName = fileName; - gDvm.gcHeap->hprofFd = fd; - gDvm.gcHeap->hprofDirectToDdms = directToDdms; - dvmCollectGarbageInternal(false, GC_HPROF_DUMP_HEAP); - result = gDvm.gcHeap->hprofResult; - - dvmUnlockMutex(&gDvm.gcHeapLock); - - return result; -} - -void dvmHeapSetHprofGcScanState(hprof_heap_tag_t state, u4 threadSerialNumber) -{ - if (gDvm.gcHeap->hprofContext != NULL) { - hprofSetGcScanState(gDvm.gcHeap->hprofContext, state, - threadSerialNumber); - } -} -#endif diff --git a/vm/alloc/HeapInternal.h b/vm/alloc/HeapInternal.h index 0298f842e..5a7e43d29 100644 --- a/vm/alloc/HeapInternal.h +++ b/vm/alloc/HeapInternal.h @@ -110,15 +110,6 @@ struct GcHeap { int ddmHpsgWhat; int ddmNhsgWhen; int ddmNhsgWhat; - -#if WITH_HPROF - bool hprofDumpOnGc; - const char* hprofFileName; - int hprofFd; - hprof_context_t *hprofContext; - int hprofResult; - bool hprofDirectToDdms; -#endif }; bool dvmLockHeap(void); diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c index 91365adbe..84c111a13 100644 --- a/vm/alloc/MarkSweep.c +++ b/vm/alloc/MarkSweep.c @@ -131,12 +131,6 @@ static void markObjectNonNull(const Object *obj, GcMarkContext *ctx, */ MARK_STACK_PUSH(ctx->stack, obj); } - -#if WITH_HPROF - if (gDvm.gcHeap->hprofContext != NULL) { - hprofMarkRootObject(gDvm.gcHeap->hprofContext, obj, 0); - } -#endif } } @@ -198,8 +192,6 @@ void dvmHeapMarkRootSet() { GcHeap *gcHeap = gDvm.gcHeap; - HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_STICKY_CLASS, 0); - LOG_SCAN("immune objects"); dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit); @@ -208,41 +200,24 @@ void dvmHeapMarkRootSet() LOG_SCAN("primitive classes\n"); dvmGcScanPrimitiveClasses(); - /* dvmGcScanRootThreadGroups() sets a bunch of - * different scan states internally. - */ - HPROF_CLEAR_GC_SCAN_STATE(); - LOG_SCAN("root thread groups\n"); dvmGcScanRootThreadGroups(); - HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_INTERNED_STRING, 0); - LOG_SCAN("interned strings\n"); dvmGcScanInternedStrings(); - HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_GLOBAL, 0); - LOG_SCAN("JNI global refs\n"); dvmGcMarkJniGlobalRefs(); - HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0); - LOG_SCAN("pending reference operations\n"); dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations); - HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0); - LOG_SCAN("pending finalizations\n"); dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs); - HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_DEBUGGER, 0); - LOG_SCAN("debugger refs\n"); dvmGcMarkDebuggerRefs(); - HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_VM_INTERNAL, 0); - /* Mark any special objects we have sitting around. */ LOG_SCAN("special objects\n"); @@ -250,15 +225,13 @@ void dvmHeapMarkRootSet() dvmMarkObjectNonNull(gDvm.internalErrorObj); dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj); //TODO: scan object references sitting in gDvm; use pointer begin & end - - HPROF_CLEAR_GC_SCAN_STATE(); } /* * Callback applied to root references. If the root location contains * a white reference it is pushed on the mark stack and grayed. */ -static void markObjectVisitor(void *addr, void *arg) +static void markObjectVisitor(void *addr, RootType type, u4 thread, void *arg) { Object *obj; @@ -519,11 +492,6 @@ static void scanObject(const Object *obj, GcMarkContext *ctx) assert(obj != NULL); assert(ctx != NULL); assert(obj->clazz != NULL); -#if WITH_HPROF - if (gDvm.gcHeap->hprofContext != NULL) { - hprofDumpHeapObject(gDvm.gcHeap->hprofContext, obj); - } -#endif /* Dispatch a type-specific scan routine. */ if (obj->clazz == gDvm.classJavaLangClass) { scanClassObject((ClassObject *)obj, ctx); @@ -986,13 +954,11 @@ void dvmHeapScheduleFinalizations() ref = newPendingRefs.table; lastRef = newPendingRefs.nextEntry; assert(ref < lastRef); - HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0); while (ref < lastRef) { assert(*ref != NULL); markObject(*ref, ctx); ref++; } - HPROF_CLEAR_GC_SCAN_STATE(); processMarkStack(ctx); dvmSignalHeapWorker(false); } diff --git a/vm/alloc/Verify.c b/vm/alloc/Verify.c index a48ff2982..5ce692cb1 100644 --- a/vm/alloc/Verify.c +++ b/vm/alloc/Verify.c @@ -42,7 +42,8 @@ static void dumpReferencesCallback(void *ptr, void *arg) } } -static void dumpReferencesRootVisitor(void *ptr, void *arg) +static void dumpReferencesRootVisitor(void *ptr, u4 threadId, + RootType type, void *arg) { Object *obj = *(Object **)ptr; Object *lookingFor = *(Object **)arg; @@ -120,9 +121,18 @@ void dvmVerifyBitmap(const HeapBitmap *bitmap) } /* + * Helper function to call verifyReference from the root verifier. + */ +static void verifyRootReference(void *addr, u4 threadId, + RootType type, void *arg) +{ + verifyReference(addr, arg); +} + +/* * Verifies references in the roots. */ void dvmVerifyRoots(void) { - dvmVisitRoots(verifyReference, NULL); + dvmVisitRoots(verifyRootReference, NULL); } diff --git a/vm/alloc/Visit.c b/vm/alloc/Visit.c index 0af27dacf..537117758 100644 --- a/vm/alloc/Visit.c +++ b/vm/alloc/Visit.c @@ -34,7 +34,8 @@ void dvmVisitObject(Visitor *visitor, Object *obj, void *arg) /* * Applies a verification function to all present values in the hash table. */ -static void visitHashTable(Visitor *visitor, HashTable *table, void *arg) +static void visitHashTable(RootVisitor *visitor, HashTable *table, + RootType type, void *arg) { int i; @@ -44,17 +45,32 @@ static void visitHashTable(Visitor *visitor, HashTable *table, void *arg) for (i = 0; i < table->tableSize; ++i) { HashEntry *entry = &table->pEntries[i]; if (entry->data != NULL && entry->data != HASH_TOMBSTONE) { - (*visitor)(&entry->data, arg); + (*visitor)(&entry->data, 0, type, arg); } } dvmHashTableUnlock(table); } /* + * Applies a verification function to all elements in the array. + */ +static void visitArray(RootVisitor *visitor, Object **array, size_t length, + RootType type, void *arg) +{ + size_t i; + + assert(visitor != NULL); + assert(array != NULL); + for (i = 0; i < length; ++i) { + (*visitor)(&array[i], 0, type, arg); + } +} + +/* * Visits all entries in the reference table. */ -static void visitReferenceTable(Visitor *visitor, const ReferenceTable *table, - void *arg) +static void visitReferenceTable(RootVisitor *visitor, ReferenceTable *table, + u4 threadId, RootType type, void *arg) { Object **entry; @@ -62,7 +78,7 @@ static void visitReferenceTable(Visitor *visitor, const ReferenceTable *table, assert(table != NULL); for (entry = table->table; entry < table->nextEntry; ++entry) { assert(entry != NULL); - (*visitor)(entry, arg); + (*visitor)(entry, threadId, type, arg); } } @@ -70,29 +86,32 @@ static void visitReferenceTable(Visitor *visitor, const ReferenceTable *table, * Visits a large heap reference table. These objects are list heads. * As such, it is valid for table to be NULL. */ -static void visitLargeHeapRefTable(Visitor *visitor, LargeHeapRefTable *table, - void *arg) +static void visitLargeHeapRefTable(RootVisitor *visitor, + LargeHeapRefTable *table, + RootType type, void *arg) { assert(visitor != NULL); for (; table != NULL; table = table->next) { - visitReferenceTable(visitor, &table->refs, arg); + visitReferenceTable(visitor, &table->refs, 0, type, arg); } } /* * Visits all stack slots. TODO: visit native methods. */ -static void visitThreadStack(Visitor *visitor, Thread *thread, void *arg) +static void visitThreadStack(RootVisitor *visitor, Thread *thread, void *arg) { const StackSaveArea *saveArea; - u4 *framePtr; + u4 *fp; + u4 threadId; assert(visitor != NULL); assert(thread != NULL); - framePtr = (u4 *)thread->curFrame; - for (; framePtr != NULL; framePtr = saveArea->prevFrame) { + threadId = thread->threadId; + fp = (u4 *)thread->curFrame; + for (; fp != NULL; fp = saveArea->prevFrame) { Method *method; - saveArea = SAVEAREA_FROM_FP(framePtr); + saveArea = SAVEAREA_FROM_FP(fp); method = (Method *)saveArea->method; if (method != NULL && !dvmIsNativeMethod(method)) { const RegisterMap* pMap = dvmGetExpandedRegisterMap(method); @@ -111,8 +130,8 @@ static void visitThreadStack(Visitor *visitor, Thread *thread, void *arg) * scan. */ for (i = 0; i < method->registersSize; ++i) { - if (dvmIsValidObject((Object *)framePtr[i])) { - (*visitor)(&framePtr[i], arg); + if (dvmIsValidObject((Object *)fp[i])) { + (*visitor)(&fp[i], threadId, ROOT_JAVA_FRAME, arg); } } } else { @@ -135,7 +154,7 @@ static void visitThreadStack(Visitor *visitor, Thread *thread, void *arg) /* * Register is marked as live, it's a valid root. */ - (*visitor)(&framePtr[i], arg); + (*visitor)(&fp[i], threadId, ROOT_JAVA_FRAME, arg); } } dvmReleaseRegisterMapLine(pMap, regVector); @@ -144,7 +163,7 @@ static void visitThreadStack(Visitor *visitor, Thread *thread, void *arg) /* * Don't fall into an infinite loop if things get corrupted. */ - assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr || + assert((uintptr_t)saveArea->prevFrame > (uintptr_t)fp || saveArea->prevFrame == NULL); } } @@ -152,16 +171,19 @@ static void visitThreadStack(Visitor *visitor, Thread *thread, void *arg) /* * Visits all roots associated with a thread. */ -static void visitThread(Visitor *visitor, Thread *thread, void *arg) +static void visitThread(RootVisitor *visitor, Thread *thread, void *arg) { + u4 threadId; + assert(visitor != NULL); assert(thread != NULL); - (*visitor)(&thread->threadObj, arg); - (*visitor)(&thread->exception, arg); - visitReferenceTable(visitor, &thread->internalLocalRefTable, arg); - visitReferenceTable(visitor, &thread->jniLocalRefTable, arg); - if (thread->jniMonitorRefTable.table) { - visitReferenceTable(visitor, &thread->jniMonitorRefTable, arg); + threadId = thread->threadId; + (*visitor)(&thread->threadObj, threadId, ROOT_THREAD_OBJECT, arg); + (*visitor)(&thread->exception, threadId, ROOT_NATIVE_STACK, arg); + visitReferenceTable(visitor, &thread->internalLocalRefTable, threadId, ROOT_NATIVE_STACK, arg); + visitReferenceTable(visitor, &thread->jniLocalRefTable, threadId, ROOT_JNI_LOCAL, arg); + if (thread->jniMonitorRefTable.table != NULL) { + visitReferenceTable(visitor, &thread->jniMonitorRefTable, threadId, ROOT_JNI_MONITOR, arg); } visitThreadStack(visitor, thread, arg); } @@ -169,7 +191,7 @@ static void visitThread(Visitor *visitor, Thread *thread, void *arg) /* * Visits all threads on the thread list. */ -static void visitThreads(Visitor *visitor, void *arg) +static void visitThreads(RootVisitor *visitor, void *arg) { Thread *thread; @@ -184,22 +206,22 @@ static void visitThreads(Visitor *visitor, void *arg) } /* - * Visits roots. TODO: visit all roots. + * Visits roots. TODO: visit cached global references. */ -void dvmVisitRoots(Visitor *visitor, void *arg) +void dvmVisitRoots(RootVisitor *visitor, void *arg) { assert(visitor != NULL); - visitHashTable(visitor, gDvm.loadedClasses, arg); - visitHashTable(visitor, gDvm.dbgRegistry, arg); - visitHashTable(visitor, gDvm.internedStrings, arg); - visitHashTable(visitor, gDvm.literalStrings, arg); - visitReferenceTable(visitor, &gDvm.jniGlobalRefTable, arg); - visitReferenceTable(visitor, &gDvm.jniPinRefTable, arg); - visitLargeHeapRefTable(visitor, gDvm.gcHeap->referenceOperations, arg); - visitLargeHeapRefTable(visitor, gDvm.gcHeap->pendingFinalizationRefs, arg); + visitHashTable(visitor, gDvm.loadedClasses, ROOT_STICKY_CLASS, arg); + visitArray(visitor, (Object **)gDvm.primitiveClass, NELEM(gDvm.primitiveClass), ROOT_STICKY_CLASS, arg); + visitHashTable(visitor, gDvm.dbgRegistry, ROOT_DEBUGGER, arg); + visitHashTable(visitor, gDvm.internedStrings, ROOT_INTERNED_STRING, arg); + visitHashTable(visitor, gDvm.literalStrings, ROOT_INTERNED_STRING, arg); + visitReferenceTable(visitor, &gDvm.jniGlobalRefTable, 0, ROOT_JNI_GLOBAL, arg); + visitReferenceTable(visitor, &gDvm.jniPinRefTable, 0, ROOT_NATIVE_STACK, arg); + visitLargeHeapRefTable(visitor, gDvm.gcHeap->referenceOperations, ROOT_REFERENCE_CLEANUP, arg); + visitLargeHeapRefTable(visitor, gDvm.gcHeap->pendingFinalizationRefs, ROOT_FINALIZING, arg); visitThreads(visitor, arg); - (*visitor)(&gDvm.outOfMemoryObj, arg); - (*visitor)(&gDvm.internalErrorObj, arg); - (*visitor)(&gDvm.noClassDefFoundErrorObj, arg); - /* TODO: visit cached global references. */ + (*visitor)(&gDvm.outOfMemoryObj, 0, ROOT_VM_INTERNAL, arg); + (*visitor)(&gDvm.internalErrorObj, 0, ROOT_VM_INTERNAL, arg); + (*visitor)(&gDvm.noClassDefFoundErrorObj, 0, ROOT_VM_INTERNAL, arg); } diff --git a/vm/alloc/Visit.h b/vm/alloc/Visit.h index 488c7212e..e7c52e58f 100644 --- a/vm/alloc/Visit.h +++ b/vm/alloc/Visit.h @@ -19,6 +19,24 @@ #include "Dalvik.h" +typedef enum { + ROOT_UNKNOWN = 0, + ROOT_JNI_GLOBAL, + ROOT_JNI_LOCAL, + ROOT_JAVA_FRAME, + ROOT_NATIVE_STACK, + ROOT_STICKY_CLASS, + ROOT_THREAD_BLOCK, + ROOT_MONITOR_USED, + ROOT_THREAD_OBJECT, + ROOT_INTERNED_STRING, + ROOT_FINALIZING, + ROOT_DEBUGGER, + ROOT_REFERENCE_CLEANUP, + ROOT_VM_INTERNAL, + ROOT_JNI_MONITOR, +} RootType; + /* * Callback invoked with the address of a reference and a user * supplied context argument. @@ -26,6 +44,13 @@ typedef void Visitor(void *addr, void *arg); /* + * Like a Visitor, but passes root specific information such as the + * containing thread id and the root type. In cases where a root is + * not specific to a thread, 0, an invalid thread id is provided. + */ +typedef void RootVisitor(void *addr, u4 threadId, RootType type, void *arg); + +/* * Visits references in an object. */ void dvmVisitObject(Visitor *visitor, Object *obj, void *arg); @@ -33,6 +58,6 @@ void dvmVisitObject(Visitor *visitor, Object *obj, void *arg); /* * Visits references in the root set. */ -void dvmVisitRoots(Visitor *visitor, void *arg); +void dvmVisitRoots(RootVisitor *visitor, void *arg); #endif /* _DALVIK_ALLOC_VISIT */ diff --git a/vm/hprof/Hprof.c b/vm/hprof/Hprof.c index 28f81c778..5cd5136c2 100644 --- a/vm/hprof/Hprof.c +++ b/vm/hprof/Hprof.c @@ -21,7 +21,10 @@ * heap, and some analysis tools require that the class and string data * appear first. */ + #include "Hprof.h" +#include "alloc/HeapInternal.h" +#include "alloc/Visit.h" #include <string.h> #include <unistd.h> @@ -30,7 +33,6 @@ #include <sys/time.h> #include <time.h> - #define kHeadSuffix "-hptemp" hprof_context_t * @@ -183,3 +185,86 @@ hprofFreeContext(hprof_context_t *ctx) free(ctx->fileDataPtr); free(ctx); } + +/* + * Visitor invoked on every root reference. + */ +static void hprofRootVisitor(void *addr, u4 threadId, RootType type, void *arg) +{ + static const hprof_heap_tag_t xlate[] = { + HPROF_ROOT_UNKNOWN, + HPROF_ROOT_JNI_GLOBAL, + HPROF_ROOT_JNI_LOCAL, + HPROF_ROOT_JAVA_FRAME, + HPROF_ROOT_NATIVE_STACK, + HPROF_ROOT_STICKY_CLASS, + HPROF_ROOT_THREAD_BLOCK, + HPROF_ROOT_MONITOR_USED, + HPROF_ROOT_THREAD_OBJECT, + HPROF_ROOT_INTERNED_STRING, + HPROF_ROOT_FINALIZING, + HPROF_ROOT_DEBUGGER, + HPROF_ROOT_REFERENCE_CLEANUP, + HPROF_ROOT_VM_INTERNAL, + HPROF_ROOT_JNI_MONITOR, + }; + hprof_context_t *ctx; + + assert(arg != NULL); + assert(type < NELEM(xlate)); + ctx = arg; + ctx->gcScanState = xlate[type]; + ctx->gcThreadSerialNumber = threadId; + hprofMarkRootObject(ctx, addr, 0); + ctx->gcScanState = 0; + ctx->gcThreadSerialNumber = 0; +} + +/* + * Visitor invoked on every heap object. + */ +static void hprofBitmapCallback(void *ptr, void *arg) +{ + Object *obj; + hprof_context_t *ctx; + + assert(ptr != NULL); + assert(arg != NULL); + obj = ptr; + ctx = arg; + hprofDumpHeapObject(ctx, obj); +} + +/* + * Walk the roots and heap writing heap information to the specified + * file. + * + * If "fd" is >= 0, the output will be written to that file descriptor. + * Otherwise, "fileName" is used to create an output file. + * + * If "directToDdms" is set, the other arguments are ignored, and data is + * sent directly to DDMS. + * + * Returns 0 on success, or an error code on failure. + */ +int hprofDumpHeap(const char* fileName, int fd, bool directToDdms) +{ + hprof_context_t *ctx; + int success; + + assert(fileName != NULL); + dvmLockHeap(); + dvmSuspendAllThreads(SUSPEND_FOR_HPROF); + ctx = hprofStartup(fileName, fd, directToDdms); + if (ctx == NULL) { + return -1; + } + dvmVisitRoots(hprofRootVisitor, ctx); + dvmHeapBitmapWalk(dvmHeapSourceGetLiveBits(), hprofBitmapCallback, ctx); + hprofFinishHeapDump(ctx); +//TODO: write a HEAP_SUMMARY record + success = hprofShutdown(ctx) ? 0 : -1; + dvmSuspendAllThreads(SUSPEND_FOR_HPROF); + dvmUnlockHeap(); + return success; +} diff --git a/vm/hprof/Hprof.h b/vm/hprof/Hprof.h index 18f410253..f95e2e193 100644 --- a/vm/hprof/Hprof.h +++ b/vm/hprof/Hprof.h @@ -251,13 +251,9 @@ bool hprofShutdown(hprof_context_t *ctx); void hprofFreeContext(hprof_context_t *ctx); /* - * Heap.c functions - * - * The contents of the hprof directory have no knowledge of - * the heap implementation; these functions require heap knowledge, - * so they are implemented in Heap.c. + * HprofVisit.c functions */ + int hprofDumpHeap(const char* fileName, int fd, bool directToDdms); -void dvmHeapSetHprofGcScanState(hprof_heap_tag_t state, u4 threadSerialNumber); #endif // _DALVIK_HPROF_HPROF diff --git a/vm/native/dalvik_system_VMDebug.c b/vm/native/dalvik_system_VMDebug.c index b9f3610a7..80e97e083 100644 --- a/vm/native/dalvik_system_VMDebug.c +++ b/vm/native/dalvik_system_VMDebug.c @@ -19,6 +19,7 @@ */ #include "Dalvik.h" #include "native/InternalNativePriv.h" +#include "hprof/Hprof.h" #include <string.h> #include <unistd.h> |