summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Richard Uhler <ruhler@google.com> 2017-09-13 17:18:37 +0100
committer Richard Uhler <ruhler@google.com> 2017-09-21 11:19:06 +0100
commit72f0ec717ce1ee13108d65af83fc99f8e507d75d (patch)
tree407ba10312a3381c5e5033f11803937a3850ab69
parent67246e9693e8fdb3b9edd101242e54586ed3fd5a (diff)
ahat: Expand test coverage using static heap dumps.
A limitation of the existing ahat test framework was that it was only easy to test heap dumps generated as part of building the ahat tests. This change adds static heap dumps from previous versions of Android to test issues that were specific to previous versions or that are easier to test with a hard-coded heap dump file. The test heap dumps are now stored as resources in ahat-test.jar rather than being passed to ahat-test.jar using system properties. Fixes a couple of minor bugs encountered when expanding tests. There are currently two failing tests: 1. Thread roots are not properly marked. 2. Root records not in the default heap are not properly marked. Test: m ahat-test, from clean build, with new tests added. Bug: 65356532 Change-Id: I3fa77e2e75d535a1dd68a763c7c45913a9e4074d
-rw-r--r--tools/ahat/Android.mk47
-rw-r--r--tools/ahat/src/heapdump/AhatClassInstance.java2
-rw-r--r--tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java4
-rw-r--r--tools/ahat/test-dump/L.hprofbin0 -> 11930828 bytes
-rw-r--r--tools/ahat/test-dump/O.hprofbin0 -> 5921872 bytes
-rw-r--r--tools/ahat/test-dump/README.txt5
-rw-r--r--tools/ahat/test-dump/RI.hprofbin0 -> 1819716 bytes
-rw-r--r--tools/ahat/test/DiffTest.java7
-rw-r--r--tools/ahat/test/InstanceTest.java113
-rw-r--r--tools/ahat/test/TestDump.java151
10 files changed, 208 insertions, 121 deletions
diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk
index 2ce61cf048..1d869af2ca 100644
--- a/tools/ahat/Android.mk
+++ b/tools/ahat/Android.mk
@@ -24,7 +24,6 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JAR_MANIFEST := src/manifest.txt
LOCAL_JAVA_RESOURCE_FILES := \
$(LOCAL_PATH)/src/style.css
-
LOCAL_STATIC_JAVA_LIBRARIES := perflib-prebuilt guavalib trove-prebuilt
LOCAL_IS_HOST_MODULE := true
LOCAL_MODULE_TAGS := optional
@@ -43,17 +42,6 @@ LOCAL_MODULE := ahat
LOCAL_SRC_FILES := ahat
include $(BUILD_PREBUILT)
-# --- ahat-tests.jar --------------
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, test)
-LOCAL_JAR_MANIFEST := test/manifest.txt
-LOCAL_STATIC_JAVA_LIBRARIES := ahat junit-host
-LOCAL_IS_HOST_MODULE := true
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE := ahat-tests
-include $(BUILD_HOST_JAVA_LIBRARY)
-AHAT_TEST_JAR := $(LOCAL_BUILT_MODULE)
-
# --- ahat-test-dump.jar --------------
include $(CLEAR_VARS)
LOCAL_MODULE := ahat-test-dump
@@ -69,7 +57,13 @@ include $(BUILD_JAVA_LIBRARY)
AHAT_TEST_DUMP_JAR := $(LOCAL_BUILT_MODULE)
AHAT_TEST_DUMP_HPROF := $(intermediates.COMMON)/test-dump.hprof
AHAT_TEST_DUMP_BASE_HPROF := $(intermediates.COMMON)/test-dump-base.hprof
-AHAT_TEST_DUMP_PROGUARD_MAP := $(proguard_dictionary)
+AHAT_TEST_DUMP_PROGUARD_MAP := $(intermediates.COMMON)/test-dump.map
+
+# Generate the proguard map in the desired location by copying it from
+# wherever the build system generates it by default.
+$(AHAT_TEST_DUMP_PROGUARD_MAP): PRIVATE_AHAT_SOURCE_PROGUARD_MAP := $(proguard_dictionary)
+$(AHAT_TEST_DUMP_PROGUARD_MAP): $(proguard_dictionary)
+ cp $(PRIVATE_AHAT_SOURCE_PROGUARD_MAP) $@
# Run ahat-test-dump.jar to generate test-dump.hprof and test-dump-base.hprof
AHAT_TEST_DUMP_DEPENDENCIES := \
@@ -80,23 +74,36 @@ AHAT_TEST_DUMP_DEPENDENCIES := \
$(AHAT_TEST_DUMP_HPROF): PRIVATE_AHAT_TEST_ART := $(HOST_OUT_EXECUTABLES)/art
$(AHAT_TEST_DUMP_HPROF): PRIVATE_AHAT_TEST_DUMP_JAR := $(AHAT_TEST_DUMP_JAR)
-$(AHAT_TEST_DUMP_HPROF): PRIVATE_AHAT_TEST_DUMP_DEPENDENCIES := $(AHAT_TEST_DUMP_DEPENDENCIES)
$(AHAT_TEST_DUMP_HPROF): $(AHAT_TEST_DUMP_JAR) $(AHAT_TEST_DUMP_DEPENDENCIES)
$(PRIVATE_AHAT_TEST_ART) -cp $(PRIVATE_AHAT_TEST_DUMP_JAR) Main $@
$(AHAT_TEST_DUMP_BASE_HPROF): PRIVATE_AHAT_TEST_ART := $(HOST_OUT_EXECUTABLES)/art
$(AHAT_TEST_DUMP_BASE_HPROF): PRIVATE_AHAT_TEST_DUMP_JAR := $(AHAT_TEST_DUMP_JAR)
-$(AHAT_TEST_DUMP_BASE_HPROF): PRIVATE_AHAT_TEST_DUMP_DEPENDENCIES := $(AHAT_TEST_DUMP_DEPENDENCIES)
$(AHAT_TEST_DUMP_BASE_HPROF): $(AHAT_TEST_DUMP_JAR) $(AHAT_TEST_DUMP_DEPENDENCIES)
$(PRIVATE_AHAT_TEST_ART) -cp $(PRIVATE_AHAT_TEST_DUMP_JAR) Main $@ --base
+# --- ahat-tests.jar --------------
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-java-files-under, test)
+LOCAL_JAR_MANIFEST := test/manifest.txt
+LOCAL_JAVA_RESOURCE_FILES := \
+ $(AHAT_TEST_DUMP_HPROF) \
+ $(AHAT_TEST_DUMP_BASE_HPROF) \
+ $(AHAT_TEST_DUMP_PROGUARD_MAP) \
+ $(LOCAL_PATH)/test-dump/L.hprof \
+ $(LOCAL_PATH)/test-dump/O.hprof \
+ $(LOCAL_PATH)/test-dump/RI.hprof
+LOCAL_STATIC_JAVA_LIBRARIES := ahat junit-host
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := ahat-tests
+include $(BUILD_HOST_JAVA_LIBRARY)
+AHAT_TEST_JAR := $(LOCAL_BUILT_MODULE)
+
.PHONY: ahat-test
-ahat-test: PRIVATE_AHAT_TEST_DUMP_HPROF := $(AHAT_TEST_DUMP_HPROF)
-ahat-test: PRIVATE_AHAT_TEST_DUMP_BASE_HPROF := $(AHAT_TEST_DUMP_BASE_HPROF)
ahat-test: PRIVATE_AHAT_TEST_JAR := $(AHAT_TEST_JAR)
-ahat-test: PRIVATE_AHAT_PROGUARD_MAP := $(AHAT_TEST_DUMP_PROGUARD_MAP)
-ahat-test: $(AHAT_TEST_JAR) $(AHAT_TEST_DUMP_HPROF) $(AHAT_TEST_DUMP_BASE_HPROF)
- java -enableassertions -Dahat.test.dump.hprof=$(PRIVATE_AHAT_TEST_DUMP_HPROF) -Dahat.test.dump.base.hprof=$(PRIVATE_AHAT_TEST_DUMP_BASE_HPROF) -Dahat.test.dump.map=$(PRIVATE_AHAT_PROGUARD_MAP) -jar $(PRIVATE_AHAT_TEST_JAR)
+ahat-test: $(AHAT_TEST_JAR)
+ java -enableassertions -jar $(PRIVATE_AHAT_TEST_JAR)
# Clean up local variables.
AHAT_TEST_JAR :=
diff --git a/tools/ahat/src/heapdump/AhatClassInstance.java b/tools/ahat/src/heapdump/AhatClassInstance.java
index f7d8431a7b..a2f61ca273 100644
--- a/tools/ahat/src/heapdump/AhatClassInstance.java
+++ b/tools/ahat/src/heapdump/AhatClassInstance.java
@@ -123,7 +123,7 @@ public class AhatClassInstance extends AhatInstance {
}
Value value = getField("value");
- if (!value.isAhatInstance()) {
+ if (value == null || !value.isAhatInstance()) {
return null;
}
diff --git a/tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java b/tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java
index 8b4c6796aa..d7f94dc687 100644
--- a/tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java
+++ b/tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java
@@ -29,6 +29,10 @@ public class AhatPlaceHolderClassObj extends AhatClassObj {
baseline.setBaseline(this);
}
+ @Override public Size getSize() {
+ return Size.ZERO;
+ }
+
@Override public Size getRetainedSize(AhatHeap heap) {
return Size.ZERO;
}
diff --git a/tools/ahat/test-dump/L.hprof b/tools/ahat/test-dump/L.hprof
new file mode 100644
index 0000000000..cf82557d6d
--- /dev/null
+++ b/tools/ahat/test-dump/L.hprof
Binary files differ
diff --git a/tools/ahat/test-dump/O.hprof b/tools/ahat/test-dump/O.hprof
new file mode 100644
index 0000000000..d474c6c6b4
--- /dev/null
+++ b/tools/ahat/test-dump/O.hprof
Binary files differ
diff --git a/tools/ahat/test-dump/README.txt b/tools/ahat/test-dump/README.txt
new file mode 100644
index 0000000000..344271c2f4
--- /dev/null
+++ b/tools/ahat/test-dump/README.txt
@@ -0,0 +1,5 @@
+
+Main.java - A program used to generate a heap dump used for tests.
+L.hprof - A version of the test dump generated on Android L.
+O.hprof - A version of the test dump generated on Android O.
+RI.hprof - A version of the test dump generated on the reference implementation.
diff --git a/tools/ahat/test-dump/RI.hprof b/tools/ahat/test-dump/RI.hprof
new file mode 100644
index 0000000000..9482542a7f
--- /dev/null
+++ b/tools/ahat/test-dump/RI.hprof
Binary files differ
diff --git a/tools/ahat/test/DiffTest.java b/tools/ahat/test/DiffTest.java
index d0349fd178..cfd0236ab3 100644
--- a/tools/ahat/test/DiffTest.java
+++ b/tools/ahat/test/DiffTest.java
@@ -93,6 +93,13 @@ public class DiffTest {
}
@Test
+ public void diffClassRemoved() throws IOException {
+ TestDump dump = TestDump.getTestDump("O.hprof", "L.hprof", null);
+ AhatHandler handler = new ObjectsHandler(dump.getAhatSnapshot());
+ TestHandler.testNoCrash(handler, "http://localhost:7100/objects?class=java.lang.Class");
+ }
+
+ @Test
public void nullClassObj() throws IOException {
// Set up a heap dump that has a null classObj.
// The heap dump is derived from the InstanceTest.asStringEmbedded test.
diff --git a/tools/ahat/test/InstanceTest.java b/tools/ahat/test/InstanceTest.java
index 63055db93d..49a21e2d70 100644
--- a/tools/ahat/test/InstanceTest.java
+++ b/tools/ahat/test/InstanceTest.java
@@ -23,23 +23,7 @@ import com.android.ahat.heapdump.AhatSnapshot;
import com.android.ahat.heapdump.PathElement;
import com.android.ahat.heapdump.Size;
import com.android.ahat.heapdump.Value;
-import com.android.tools.perflib.heap.hprof.HprofClassDump;
-import com.android.tools.perflib.heap.hprof.HprofConstant;
-import com.android.tools.perflib.heap.hprof.HprofDumpRecord;
-import com.android.tools.perflib.heap.hprof.HprofHeapDump;
-import com.android.tools.perflib.heap.hprof.HprofInstanceDump;
-import com.android.tools.perflib.heap.hprof.HprofInstanceField;
-import com.android.tools.perflib.heap.hprof.HprofLoadClass;
-import com.android.tools.perflib.heap.hprof.HprofPrimitiveArrayDump;
-import com.android.tools.perflib.heap.hprof.HprofRecord;
-import com.android.tools.perflib.heap.hprof.HprofRootDebugger;
-import com.android.tools.perflib.heap.hprof.HprofStaticField;
-import com.android.tools.perflib.heap.hprof.HprofStringBuilder;
-import com.android.tools.perflib.heap.hprof.HprofType;
-import com.google.common.io.ByteArrayDataOutput;
-import com.google.common.io.ByteStreams;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
@@ -395,44 +379,63 @@ public class InstanceTest {
@Test
public void asStringEmbedded() throws IOException {
- // Set up a heap dump with an instance of java.lang.String of
- // "hello" with instance id 0x42 that is backed by a char array that is
- // bigger. This is how ART used to represent strings, and we should still
- // support it in case the heap dump is from a previous platform version.
- HprofStringBuilder strings = new HprofStringBuilder(0);
- List<HprofRecord> records = new ArrayList<HprofRecord>();
- List<HprofDumpRecord> dump = new ArrayList<HprofDumpRecord>();
-
- final int stringClassObjectId = 1;
- records.add(new HprofLoadClass(0, 0, stringClassObjectId, 0, strings.get("java.lang.String")));
- dump.add(new HprofClassDump(stringClassObjectId, 0, 0, 0, 0, 0, 0, 0, 0,
- new HprofConstant[0], new HprofStaticField[0],
- new HprofInstanceField[]{
- new HprofInstanceField(strings.get("count"), HprofType.TYPE_INT),
- new HprofInstanceField(strings.get("hashCode"), HprofType.TYPE_INT),
- new HprofInstanceField(strings.get("offset"), HprofType.TYPE_INT),
- new HprofInstanceField(strings.get("value"), HprofType.TYPE_OBJECT)}));
-
- dump.add(new HprofPrimitiveArrayDump(0x41, 0, HprofType.TYPE_CHAR,
- new long[]{'n', 'o', 't', ' ', 'h', 'e', 'l', 'l', 'o', 'o', 'p'}));
-
- ByteArrayDataOutput values = ByteStreams.newDataOutput();
- values.writeInt(5); // count
- values.writeInt(0); // hashCode
- values.writeInt(4); // offset
- values.writeInt(0x41); // value
- dump.add(new HprofInstanceDump(0x42, 0, stringClassObjectId, values.toByteArray()));
- dump.add(new HprofRootDebugger(stringClassObjectId));
- dump.add(new HprofRootDebugger(0x42));
-
- records.add(new HprofHeapDump(0, dump.toArray(new HprofDumpRecord[0])));
- AhatSnapshot snapshot = SnapshotBuilder.makeSnapshot(strings, records);
- AhatInstance chars = snapshot.findInstance(0x41);
- assertNotNull(chars);
- assertEquals("not helloop", chars.asString());
-
- AhatInstance stringInstance = snapshot.findInstance(0x42);
- assertNotNull(stringInstance);
- assertEquals("hello", stringInstance.asString());
+ // On Android L, image strings were backed by a single big char array.
+ // Verify we show just the relative part of the string, not the entire
+ // char array.
+ TestDump dump = TestDump.getTestDump("L.hprof", null, null);
+ AhatSnapshot snapshot = dump.getAhatSnapshot();
+
+ // java.lang.String@0x6fe17050 is an image string "char" backed by a
+ // shared char array.
+ AhatInstance str = snapshot.findInstance(0x6fe17050);
+ assertEquals("char", str.asString());
+ }
+
+ @Test
+ public void nonDefaultHeapRoot() throws IOException {
+ TestDump dump = TestDump.getTestDump("O.hprof", null, null);
+ AhatSnapshot snapshot = dump.getAhatSnapshot();
+
+ // java.util.HashMap@6004fdb8 is marked as a VM INTERNAL root.
+ // Previously we had a bug where roots not on the default heap were not
+ // properly treated as roots (b/65356532).
+ AhatInstance map = snapshot.findInstance(0x6004fdb8);
+ assertEquals("java.util.HashMap", map.getClassName());
+ assertTrue(map.isRoot());
+ }
+
+ @Test
+ public void threadRoot() throws IOException {
+ TestDump dump = TestDump.getTestDump("O.hprof", null, null);
+ AhatSnapshot snapshot = dump.getAhatSnapshot();
+
+ // java.lang.Thread@12c03470 is marked as a thread root.
+ // Previously we had a bug where thread roots were not properly treated as
+ // roots (b/65356532).
+ AhatInstance thread = snapshot.findInstance(0x12c03470);
+ assertEquals("java.lang.Thread", thread.getClassName());
+ assertTrue(thread.isRoot());
+ }
+
+ @Test
+ public void classOfClass() throws IOException {
+ TestDump dump = TestDump.getTestDump();
+ AhatInstance obj = dump.getDumpedAhatInstance("anObject");
+ AhatClassObj cls = obj.getClassObj();
+ AhatClassObj clscls = cls.getClassObj();
+ assertNotNull(clscls);
+ assertEquals("java.lang.Class", clscls.getName());
+ }
+
+ @Test
+ public void nullValueString() throws IOException {
+ TestDump dump = TestDump.getTestDump("RI.hprof", null, null);
+ AhatSnapshot snapshot = dump.getAhatSnapshot();
+
+ // java.lang.String@500001a8 has a null 'value' field, which should not
+ // cause ahat to crash.
+ AhatInstance str = snapshot.findInstance(0x500001a8);
+ assertEquals("java.lang.String", str.getClassName());
+ assertNull(str.asString());
}
}
diff --git a/tools/ahat/test/TestDump.java b/tools/ahat/test/TestDump.java
index db9b25646a..d1afe43132 100644
--- a/tools/ahat/test/TestDump.java
+++ b/tools/ahat/test/TestDump.java
@@ -23,73 +23,114 @@ import com.android.ahat.heapdump.Diff;
import com.android.ahat.heapdump.FieldValue;
import com.android.ahat.heapdump.Site;
import com.android.ahat.heapdump.Value;
+import com.android.tools.perflib.captures.DataBuffer;
import com.android.tools.perflib.heap.ProguardMap;
-import java.io.File;
+import com.android.tools.perflib.heap.io.InMemoryBuffer;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
/**
- * The TestDump class is used to get an AhatSnapshot for the test-dump
- * program.
+ * The TestDump class is used to get the current and baseline AhatSnapshots
+ * for heap dumps generated by the test-dump program that are stored as
+ * resources in this jar file.
*/
public class TestDump {
- // It can take on the order of a second to parse and process the test-dump
- // hprof. To avoid repeating this overhead for each test case, we cache the
- // loaded instance of TestDump and reuse it when possible. In theory the
- // test cases should not be able to modify the cached snapshot in a way that
- // is visible to other test cases.
- private static TestDump mCachedTestDump = null;
+ // It can take on the order of a second to parse and process test dumps.
+ // To avoid repeating this overhead for each test case, we provide a way to
+ // cache loaded instance of TestDump and reuse it when possible. In theory
+ // the test cases should not be able to modify the cached snapshot in a way
+ // that is visible to other test cases.
+ private static List<TestDump> mCachedTestDumps = new ArrayList<TestDump>();
+
+ // The name of the resources this test dump is loaded from.
+ private String mHprofResource;
+ private String mHprofBaseResource;
+ private String mMapResource;
// If the test dump fails to load the first time, it will likely fail every
// other test we try. Rather than having to wait a potentially very long
// time for test dump loading to fail over and over again, record when it
// fails and don't try to load it again.
- private static boolean mTestDumpFailed = false;
+ private boolean mTestDumpFailed = true;
+ // The loaded heap dumps.
private AhatSnapshot mSnapshot;
private AhatSnapshot mBaseline;
+
+ // Cached reference to the 'Main' class object in the snapshot and baseline
+ // heap dumps.
private AhatClassObj mMain;
private AhatClassObj mBaselineMain;
/**
- * Load the test-dump.hprof and test-dump-base.hprof files.
- * The location of the files are read from the system properties
- * "ahat.test.dump.hprof" and "ahat.test.dump.base.hprof", which is expected
- * to be set on the command line.
- * The location of the proguard map for both hprof files is read from the
- * system property "ahat.test.dump.map". For example:
- * java -Dahat.test.dump.hprof=test-dump.hprof \
- * -Dahat.test.dump.base.hprof=test-dump-base.hprof \
- * -Dahat.test.dump.map=proguard.map \
- * -jar ahat-tests.jar
+ * Read the named resource into a DataBuffer.
+ */
+ private static DataBuffer dataBufferFromResource(String name) throws IOException {
+ ClassLoader loader = TestDump.class.getClassLoader();
+ InputStream is = loader.getResourceAsStream(name);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buf = new byte[4096];
+ int read;
+ while ((read = is.read(buf)) != -1) {
+ baos.write(buf, 0, read);
+ }
+ return new InMemoryBuffer(baos.toByteArray());
+ }
+
+ /**
+ * Create a TestDump instance.
+ * The load() method should be called to load and process the heap dumps.
+ * The files are specified as names of resources compiled into the jar file.
+ * The baseline resouce may be null to indicate that no diffing should be
+ * performed.
+ * The map resource may be null to indicate no proguard map will be used.
*
+ */
+ private TestDump(String hprofResource, String hprofBaseResource, String mapResource) {
+ mHprofResource = hprofResource;
+ mHprofBaseResource = hprofBaseResource;
+ mMapResource = mapResource;
+ }
+
+ /**
+ * Load the heap dumps for this TestDump.
* An IOException is thrown if there is a failure reading the hprof files or
* the proguard map.
*/
- private TestDump() throws IOException {
- // TODO: Make use of the baseline hprof for tests.
- String hprof = System.getProperty("ahat.test.dump.hprof");
- String hprofBase = System.getProperty("ahat.test.dump.base.hprof");
-
- String mapfile = System.getProperty("ahat.test.dump.map");
+ private void load() throws IOException {
ProguardMap map = new ProguardMap();
- try {
- map.readFromFile(new File(mapfile));
- } catch (ParseException e) {
- throw new IOException("Unable to load proguard map", e);
+ if (mMapResource != null) {
+ try {
+ ClassLoader loader = TestDump.class.getClassLoader();
+ InputStream is = loader.getResourceAsStream(mMapResource);
+ map.readFromReader(new InputStreamReader(is));
+ } catch (ParseException e) {
+ throw new IOException("Unable to load proguard map", e);
+ }
}
- mSnapshot = AhatSnapshot.fromHprof(new File(hprof), map);
- mBaseline = AhatSnapshot.fromHprof(new File(hprofBase), map);
- Diff.snapshots(mSnapshot, mBaseline);
-
+ DataBuffer hprof = dataBufferFromResource(mHprofResource);
+ mSnapshot = AhatSnapshot.fromDataBuffer(hprof, map);
mMain = findClass(mSnapshot, "Main");
assert(mMain != null);
- mBaselineMain = findClass(mBaseline, "Main");
- assert(mBaselineMain != null);
+ if (mHprofBaseResource != null) {
+ DataBuffer hprofBase = dataBufferFromResource(mHprofBaseResource);
+ mBaseline = AhatSnapshot.fromDataBuffer(hprofBase, map);
+ mBaselineMain = findClass(mBaseline, "Main");
+ assert(mBaselineMain != null);
+
+ Diff.snapshots(mSnapshot, mBaseline);
+ }
+
+ mTestDumpFailed = false;
}
/**
@@ -182,22 +223,42 @@ public class TestDump {
}
/**
- * Get the test dump.
+ * Get the default (cached) test dump.
* An IOException is thrown if there is an error reading the test dump hprof
* file.
* To improve performance, this returns a cached instance of the TestDump
* when possible.
*/
public static synchronized TestDump getTestDump() throws IOException {
- if (mTestDumpFailed) {
- throw new RuntimeException("Test dump failed before, assuming it will again");
- }
+ return getTestDump("test-dump.hprof", "test-dump-base.hprof", "test-dump.map");
+ }
- if (mCachedTestDump == null) {
- mTestDumpFailed = true;
- mCachedTestDump = new TestDump();
- mTestDumpFailed = false;
+ /**
+ * Get a (cached) test dump.
+ * @param hprof - The string resouce name of the hprof file.
+ * @param base - The string resouce name of the baseline hprof, may be null.
+ * @param map - The string resouce name of the proguard map, may be null.
+ * An IOException is thrown if there is an error reading the test dump hprof
+ * file.
+ * To improve performance, this returns a cached instance of the TestDump
+ * when possible.
+ */
+ public static synchronized TestDump getTestDump(String hprof, String base, String map)
+ throws IOException {
+ for (TestDump loaded : mCachedTestDumps) {
+ if (Objects.equals(loaded.mHprofResource, hprof)
+ && Objects.equals(loaded.mHprofBaseResource, base)
+ && Objects.equals(loaded.mMapResource, map)) {
+ if (loaded.mTestDumpFailed) {
+ throw new IOException("Test dump failed before, assuming it will again");
+ }
+ return loaded;
+ }
}
- return mCachedTestDump;
+
+ TestDump dump = new TestDump(hprof, base, map);
+ mCachedTestDumps.add(dump);
+ dump.load();
+ return dump;
}
}