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