/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.tools.perflib.heap.analysis; import com.android.tools.perflib.heap.ClassObj; import com.android.tools.perflib.heap.HprofParser; import com.android.tools.perflib.heap.Instance; import com.android.tools.perflib.heap.Snapshot; import com.android.tools.perflib.heap.io.MemoryMappedFileBuffer; import junit.framework.TestCase; import java.io.File; public class DominatorsTest extends TestCase { private Snapshot mSnapshot; public void testSimpleGraph() { mSnapshot = new SnapshotBuilder(6) .addReferences(1, 2, 3) .addReferences(2, 4, 6) .addReferences(3, 4, 5) .addReferences(4, 6) .addRoot(1) .getSnapshot(); mSnapshot.computeDominators(); assertEquals(6, mSnapshot.getReachableInstances().size()); assertDominates(1, 2); assertDominates(1, 3); assertDominates(1, 4); assertDominates(1, 6); assertDominates(3, 5); } public void testCyclicGraph() { mSnapshot = new SnapshotBuilder(4) .addReferences(1, 2, 3, 4) .addReferences(2, 3) .addReferences(3, 4) .addReferences(4, 2) .addRoot(1) .getSnapshot(); mSnapshot.computeDominators(); assertEquals(4, mSnapshot.getReachableInstances().size()); assertDominates(1, 2); assertDominates(1, 3); assertDominates(1, 4); } public void testMultipleRoots() { mSnapshot = new SnapshotBuilder(6) .addReferences(1, 3) .addReferences(2, 4) .addReferences(3, 5) .addReferences(4, 5) .addReferences(5, 6) .addRoot(1) .addRoot(2) .getSnapshot(); mSnapshot.computeDominators(); assertEquals(6, mSnapshot.getReachableInstances().size()); assertDominates(1, 3); assertDominates(2, 4); // Node 5 is reachable via both roots, neither of which can be the sole dominator. assertEquals(mSnapshot.SENTINEL_ROOT, mSnapshot.findReference(5).getImmediateDominator()); assertDominates(5, 6); } public void testDoublyLinkedList() { // Node 1 points to a doubly-linked list 2-3-4-5-6-7-8-9. mSnapshot = new SnapshotBuilder(9) .addReferences(1, 2) .addReferences(2, 3, 9) .addReferences(3, 2, 4) .addReferences(4, 3, 5) .addReferences(5, 4, 6) .addReferences(6, 5, 7) .addReferences(7, 6, 8) .addReferences(8, 7, 9) .addReferences(9, 2, 8) .addRoot(1) .getSnapshot(); mSnapshot.computeDominators(); assertEquals(45, mSnapshot.findReference(1).getRetainedSize(1)); assertEquals(44, mSnapshot.findReference(2).getRetainedSize(1)); for (int i = 3; i <= 9; i++) { assertEquals(i, mSnapshot.findReference(i).getRetainedSize(1)); } } public void testSampleHprof() throws Exception { File file = new File(ClassLoader.getSystemResource("dialer.android-hprof").getFile()); mSnapshot = (new HprofParser(new MemoryMappedFileBuffer(file))).parse(); mSnapshot.computeDominators(); // TODO: Double-check this data assertEquals(29597, mSnapshot.getReachableInstances().size()); // An object reachable via two GC roots, a JNI global and a Thread. Instance instance = mSnapshot.findReference(0xB0EDFFA0); assertEquals(Snapshot.SENTINEL_ROOT, instance.getImmediateDominator()); int appIndex = mSnapshot.getHeapIndex(mSnapshot.getHeap("app")); int zygoteIndex = mSnapshot.getHeapIndex(mSnapshot.getHeap("zygote")); // The largest object in our sample hprof belongs to the zygote ClassObj htmlParser = mSnapshot.findClass("android.text.Html$HtmlParser"); assertEquals(116468, htmlParser.getRetainedSize(zygoteIndex)); assertEquals(0, htmlParser.getRetainedSize(appIndex)); // One of the bigger objects in the app heap ClassObj activityThread = mSnapshot.findClass("android.app.ActivityThread"); assertEquals(237, activityThread.getRetainedSize(zygoteIndex)); assertEquals(576, activityThread.getRetainedSize(appIndex)); } /** * Asserts that nodeA dominates nodeB in mHeap. */ private void assertDominates(int nodeA, int nodeB) { assertEquals(mSnapshot.findReference(nodeA), mSnapshot.findReference(nodeB).getImmediateDominator()); } }