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