Unify reference table dump
Merge ReferenceTable and IndirectRefTable debugging-dump functions.
Bug 3447435
Change-Id: I154a84b1910d10cf68b62b079da6bd1e5475222f
diff --git a/vm/IndirectRefTable.c b/vm/IndirectRefTable.c
index 8d7b3f9..81cfeed 100644
--- a/vm/IndirectRefTable.c
+++ b/vm/IndirectRefTable.c
@@ -345,158 +345,10 @@
}
/*
- * This is a qsort() callback. We sort Object* by class, allocation size,
- * and then by the Object* itself.
- */
-static int compareObject(const void* vobj1, const void* vobj2)
-{
- Object* obj1 = *((Object**) vobj1);
- Object* obj2 = *((Object**) vobj2);
-
- /* ensure null references appear at the end */
- if (obj1 == NULL) {
- if (obj2 == NULL) {
- return 0;
- } else {
- return 1;
- }
- } else if (obj2 == NULL) {
- return -1;
- }
-
- if (obj1->clazz != obj2->clazz) {
- return (u1*)obj1->clazz - (u1*)obj2->clazz;
- } else {
- int size1 = dvmObjectSizeInHeap(obj1);
- int size2 = dvmObjectSizeInHeap(obj2);
- if (size1 != size2) {
- return size1 - size2;
- } else {
- return (u1*)obj1 - (u1*)obj2;
- }
- }
-}
-
-/*
- * Log an object with some additional info.
- *
- * Pass in the number of additional elements that are identical to or
- * equivalent to the original.
- */
-static void logObject(Object* obj, int size, int identical, int equiv)
-{
- if (obj == NULL) {
- LOGW(" NULL reference (count=%d)\n", equiv);
- return;
- }
-
- if (identical + equiv != 0) {
- LOGW("%5d of %s %dB (%d unique)\n", identical + equiv +1,
- obj->clazz->descriptor, size, equiv +1);
- } else {
- LOGW("%5d of %s %dB\n", identical + equiv +1,
- obj->clazz->descriptor, size);
- }
-}
-
-/*
* Dump the contents of a IndirectRefTable to the log.
*/
void dvmDumpIndirectRefTable(const IndirectRefTable* pRef, const char* descr)
{
- const int kLast = 10;
- int count = dvmIndirectRefTableEntries(pRef);
- Object** refs;
- int i;
-
- if (count == 0) {
- LOGW("Reference table has no entries\n");
- return;
- }
- assert(count > 0);
-
- /*
- * Dump the most recent N entries. If there are holes, we will show
- * fewer than N.
- */
- LOGW("Last %d entries in %s reference table:\n", kLast, descr);
- refs = pRef->table; // use unsorted list
- int size;
- int start = count - kLast;
- if (start < 0)
- start = 0;
-
- for (i = start; i < count; i++) {
- if (refs[i] == NULL)
- continue;
- size = dvmObjectSizeInHeap(refs[i]);
- Object* ref = refs[i];
- if (ref->clazz == gDvm.classJavaLangClass) {
- ClassObject* clazz = (ClassObject*) ref;
- LOGW("%5d: %p cls=%s '%s' (%d bytes)\n", i, ref,
- (refs[i] == NULL) ? "-" : ref->clazz->descriptor,
- clazz->descriptor, size);
- } else {
- LOGW("%5d: %p cls=%s (%d bytes)\n", i, ref,
- (refs[i] == NULL) ? "-" : ref->clazz->descriptor, size);
- }
- }
-
- /*
- * Make a copy of the table, and sort it.
- *
- * The NULL "holes" wind up at the end, so we can strip them off easily.
- */
- Object** tableCopy = (Object**)malloc(sizeof(Object*) * count);
- memcpy(tableCopy, pRef->table, sizeof(Object*) * count);
- qsort(tableCopy, count, sizeof(Object*), compareObject);
- refs = tableCopy; // use sorted list
-
- if (false) {
- int q;
- for (q = 0; q < count; q++)
- LOGI("%d %p\n", q, refs[q]);
- }
-
- int holes = 0;
- while (refs[count-1] == NULL) {
- count--;
- holes++;
- }
-
- /*
- * Dump uniquified table summary. While we're at it, generate a
- * cumulative total amount of pinned memory based on the unique entries.
- */
- LOGW("%s reference table summary (%d entries / %d holes):\n",
- descr, count, holes);
- int equiv, identical, total;
- total = equiv = identical = 0;
- for (i = 1; i < count; i++) {
- size = dvmObjectSizeInHeap(refs[i-1]);
-
- if (refs[i] == refs[i-1]) {
- /* same reference, added more than once */
- identical++;
- } else if (refs[i]->clazz == refs[i-1]->clazz &&
- (int) dvmObjectSizeInHeap(refs[i]) == size)
- {
- /* same class / size, different object */
- total += size;
- equiv++;
- } else {
- /* different class */
- total += size;
- logObject(refs[i-1], size, identical, equiv);
- equiv = identical = 0;
- }
- }
-
- /* handle the last entry (everything above outputs refs[i-1]) */
- size = (refs[count-1] == NULL) ? 0 : dvmObjectSizeInHeap(refs[count-1]);
- total += size;
- logObject(refs[count-1], size, identical, equiv);
-
- LOGW("Memory held directly by native code is %d bytes\n", total);
- free(tableCopy);
+ dvmDumpReferenceTableContents(pRef->table, dvmIndirectRefTableEntries(pRef),
+ descr);
}
diff --git a/vm/IndirectRefTable.h b/vm/IndirectRefTable.h
index f5157cb..c33a509 100644
--- a/vm/IndirectRefTable.h
+++ b/vm/IndirectRefTable.h
@@ -376,6 +376,8 @@
/*
* Dump the contents of a reference table to the log file.
+ *
+ * The caller should lock any external sync before calling.
*/
void dvmDumpIndirectRefTable(const IndirectRefTable* pRef, const char* descr);
diff --git a/vm/ReferenceTable.c b/vm/ReferenceTable.c
index 8984d5f..20d4d46 100644
--- a/vm/ReferenceTable.c
+++ b/vm/ReferenceTable.c
@@ -156,11 +156,19 @@
*/
static int compareObject(const void* vobj1, const void* vobj2)
{
- Object* obj1 = *((Object**) vobj1);
- Object* obj2 = *((Object**) vobj2);
+ const Object* obj1 = *((Object* const*) vobj1);
+ const Object* obj2 = *((Object* const*) vobj2);
- if (obj1 == NULL || obj2 == NULL)
- return (u1*)obj1 - (u1*)obj2;
+ /* ensure null references appear at the end */
+ if (obj1 == NULL) {
+ if (obj2 == NULL) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else if (obj2 == NULL) {
+ return -1;
+ }
if (obj1->clazz != obj2->clazz) {
return (u1*)obj1->clazz - (u1*)obj2->clazz;
@@ -181,7 +189,7 @@
* Pass in the number of additional elements that are identical to or
* equivalent to the original.
*/
-static void logObject(Object* obj, int size, int identical, int equiv)
+static void logObject(const Object* obj, int size, int identical, int equiv)
{
if (obj == NULL) {
LOGW(" NULL reference (count=%d)\n", equiv);
@@ -201,19 +209,15 @@
}
/*
- * Dump the contents of a ReferenceTable to the log.
+ * Dump a summary of an array of references to the log file.
*
- * The caller should lock any external sync before calling.
- *
- * (This was originally written to be tolerant of null entries in the table.
- * I don't think that can happen anymore.)
+ * This is used to dump the contents of ReferenceTable and IndirectRefTable
+ * structs.
*/
-void dvmDumpReferenceTable(const ReferenceTable* pRef, const char* descr)
+void dvmDumpReferenceTableContents(Object* const* refs, size_t count,
+ const char* descr)
{
- const int kLast = 10;
- int count = dvmReferenceTableEntries(pRef);
- Object** refs;
- int i;
+ const size_t kLast = 10;
if (count == 0) {
LOGW("%s reference table has no entries\n", descr);
@@ -225,26 +229,27 @@
* Dump the most recent N entries.
*/
LOGW("Last %d entries in %s reference table:\n", kLast, descr);
- refs = pRef->table; // use unsorted list
- int size;
+ size_t size, idx;
int start = count - kLast;
if (start < 0)
start = 0;
- for (i = start; i < count; i++) {
- size = (refs[i] == NULL) ? 0 : dvmObjectSizeInHeap(refs[i]);
- Object* ref = refs[i];
+ for (idx = start; idx < count; idx++) {
+ if (refs[idx] == NULL)
+ continue;
+ size = dvmObjectSizeInHeap(refs[idx]);
+ const Object* ref = refs[idx];
if (ref->clazz == gDvm.classJavaLangClass) {
ClassObject* clazz = (ClassObject*) ref;
- LOGW("%5d: %p cls=%s '%s' (%d bytes)\n", i, ref,
- (refs[i] == NULL) ? "-" : ref->clazz->descriptor,
+ LOGW("%5d: %p cls=%s '%s' (%d bytes)\n", idx, ref,
+ (refs[idx] == NULL) ? "-" : ref->clazz->descriptor,
clazz->descriptor, size);
} else if (ref->clazz == NULL) {
/* should only be possible right after a plain dvmMalloc() */
- LOGW("%5d: %p cls=(raw) (%d bytes)\n", i, ref, size);
+ LOGW("%5d: %p cls=(raw) (%d bytes)\n", idx, ref, size);
} else {
- LOGW("%5d: %p cls=%s (%d bytes)\n", i, ref,
- (refs[i] == NULL) ? "-" : ref->clazz->descriptor, size);
+ LOGW("%5d: %p cls=%s (%d bytes)\n", idx, ref,
+ (refs[idx] == NULL) ? "-" : ref->clazz->descriptor, size);
}
}
@@ -252,25 +257,43 @@
* Make a copy of the table, and sort it.
*/
Object** tableCopy = (Object**)malloc(sizeof(Object*) * count);
- memcpy(tableCopy, pRef->table, sizeof(Object*) * count);
+ if (tableCopy == NULL) {
+ LOGE("Unable to copy table with %d elements\n", count);
+ return;
+ }
+ memcpy(tableCopy, refs, sizeof(Object*) * count);
qsort(tableCopy, count, sizeof(Object*), compareObject);
refs = tableCopy; // use sorted list
/*
+ * Find and remove any "holes" in the list. The sort moved them all
+ * to the end.
+ *
+ * A table with nothing but NULL entries should have count==0, which
+ * was handled above, so this operation should not leave us with an
+ * empty list.
+ */
+ while (refs[count-1] == NULL) {
+ count--;
+ }
+ assert(count > 0);
+
+ /*
* Dump uniquified table summary. While we're at it, generate a
- * cumulative total amount of pinned memory based on the unique entries.
+ * cumulative total amount of referenced memory based on the unique
+ * entries.
*/
LOGW("%s reference table summary (%d entries):\n", descr, count);
- int equiv, identical, total;
+ size_t equiv, identical, total;
total = equiv = identical = 0;
- for (i = 1; i < count; i++) {
- size = (refs[i-1] == NULL) ? 0 : dvmObjectSizeInHeap(refs[i-1]);
+ for (idx = 1; idx < count; idx++) {
+ size = dvmObjectSizeInHeap(refs[idx-1]);
- if (refs[i] == refs[i-1]) {
+ if (refs[idx] == refs[idx-1]) {
/* same reference, added more than once */
identical++;
- } else if (refs[i]->clazz == refs[i-1]->clazz &&
- (int) dvmObjectSizeInHeap(refs[i]) == size)
+ } else if (refs[idx]->clazz == refs[idx-1]->clazz &&
+ dvmObjectSizeInHeap(refs[idx]) == size)
{
/* same class / size, different object */
total += size;
@@ -278,16 +301,25 @@
} else {
/* different class */
total += size;
- logObject(refs[i-1], size, identical, equiv);
+ logObject(refs[idx-1], size, identical, equiv);
equiv = identical = 0;
}
}
/* handle the last entry (everything above outputs refs[i-1]) */
- size = (refs[count-1] == NULL) ? 0 : dvmObjectSizeInHeap(refs[count-1]);
+ size = dvmObjectSizeInHeap(refs[count-1]);
total += size;
logObject(refs[count-1], size, identical, equiv);
LOGW("Memory held directly by tracked refs is %d bytes\n", total);
free(tableCopy);
}
+
+/*
+ * Dump the contents of a ReferenceTable to the log.
+ */
+void dvmDumpReferenceTable(const ReferenceTable* pRef, const char* descr)
+{
+ dvmDumpReferenceTableContents(pRef->table, dvmReferenceTableEntries(pRef),
+ descr);
+}
diff --git a/vm/ReferenceTable.h b/vm/ReferenceTable.h
index d6e2d70..f434f55 100644
--- a/vm/ReferenceTable.h
+++ b/vm/ReferenceTable.h
@@ -111,7 +111,15 @@
/*
* Dump the contents of a reference table to the log file.
+ *
+ * The caller should lock any external sync before calling.
*/
void dvmDumpReferenceTable(const ReferenceTable* pRef, const char* descr);
+/*
+ * Internal function, shared with IndirectRefTable.
+ */
+void dvmDumpReferenceTableContents(Object* const* refs, size_t count,
+ const char* descr);
+
#endif /*_DALVIK_REFERENCETABLE*/