ahat: Show GC Root Paths.
The Dominator Path in the objects view is replaced by an augmented
Sample Path from GC Root, which includes non-dominator objects
along a sample path and field names.
Also, use blanks instead of "0" in heap tables when the size is 0.
This cleans up the pages a little, and conveniently lets us
distinguish between dominator and non-dominator objects in the Sample
Path from GC Root.
Test: m ahat-test, with new InstanceUtils.gcRootPath test added.
Bug: 27299030
Change-Id: I53d75f9dcb3157c2b5b3afc74958711536cd67b6
diff --git a/tools/ahat/test/InstanceUtilsTest.java b/tools/ahat/test/InstanceUtilsTest.java
index 59b1c90..ec77e70 100644
--- a/tools/ahat/test/InstanceUtilsTest.java
+++ b/tools/ahat/test/InstanceUtilsTest.java
@@ -16,11 +16,16 @@
package com.android.ahat;
+import com.android.tools.perflib.heap.ArrayInstance;
+import com.android.tools.perflib.heap.ClassObj;
import com.android.tools.perflib.heap.Instance;
import java.io.IOException;
+import java.util.List;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class InstanceUtilsTest {
@@ -123,4 +128,55 @@
assertEquals(referent, InstanceUtils.getReferent(wref));
assertNull(InstanceUtils.getReferent(referent));
}
+
+ @Test
+ public void gcRootPath() throws IOException {
+ TestDump dump = TestDump.getTestDump();
+
+ ClassObj main = dump.getAhatSnapshot().findClass("Main");
+ ArrayInstance gcPathArray = (ArrayInstance)dump.getDumpedThing("gcPathArray");
+ Object[] values = gcPathArray.getValues();
+ Instance base = (Instance)values[2];
+ Instance left = InstanceUtils.getRefField(base, "left");
+ Instance right = InstanceUtils.getRefField(base, "right");
+ Instance target = InstanceUtils.getRefField(left, "right");
+
+ List<InstanceUtils.PathElement> path = InstanceUtils.getPathFromGcRoot(target);
+ assertEquals(6, path.size());
+
+ assertEquals(main, path.get(0).instance);
+ assertEquals(".stuff", path.get(0).field);
+ assertTrue(path.get(0).isDominator);
+
+ assertEquals(".gcPathArray", path.get(1).field);
+ assertTrue(path.get(1).isDominator);
+
+ assertEquals(gcPathArray, path.get(2).instance);
+ assertEquals("[2]", path.get(2).field);
+ assertTrue(path.get(2).isDominator);
+
+ assertEquals(base, path.get(3).instance);
+ assertTrue(path.get(3).isDominator);
+
+ // There are two possible paths. Either it can go through the 'left' node,
+ // or the 'right' node.
+ if (path.get(3).field.equals(".left")) {
+ assertEquals(".left", path.get(3).field);
+
+ assertEquals(left, path.get(4).instance);
+ assertEquals(".right", path.get(4).field);
+ assertFalse(path.get(4).isDominator);
+
+ } else {
+ assertEquals(".right", path.get(3).field);
+
+ assertEquals(right, path.get(4).instance);
+ assertEquals(".left", path.get(4).field);
+ assertFalse(path.get(4).isDominator);
+ }
+
+ assertEquals(target, path.get(5).instance);
+ assertEquals("", path.get(5).field);
+ assertTrue(path.get(5).isDominator);
+ }
}