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 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 */ 77 public String getClassName() { 78 return classObj == null ? "???" : classObj.getName(); 79 } 80 81 public void setBaseline(ObjectsInfo baseline) { 82 this.baseline = baseline; 83 } 84 85 @Override public ObjectsInfo getBaseline() { 86 return baseline; 87 } 88 89 @Override public boolean isPlaceHolder() { 90 return false; 91 } 92 } 93 94 /** 95 * Construct a root site. 96 */ 97 public Site(String name) { 98 this(null, name, "", "", 0, 0, 0); 99 } 100 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 */ 124 Site add(StackFrame[] frames, int depth, AhatInstance inst) { 125 return add(this, frames, depth, inst); 126 } 127 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. 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 */ 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 */ 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 208 public List<ObjectsInfo> getObjectsInfos() { 209 return mObjectsInfos; 210 } 211 212 // Get the combined size of the site for all heaps. 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 */ 225 public Site getParent() { 226 return mParent; 227 } 228 229 public String getMethodName() { 230 return mMethodName; 231 } 232 233 public String getSignature() { 234 return mSignature; 235 } 236 237 public String getFilename() { 238 return mFilename; 239 } 240 241 public int getLineNumber() { 242 return mLineNumber; 243 } 244 245 /** 246 * Returns the id of some object allocated in this site. 247 */ 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 */ 256 public int getDepth() { 257 return mDepth; 258 } 259 260 public List<Site> getChildren() { 261 return mChildren; 262 } 263 264 void setBaseline(Site baseline) { 265 mBaseline = baseline; 266 } 267 268 @Override public Site getBaseline() { 269 return mBaseline; 270 } 271 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 */ 279 void addPlaceHolderInstance(AhatInstance placeholder) { 280 for (Site site = this; site != null; site = site.mParent) { 281 site.mObjects.add(placeholder); 282 } 283 } 284 } 285