Home | History | Annotate | Download | only in heapdump
      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