summaryrefslogtreecommitdiffstats
path: root/vm/hprof/Hprof.c
diff options
context:
space:
mode:
authorCarl Shapiro <cshapiro@google.com>2010-10-26 21:07:41 -0700
committerCarl Shapiro <cshapiro@google.com>2010-10-28 18:05:28 -0700
commit07018e2d14b012ae433a0d82025a885ed8debc3b (patch)
tree101b71a3eb10034779a38f01394ae98ba61c27a1 /vm/hprof/Hprof.c
parente2d2470a6282113b495f2c05a2fa47109d8a4b46 (diff)
downloadandroid_dalvik-07018e2d14b012ae433a0d82025a885ed8debc3b.tar.gz
android_dalvik-07018e2d14b012ae433a0d82025a885ed8debc3b.tar.bz2
android_dalvik-07018e2d14b012ae433a0d82025a885ed8debc3b.zip
Separate HPROF from the GC.
In the beginning, the only way to traverse the roots and heap was to piggyback off the garbage collector. As such, HPROF was implemented by instrumenting the root- and object traversal routines to check a mode flag and call into HPROF during a GC when the flag was set. This change moves the HPROF calls out of the GC and into callbacks invoked through the visitor. Notably, it allows HPROF dumps to be computed at any point in time without invoking a GC and potentially destroying evidence relating to the cause of an OOM. Change-Id: I2b74c4f10f35af3ca33b7c0bbfe470a8b586ff66
Diffstat (limited to 'vm/hprof/Hprof.c')
-rw-r--r--vm/hprof/Hprof.c87
1 files changed, 86 insertions, 1 deletions
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;
+}