blob: 2437d0388c2512ea65cd6cde64cf6c2c94a23b27 [file] [log] [blame]
Richard Uhlerb730b782015-07-15 16:01:58 -07001/*
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
17package com.android.ahat;
18
19import com.android.tools.perflib.heap.ClassObj;
20import com.android.tools.perflib.heap.Heap;
21import com.android.tools.perflib.heap.Instance;
22import com.android.tools.perflib.heap.RootObj;
23import com.android.tools.perflib.heap.Snapshot;
24import com.android.tools.perflib.heap.StackFrame;
25import com.android.tools.perflib.heap.StackTrace;
26import com.google.common.collect.Iterables;
27import com.google.common.collect.Lists;
28import java.util.ArrayList;
29import java.util.Arrays;
30import java.util.Collection;
31import java.util.Collections;
32import java.util.HashMap;
33import java.util.List;
34import java.util.Map;
35
36/**
37 * A wrapper over the perflib snapshot that provides the behavior we use in
38 * ahat.
39 */
40class AhatSnapshot {
41 private Snapshot mSnapshot;
42 private List<Heap> mHeaps;
43
44 // Map from Instance to the list of Instances it immediately dominates.
45 private Map<Instance, List<Instance>> mDominated;
46
47 private Site mRootSite;
48 private Map<Heap, Long> mHeapSizes;
49
50 public AhatSnapshot(Snapshot snapshot) {
51 mSnapshot = snapshot;
52 mHeaps = new ArrayList<Heap>(mSnapshot.getHeaps());
53 mDominated = new HashMap<Instance, List<Instance>>();
54 mRootSite = new Site("ROOT");
55 mHeapSizes = new HashMap<Heap, Long>();
56
57 ClassObj javaLangClass = mSnapshot.findClass("java.lang.Class");
58 for (Heap heap : mHeaps) {
59 long total = 0;
60 for (Instance inst : Iterables.concat(heap.getClasses(), heap.getInstances())) {
61 Instance dominator = inst.getImmediateDominator();
62 if (dominator != null) {
63 total += inst.getSize();
64
65 // Properly label the class of a class object.
66 if (inst instanceof ClassObj && javaLangClass != null && inst.getClassObj() == null) {
67 inst.setClassId(javaLangClass.getId());
68 }
69
70 // Update dominated instances.
71 List<Instance> instances = mDominated.get(dominator);
72 if (instances == null) {
73 instances = new ArrayList<Instance>();
74 mDominated.put(dominator, instances);
75 }
76 instances.add(inst);
77
78 // Update sites.
79 List<StackFrame> path = Collections.emptyList();
80 StackTrace stack = getStack(inst);
81 int stackId = getStackTraceSerialNumber(stack);
82 if (stack != null) {
83 StackFrame[] frames = getStackFrames(stack);
84 if (frames != null && frames.length > 0) {
85 path = Lists.reverse(Arrays.asList(frames));
86 }
87 }
88 mRootSite.add(stackId, 0, path.iterator(), inst);
89 }
90 }
91 mHeapSizes.put(heap, total);
92 }
93 }
94
95 public Instance findInstance(long id) {
96 return mSnapshot.findInstance(id);
97 }
98
99 public int getHeapIndex(Heap heap) {
100 return mSnapshot.getHeapIndex(heap);
101 }
102
103 public Heap getHeap(String name) {
104 return mSnapshot.getHeap(name);
105 }
106
107 public Collection<RootObj> getGCRoots() {
108 return mSnapshot.getGCRoots();
109 }
110
111 public List<Heap> getHeaps() {
112 return mHeaps;
113 }
114
115 public Site getRootSite() {
116 return mRootSite;
117 }
118
119 /**
120 * Look up the site at which the given object was allocated.
121 */
122 public Site getSiteForInstance(Instance inst) {
123 Site site = mRootSite;
124 StackTrace stack = getStack(inst);
125 if (stack != null) {
126 StackFrame[] frames = getStackFrames(stack);
127 if (frames != null) {
128 List<StackFrame> path = Lists.reverse(Arrays.asList(frames));
129 site = mRootSite.getChild(path.iterator());
130 }
131 }
132 return site;
133 }
134
135 /**
136 * Return a list of those objects immediately dominated by the given
137 * instance.
138 */
139 public List<Instance> getDominated(Instance inst) {
140 return mDominated.get(inst);
141 }
142
143 /**
144 * Return the total size of reachable objects allocated on the given heap.
145 */
146 public long getHeapSize(Heap heap) {
147 return mHeapSizes.get(heap);
148 }
149
150 /**
151 * Return the class name for the given class object.
152 * classObj may be null, in which case "(class unknown)" is returned.
153 */
154 public static String getClassName(ClassObj classObj) {
155 if (classObj == null) {
156 return "(class unknown)";
157 }
158 return classObj.getClassName();
159 }
160
161 // Return the stack where the given instance was allocated.
162 private static StackTrace getStack(Instance inst) {
163 // TODO: return inst.getStack() once perflib is fixed.
164 return null;
165 }
166
167 // Return the list of stack frames for a stack trace.
168 private static StackFrame[] getStackFrames(StackTrace stack) {
169 // TODO: Use stack.getFrames() once perflib is fixed.
170 return null;
171 }
172
173 // Return the serial number of the given stack trace.
174 private static int getStackTraceSerialNumber(StackTrace stack) {
175 // TODO: Use stack.getSerialNumber() once perflib is fixed.
176 return 0;
177 }
178
179 // Get the site associated with the given stack id and depth.
180 // Returns the root site if no such site found.
181 // depth of -1 means the full stack.
182 public Site getSite(int stackId, int depth) {
183 Site site = mRootSite;
184 StackTrace stack = mSnapshot.getStackTrace(stackId);
185 if (stack != null) {
186 StackFrame[] frames = getStackFrames(stack);
187 if (frames != null) {
188 List<StackFrame> path = Lists.reverse(Arrays.asList(frames));
189 if (depth >= 0) {
190 path = path.subList(0, depth);
191 }
192 site = mRootSite.getChild(path.iterator());
193 }
194 }
195 return site;
196 }
197}