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;
18 
19 import com.android.tools.perflib.heap.ClassObj;
20 import com.android.tools.perflib.heap.Heap;
21 import com.android.tools.perflib.heap.Instance;
22 import com.android.tools.perflib.heap.StackFrame;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 
30 class Site {
31   // The site that this site was directly called from.
32   // mParent is null for the root site.
33   private Site mParent;
34 
35   // A description of the Site. Currently this is used to uniquely identify a
36   // site within its parent.
37   private String mName;
38 
39   // To identify this site, we pick one stack trace where we have seen the
40   // site. mStackId is the id for that stack trace, and mStackDepth is the
41   // depth of this site in that stack trace.
42   // For the root site, mStackId is 0 and mStackDepth is 0.
43   private int mStackId;
44   private int mStackDepth;
45 
46   // Mapping from heap name to the total size of objects allocated in this
47   // site (including child sites) on the given heap.
48   private Map<String, Long> mSizesByHeap;
49 
50   // Mapping from child site name to child site.
51   private Map<String, Site> mChildren;
52 
53   // List of all objects allocated in this site (including child sites).
54   private List<Instance> mObjects;
55   private List<ObjectsInfo> mObjectsInfos;
56   private Map<Heap, Map<ClassObj, ObjectsInfo>> mObjectsInfoMap;
57 
58   public static class ObjectsInfo {
59     public Heap heap;
60     public ClassObj classObj;
61     public long numInstances;
62     public long numBytes;
63 
ObjectsInfo(Heap heap, ClassObj classObj, long numInstances, long numBytes)64     public ObjectsInfo(Heap heap, ClassObj classObj, long numInstances, long numBytes) {
65       this.heap = heap;
66       this.classObj = classObj;
67       this.numInstances = numInstances;
68       this.numBytes = numBytes;
69     }
70   }
71 
72   /**
73    * Construct a root site.
74    */
Site(String name)75   public Site(String name) {
76     this(null, name, 0, 0);
77   }
78 
Site(Site parent, String name, int stackId, int stackDepth)79   public Site(Site parent, String name, int stackId, int stackDepth) {
80     mParent = parent;
81     mName = name;
82     mStackId = stackId;
83     mStackDepth = stackDepth;
84     mSizesByHeap = new HashMap<String, Long>();
85     mChildren = new HashMap<String, Site>();
86     mObjects = new ArrayList<Instance>();
87     mObjectsInfos = new ArrayList<ObjectsInfo>();
88     mObjectsInfoMap = new HashMap<Heap, Map<ClassObj, ObjectsInfo>>();
89   }
90 
91   /**
92    * Add an instance to this site.
93    * Returns the site at which the instance was allocated.
94    */
add(int stackId, int stackDepth, Iterator<StackFrame> path, Instance inst)95   public Site add(int stackId, int stackDepth, Iterator<StackFrame> path, Instance inst) {
96     mObjects.add(inst);
97 
98     String heap = inst.getHeap().getName();
99     mSizesByHeap.put(heap, getSize(heap) + inst.getSize());
100 
101     Map<ClassObj, ObjectsInfo> classToObjectsInfo = mObjectsInfoMap.get(inst.getHeap());
102     if (classToObjectsInfo == null) {
103       classToObjectsInfo = new HashMap<ClassObj, ObjectsInfo>();
104       mObjectsInfoMap.put(inst.getHeap(), classToObjectsInfo);
105     }
106 
107     ObjectsInfo info = classToObjectsInfo.get(inst.getClassObj());
108     if (info == null) {
109       info = new ObjectsInfo(inst.getHeap(), inst.getClassObj(), 0, 0);
110       mObjectsInfos.add(info);
111       classToObjectsInfo.put(inst.getClassObj(), info);
112     }
113 
114     info.numInstances++;
115     info.numBytes += inst.getSize();
116 
117     if (path.hasNext()) {
118       String next = path.next().toString();
119       Site child = mChildren.get(next);
120       if (child == null) {
121         child = new Site(this, next, stackId, stackDepth + 1);
122         mChildren.put(next, child);
123       }
124       return child.add(stackId, stackDepth + 1, path, inst);
125     } else {
126       return this;
127     }
128   }
129 
130   // Get the size of a site for a specific heap.
getSize(String heap)131   public long getSize(String heap) {
132     Long val = mSizesByHeap.get(heap);
133     if (val == null) {
134       return 0;
135     }
136     return val;
137   }
138 
139   /**
140    * Get the list of objects allocated under this site. Includes objects
141    * allocated in children sites.
142    */
getObjects()143   public Collection<Instance> getObjects() {
144     return mObjects;
145   }
146 
getObjectsInfos()147   public List<ObjectsInfo> getObjectsInfos() {
148     return mObjectsInfos;
149   }
150 
151   // Get the combined size of the site for all heaps.
getTotalSize()152   public long getTotalSize() {
153     long size = 0;
154     for (Long val : mSizesByHeap.values()) {
155       size += val;
156     }
157     return size;
158   }
159 
160   /**
161    * Return the site this site was called from.
162    * Returns null for the root site.
163    */
getParent()164   public Site getParent() {
165     return mParent;
166   }
167 
getName()168   public String getName() {
169     return mName;
170   }
171 
172   // Returns the hprof id of a stack this site appears on.
getStackId()173   public int getStackId() {
174     return mStackId;
175   }
176 
177   // Returns the stack depth of this site in the stack whose id is returned
178   // by getStackId().
getStackDepth()179   public int getStackDepth() {
180     return mStackDepth;
181   }
182 
getChildren()183   List<Site> getChildren() {
184     return new ArrayList<Site>(mChildren.values());
185   }
186 
187   // Get the child at the given path relative to this site.
188   // Returns null if no such child found.
getChild(Iterator<StackFrame> path)189   Site getChild(Iterator<StackFrame> path) {
190     if (path.hasNext()) {
191       String next = path.next().toString();
192       Site child = mChildren.get(next);
193       return (child == null) ? null : child.getChild(path);
194     } else {
195       return this;
196     }
197   }
198 }
199