1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.ahat.heapdump;
18 
19 import com.android.ahat.dominators.DominatorsComputation;
20 import java.util.List;
21 
22 /**
23  * A parsed heap dump.
24  * It contains methods to access the heaps, allocation sites, roots, classes,
25  * and instances from the parsed heap dump.
26  */
27 public class AhatSnapshot implements Diffable<AhatSnapshot> {
28   private final Site mRootSite;
29 
30   private final SuperRoot mSuperRoot;
31 
32   // List of all ahat instances.
33   private final Instances<AhatInstance> mInstances;
34 
35   private List<AhatHeap> mHeaps;
36 
37   private AhatSnapshot mBaseline = this;
38 
AhatSnapshot(SuperRoot root, Instances<AhatInstance> instances, List<AhatHeap> heaps, Site rootSite)39   AhatSnapshot(SuperRoot root,
40                Instances<AhatInstance> instances,
41                List<AhatHeap> heaps,
42                Site rootSite) {
43     mSuperRoot = root;
44     mInstances = instances;
45     mHeaps = heaps;
46     mRootSite = rootSite;
47 
48     // Update registered native allocation size.
49     for (AhatInstance cleaner : mInstances) {
50       AhatInstance.RegisteredNativeAllocation nra = cleaner.asRegisteredNativeAllocation();
51       if (nra != null) {
52         nra.referent.addRegisteredNativeSize(nra.size);
53       }
54     }
55 
56     AhatInstance.computeReverseReferences(mSuperRoot);
57     DominatorsComputation.computeDominators(mSuperRoot);
58     AhatInstance.computeRetainedSize(mSuperRoot, mHeaps.size());
59 
60     for (AhatHeap heap : mHeaps) {
61       heap.addToSize(mSuperRoot.getRetainedSize(heap));
62     }
63 
64     mRootSite.prepareForUse(0, mHeaps.size());
65   }
66 
67   /**
68    * Returns the instance with the given id in this snapshot.
69    * Where the id of an instance x is x.getId().
70    * Returns null if no instance with the given id is found.
71    *
72    * @param id the id of the instance to find
73    * @return the instance with the given id
74    */
findInstance(long id)75   public AhatInstance findInstance(long id) {
76     return mInstances.get(id);
77   }
78 
79   /**
80    * Returns the AhatClassObj with the given id in this snapshot.
81    * Where the id of a class object x is x.getId().
82    * Returns null if no class object with the given id is found.
83    *
84    * @param id the id of the class object to find
85    * @return the class object with the given id
86    */
findClassObj(long id)87   public AhatClassObj findClassObj(long id) {
88     AhatInstance inst = findInstance(id);
89     return inst == null ? null : inst.asClassObj();
90   }
91 
92   /**
93    * Returns the heap with the given name.
94    * Where the name of a heap x is x.getName().
95    * Returns null if no heap with the given name could be found.
96    *
97    * @param name the name of the heap to get
98    * @return the heap with the given name
99    */
getHeap(String name)100   public AhatHeap getHeap(String name) {
101     // We expect a small number of heaps (maybe 3 or 4 total), so a linear
102     // search should be acceptable here performance wise.
103     for (AhatHeap heap : getHeaps()) {
104       if (heap.getName().equals(name)) {
105         return heap;
106       }
107     }
108     return null;
109   }
110 
111   /**
112    * Returns a list of heaps in the snapshot in canonical order.
113    * <p>
114    * Note: modifications to the returned list are visible to this
115    * AhatSnapshot, which is used by diff to insert place holder heaps.
116    *
117    * @return list of heaps
118    */
getHeaps()119   public List<AhatHeap> getHeaps() {
120     return mHeaps;
121   }
122 
123   /**
124    * Returns a collection of "rooted" instances.
125    * An instance is "rooted" if it is a GC root, or if it is retained by more
126    * than one GC root. These are reachable instances that are not immediately
127    * dominated by any other instance in the heap.
128    *
129    * @return collection of rooted instances
130    */
getRooted()131   public List<AhatInstance> getRooted() {
132     return mSuperRoot.getDominated();
133   }
134 
135   /**
136    * Returns the root allocation site for this snapshot.
137    *
138    * @return the root allocation site
139    */
getRootSite()140   public Site getRootSite() {
141     return mRootSite;
142   }
143 
144   /**
145    * Returns the site associated with the given id.
146    * Where the id of a site x is x.getId().
147    * Returns the root site if no site with the given id is found.
148    *
149    * @param id the id of the site to get
150    * @return the site with the given id
151    */
getSite(long id)152   public Site getSite(long id) {
153     Site site = mRootSite.findSite(id);
154     return site == null ? mRootSite : site;
155   }
156 
setBaseline(AhatSnapshot baseline)157   void setBaseline(AhatSnapshot baseline) {
158     mBaseline = baseline;
159   }
160 
161   /**
162    * Returns true if this snapshot has been diffed against a different
163    * snapshot.
164    *
165    * @return true if the snapshot has been diffed
166    */
isDiffed()167   public boolean isDiffed() {
168     return mBaseline != this;
169   }
170 
getBaseline()171   @Override public AhatSnapshot getBaseline() {
172     return mBaseline;
173   }
174 
isPlaceHolder()175   @Override public boolean isPlaceHolder() {
176     return false;
177   }
178 }
179