• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.tools.perflib.heap.StackFrame;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 
26 public class Site implements Diffable<Site> {
27   // The site that this site was directly called from.
28   // mParent is null for the root site.
29   private Site mParent;
30 
31   private String mMethodName;
32   private String mSignature;
33   private String mFilename;
34   private int mLineNumber;
35 
36   // To identify this site, we pick a stack trace that includes the site.
37   // mId is the id of an object allocated at that stack trace, and mDepth
38   // is the number of calls between this site and the innermost site of
39   // allocation of the object with mId.
40   // For the root site, mId is 0 and mDepth is 0.
41   private long mId;
42   private int mDepth;
43 
44   // The total size of objects allocated in this site (including child sites),
45   // organized by heap index. Heap indices outside the range of mSizesByHeap
46   // implicitly have size 0.
47   private long[] mSizesByHeap;
48 
49   // List of child sites.
50   private List<Site> mChildren;
51 
52   // List of all objects allocated in this site (including child sites).
53   private List<AhatInstance> mObjects;
54   private List<ObjectsInfo> mObjectsInfos;
55   private Map<AhatHeap, Map<AhatClassObj, ObjectsInfo>> mObjectsInfoMap;
56 
57   private Site mBaseline;
58 
59   public static class ObjectsInfo implements Diffable<ObjectsInfo> {
60     public AhatHeap heap;
61     public AhatClassObj classObj;   // May be null.
62     public long numInstances;
63     public long numBytes;
64     private ObjectsInfo baseline;
65 
ObjectsInfo(AhatHeap heap, AhatClassObj classObj, long numInstances, long numBytes)66     public ObjectsInfo(AhatHeap heap, AhatClassObj classObj, long numInstances, long numBytes) {
67       this.heap = heap;
68       this.classObj = classObj;
69       this.numInstances = numInstances;
70       this.numBytes = numBytes;
71       this.baseline = this;
72     }
73 
74     /**
75      * Returns the name of the class this ObjectsInfo is associated with.
76      */
getClassName()77     public String getClassName() {
78       return classObj == null ? "???" : classObj.getName();
79     }
80 
setBaseline(ObjectsInfo baseline)81     public void setBaseline(ObjectsInfo baseline) {
82       this.baseline = baseline;
83     }
84 
getBaseline()85     @Override public ObjectsInfo getBaseline() {
86       return baseline;
87     }
88 
isPlaceHolder()89     @Override public boolean isPlaceHolder() {
90       return false;
91     }
92   }
93 
94   /**
95    * Construct a root site.
96    */
Site(String name)97   public Site(String name) {
98     this(null, name, "", "", 0, 0, 0);
99   }
100 
Site(Site parent, String method, String signature, String file, int line, long id, int depth)101   public Site(Site parent, String method, String signature, String file,
102       int line, long id, int depth) {
103     mParent = parent;
104     mMethodName = method;
105     mSignature = signature;
106     mFilename = file;
107     mLineNumber = line;
108     mId = id;
109     mDepth = depth;
110     mSizesByHeap = new long[1];
111     mChildren = new ArrayList<Site>();
112     mObjects = new ArrayList<AhatInstance>();
113     mObjectsInfos = new ArrayList<ObjectsInfo>();
114     mObjectsInfoMap = new HashMap<AhatHeap, Map<AhatClassObj, ObjectsInfo>>();
115     mBaseline = this;
116   }
117 
118   /**
119    * Add an instance to this site.
120    * Returns the site at which the instance was allocated.
121    * @param frames - The list of frames in the stack trace, starting with the inner-most frame.
122    * @param depth - The number of frames remaining before the inner-most frame is reached.
123    */
add(StackFrame[] frames, int depth, AhatInstance inst)124   Site add(StackFrame[] frames, int depth, AhatInstance inst) {
125     return add(this, frames, depth, inst);
126   }
127 
add(Site site, StackFrame[] frames, int depth, AhatInstance inst)128   private static Site add(Site site, StackFrame[] frames, int depth, AhatInstance inst) {
129     while (true) {
130       site.mObjects.add(inst);
131 
132       ObjectsInfo info = site.getObjectsInfo(inst.getHeap(), inst.getClassObj());
133       if (inst.isReachable()) {
134         AhatHeap heap = inst.getHeap();
135         if (heap.getIndex() >= site.mSizesByHeap.length) {
136           long[] newSizes = new long[heap.getIndex() + 1];
137           for (int i = 0; i < site.mSizesByHeap.length; i++) {
138             newSizes[i] = site.mSizesByHeap[i];
139           }
140           site.mSizesByHeap = newSizes;
141         }
142         site.mSizesByHeap[heap.getIndex()] += inst.getSize();
143 
144         info.numInstances++;
145         info.numBytes += inst.getSize();
146       }
147 
148       if (depth > 0) {
149         StackFrame next = frames[depth - 1];
150         Site child = null;
151         for (int i = 0; i < site.mChildren.size(); i++) {
152           Site curr = site.mChildren.get(i);
153           if (curr.mLineNumber == next.getLineNumber()
154               && curr.mMethodName.equals(next.getMethodName())
155               && curr.mSignature.equals(next.getSignature())
156               && curr.mFilename.equals(next.getFilename())) {
157             child = curr;
158             break;
159           }
160         }
161         if (child == null) {
162           child = new Site(site, next.getMethodName(), next.getSignature(),
163               next.getFilename(), next.getLineNumber(), inst.getId(), depth - 1);
164           site.mChildren.add(child);
165         }
166         depth = depth - 1;
167         site = child;
168       } else {
169         return site;
170       }
171     }
172   }
173 
174   // Get the size of a site for a specific heap.
getSize(AhatHeap heap)175   public long getSize(AhatHeap heap) {
176     int index = heap.getIndex();
177     return index >= 0 && index < mSizesByHeap.length ? mSizesByHeap[index] : 0;
178   }
179 
180   /**
181    * Get the list of objects allocated under this site. Includes objects
182    * allocated in children sites.
183    */
getObjects()184   public Collection<AhatInstance> getObjects() {
185     return mObjects;
186   }
187 
188   /**
189    * Returns the ObjectsInfo at this site for the given heap and class
190    * objects. Creates a new empty ObjectsInfo if none existed before.
191    */
getObjectsInfo(AhatHeap heap, AhatClassObj classObj)192   ObjectsInfo getObjectsInfo(AhatHeap heap, AhatClassObj classObj) {
193     Map<AhatClassObj, ObjectsInfo> classToObjectsInfo = mObjectsInfoMap.get(heap);
194     if (classToObjectsInfo == null) {
195       classToObjectsInfo = new HashMap<AhatClassObj, ObjectsInfo>();
196       mObjectsInfoMap.put(heap, classToObjectsInfo);
197     }
198 
199     ObjectsInfo info = classToObjectsInfo.get(classObj);
200     if (info == null) {
201       info = new ObjectsInfo(heap, classObj, 0, 0);
202       mObjectsInfos.add(info);
203       classToObjectsInfo.put(classObj, info);
204     }
205     return info;
206   }
207 
getObjectsInfos()208   public List<ObjectsInfo> getObjectsInfos() {
209     return mObjectsInfos;
210   }
211 
212   // Get the combined size of the site for all heaps.
getTotalSize()213   public long getTotalSize() {
214     long total = 0;
215     for (int i = 0; i < mSizesByHeap.length; i++) {
216       total += mSizesByHeap[i];
217     }
218     return total;
219   }
220 
221   /**
222    * Return the site this site was called from.
223    * Returns null for the root site.
224    */
getParent()225   public Site getParent() {
226     return mParent;
227   }
228 
getMethodName()229   public String getMethodName() {
230     return mMethodName;
231   }
232 
getSignature()233   public String getSignature() {
234     return mSignature;
235   }
236 
getFilename()237   public String getFilename() {
238     return mFilename;
239   }
240 
getLineNumber()241   public int getLineNumber() {
242     return mLineNumber;
243   }
244 
245   /**
246    * Returns the id of some object allocated in this site.
247    */
getId()248   public long getId() {
249     return mId;
250   }
251 
252   /**
253    * Returns the number of frames between this site and the site where the
254    * object with id getId() was allocated.
255    */
getDepth()256   public int getDepth() {
257     return mDepth;
258   }
259 
getChildren()260   public List<Site> getChildren() {
261     return mChildren;
262   }
263 
setBaseline(Site baseline)264   void setBaseline(Site baseline) {
265     mBaseline = baseline;
266   }
267 
getBaseline()268   @Override public Site getBaseline() {
269     return mBaseline;
270   }
271 
isPlaceHolder()272   @Override public boolean isPlaceHolder() {
273     return false;
274   }
275 
276   /**
277    * Adds a place holder instance to this site and all parent sites.
278    */
addPlaceHolderInstance(AhatInstance placeholder)279   void addPlaceHolderInstance(AhatInstance placeholder) {
280     for (Site site = this; site != null; site = site.mParent) {
281       site.mObjects.add(placeholder);
282     }
283   }
284 }
285