blob: 78aac178e98078e1ec20a63226f22cd442f1d97a [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.ArrayInstance;
20import com.android.tools.perflib.heap.ClassInstance;
21import com.android.tools.perflib.heap.ClassObj;
22import com.android.tools.perflib.heap.Field;
23import com.android.tools.perflib.heap.Heap;
24import com.android.tools.perflib.heap.Instance;
Richard Uhler38f9eba2015-11-11 08:31:52 -080025import com.android.tools.perflib.heap.RootType;
Richard Uhlerb730b782015-07-15 16:01:58 -070026import java.io.IOException;
27import java.util.ArrayList;
Richard Uhler1af86f12015-10-29 14:55:00 -070028import java.util.Arrays;
Richard Uhler38f9eba2015-11-11 08:31:52 -080029import java.util.Collection;
Richard Uhlerb730b782015-07-15 16:01:58 -070030import java.util.Collections;
31import java.util.List;
32import java.util.Map;
33
Richard Uhler69286492016-09-20 10:41:47 +010034import static com.android.ahat.InstanceUtils.PathElement;
35
Richard Uhler1af86f12015-10-29 14:55:00 -070036class ObjectHandler implements AhatHandler {
37
38 private static final String ARRAY_ELEMENTS_ID = "elements";
39 private static final String DOMINATOR_PATH_ID = "dompath";
40 private static final String ALLOCATION_SITE_ID = "frames";
41 private static final String DOMINATED_OBJECTS_ID = "dominated";
42 private static final String INSTANCE_FIELDS_ID = "ifields";
43 private static final String STATIC_FIELDS_ID = "sfields";
44 private static final String HARD_REFS_ID = "refs";
45 private static final String SOFT_REFS_ID = "srefs";
46
47 private AhatSnapshot mSnapshot;
48
Richard Uhlerb730b782015-07-15 16:01:58 -070049 public ObjectHandler(AhatSnapshot snapshot) {
Richard Uhler1af86f12015-10-29 14:55:00 -070050 mSnapshot = snapshot;
Richard Uhlerb730b782015-07-15 16:01:58 -070051 }
52
53 @Override
54 public void handle(Doc doc, Query query) throws IOException {
55 long id = query.getLong("id", 0);
56 Instance inst = mSnapshot.findInstance(id);
57 if (inst == null) {
Richard Uhlerc21e4e62015-08-31 16:16:14 -070058 doc.println(DocString.format("No object with id %08xl", id));
Richard Uhlerb730b782015-07-15 16:01:58 -070059 return;
60 }
61
62 doc.title("Object %08x", inst.getUniqueId());
Richard Uhler38f9eba2015-11-11 08:31:52 -080063 doc.big(Value.render(mSnapshot, inst));
Richard Uhlerb730b782015-07-15 16:01:58 -070064
Richard Uhler1af86f12015-10-29 14:55:00 -070065 printAllocationSite(doc, query, inst);
Richard Uhler69286492016-09-20 10:41:47 +010066 printGcRootPath(doc, query, inst);
Richard Uhlerb730b782015-07-15 16:01:58 -070067
68 doc.section("Object Info");
69 ClassObj cls = inst.getClassObj();
70 doc.descriptions();
Richard Uhler38f9eba2015-11-11 08:31:52 -080071 doc.description(DocString.text("Class"), Value.render(mSnapshot, cls));
Richard Uhlerc21e4e62015-08-31 16:16:14 -070072 doc.description(DocString.text("Size"), DocString.format("%d", inst.getSize()));
Richard Uhlerb730b782015-07-15 16:01:58 -070073 doc.description(
74 DocString.text("Retained Size"),
Richard Uhlerc21e4e62015-08-31 16:16:14 -070075 DocString.format("%d", inst.getTotalRetainedSize()));
Richard Uhlerb730b782015-07-15 16:01:58 -070076 doc.description(DocString.text("Heap"), DocString.text(inst.getHeap().getName()));
Richard Uhler38f9eba2015-11-11 08:31:52 -080077
78 Collection<RootType> rootTypes = mSnapshot.getRootTypes(inst);
79 if (rootTypes != null) {
80 DocString types = new DocString();
81 String comma = "";
82 for (RootType type : rootTypes) {
83 types.append(comma);
84 types.append(type.getName());
85 comma = ", ";
86 }
87 doc.description(DocString.text("Root Types"), types);
88 }
89
Richard Uhlerb730b782015-07-15 16:01:58 -070090 doc.end();
91
92 printBitmap(doc, inst);
93 if (inst instanceof ClassInstance) {
Richard Uhler38f9eba2015-11-11 08:31:52 -080094 printClassInstanceFields(doc, query, mSnapshot, (ClassInstance)inst);
Richard Uhlerb730b782015-07-15 16:01:58 -070095 } else if (inst instanceof ArrayInstance) {
Richard Uhler38f9eba2015-11-11 08:31:52 -080096 printArrayElements(doc, query, mSnapshot, (ArrayInstance)inst);
Richard Uhlerb730b782015-07-15 16:01:58 -070097 } else if (inst instanceof ClassObj) {
Richard Uhler38f9eba2015-11-11 08:31:52 -080098 printClassInfo(doc, query, mSnapshot, (ClassObj)inst);
Richard Uhlerb730b782015-07-15 16:01:58 -070099 }
Richard Uhler38f9eba2015-11-11 08:31:52 -0800100 printReferences(doc, query, mSnapshot, inst);
Richard Uhlerb730b782015-07-15 16:01:58 -0700101 printDominatedObjects(doc, query, inst);
102 }
103
Richard Uhler38f9eba2015-11-11 08:31:52 -0800104 private static void printClassInstanceFields(
105 Doc doc, Query query, AhatSnapshot snapshot, ClassInstance inst) {
Richard Uhlerb730b782015-07-15 16:01:58 -0700106 doc.section("Fields");
107 doc.table(new Column("Type"), new Column("Name"), new Column("Value"));
Richard Uhler1af86f12015-10-29 14:55:00 -0700108 SubsetSelector<ClassInstance.FieldValue> selector
109 = new SubsetSelector(query, INSTANCE_FIELDS_ID, inst.getValues());
110 for (ClassInstance.FieldValue field : selector.selected()) {
Richard Uhlerb730b782015-07-15 16:01:58 -0700111 doc.row(
112 DocString.text(field.getField().getType().toString()),
113 DocString.text(field.getField().getName()),
Richard Uhler38f9eba2015-11-11 08:31:52 -0800114 Value.render(snapshot, field.getValue()));
Richard Uhlerb730b782015-07-15 16:01:58 -0700115 }
116 doc.end();
Richard Uhler1af86f12015-10-29 14:55:00 -0700117 selector.render(doc);
Richard Uhlerb730b782015-07-15 16:01:58 -0700118 }
119
Richard Uhler38f9eba2015-11-11 08:31:52 -0800120 private static void printArrayElements(
121 Doc doc, Query query, AhatSnapshot snapshot, ArrayInstance array) {
Richard Uhlerb730b782015-07-15 16:01:58 -0700122 doc.section("Array Elements");
123 doc.table(new Column("Index", Column.Align.RIGHT), new Column("Value"));
Richard Uhler1af86f12015-10-29 14:55:00 -0700124 List<Object> elements = Arrays.asList(array.getValues());
125 SubsetSelector<Object> selector = new SubsetSelector(query, ARRAY_ELEMENTS_ID, elements);
126 int i = 0;
127 for (Object elem : selector.selected()) {
Richard Uhler38f9eba2015-11-11 08:31:52 -0800128 doc.row(DocString.format("%d", i), Value.render(snapshot, elem));
Richard Uhler1af86f12015-10-29 14:55:00 -0700129 i++;
Richard Uhlerb730b782015-07-15 16:01:58 -0700130 }
131 doc.end();
Richard Uhler1af86f12015-10-29 14:55:00 -0700132 selector.render(doc);
Richard Uhlerb730b782015-07-15 16:01:58 -0700133 }
134
Richard Uhler38f9eba2015-11-11 08:31:52 -0800135 private static void printClassInfo(
136 Doc doc, Query query, AhatSnapshot snapshot, ClassObj clsobj) {
Richard Uhlerb730b782015-07-15 16:01:58 -0700137 doc.section("Class Info");
138 doc.descriptions();
Richard Uhler38f9eba2015-11-11 08:31:52 -0800139 doc.description(DocString.text("Super Class"),
140 Value.render(snapshot, clsobj.getSuperClassObj()));
141 doc.description(DocString.text("Class Loader"),
142 Value.render(snapshot, clsobj.getClassLoader()));
Richard Uhlerb730b782015-07-15 16:01:58 -0700143 doc.end();
144
145 doc.section("Static Fields");
146 doc.table(new Column("Type"), new Column("Name"), new Column("Value"));
Richard Uhler1af86f12015-10-29 14:55:00 -0700147 List<Map.Entry<Field, Object>> fields
148 = new ArrayList<Map.Entry<Field, Object>>(clsobj.getStaticFieldValues().entrySet());
149 SubsetSelector<Map.Entry<Field, Object>> selector
150 = new SubsetSelector(query, STATIC_FIELDS_ID, fields);
151 for (Map.Entry<Field, Object> field : selector.selected()) {
Richard Uhlerb730b782015-07-15 16:01:58 -0700152 doc.row(
153 DocString.text(field.getKey().getType().toString()),
154 DocString.text(field.getKey().getName()),
Richard Uhler38f9eba2015-11-11 08:31:52 -0800155 Value.render(snapshot, field.getValue()));
Richard Uhlerb730b782015-07-15 16:01:58 -0700156 }
157 doc.end();
Richard Uhler1af86f12015-10-29 14:55:00 -0700158 selector.render(doc);
Richard Uhlerb730b782015-07-15 16:01:58 -0700159 }
160
Richard Uhler38f9eba2015-11-11 08:31:52 -0800161 private static void printReferences(
162 Doc doc, Query query, AhatSnapshot snapshot, Instance inst) {
Richard Uhlerb730b782015-07-15 16:01:58 -0700163 doc.section("Objects with References to this Object");
Richard Uhler6919a012015-12-15 09:15:00 -0800164 if (inst.getHardReverseReferences().isEmpty()) {
Richard Uhlerb730b782015-07-15 16:01:58 -0700165 doc.println(DocString.text("(none)"));
166 } else {
167 doc.table(new Column("Object"));
Richard Uhler6919a012015-12-15 09:15:00 -0800168 List<Instance> references = inst.getHardReverseReferences();
Richard Uhler1af86f12015-10-29 14:55:00 -0700169 SubsetSelector<Instance> selector = new SubsetSelector(query, HARD_REFS_ID, references);
170 for (Instance ref : selector.selected()) {
Richard Uhler38f9eba2015-11-11 08:31:52 -0800171 doc.row(Value.render(snapshot, ref));
Richard Uhlerb730b782015-07-15 16:01:58 -0700172 }
173 doc.end();
Richard Uhler1af86f12015-10-29 14:55:00 -0700174 selector.render(doc);
Richard Uhlerb730b782015-07-15 16:01:58 -0700175 }
176
Richard Uhler6919a012015-12-15 09:15:00 -0800177 if (inst.getSoftReverseReferences() != null) {
Richard Uhlerb730b782015-07-15 16:01:58 -0700178 doc.section("Objects with Soft References to this Object");
179 doc.table(new Column("Object"));
Richard Uhler6919a012015-12-15 09:15:00 -0800180 List<Instance> references = inst.getSoftReverseReferences();
Richard Uhler1af86f12015-10-29 14:55:00 -0700181 SubsetSelector<Instance> selector = new SubsetSelector(query, SOFT_REFS_ID, references);
182 for (Instance ref : selector.selected()) {
Richard Uhler38f9eba2015-11-11 08:31:52 -0800183 doc.row(Value.render(snapshot, ref));
Richard Uhlerb730b782015-07-15 16:01:58 -0700184 }
185 doc.end();
Richard Uhler1af86f12015-10-29 14:55:00 -0700186 selector.render(doc);
Richard Uhlerb730b782015-07-15 16:01:58 -0700187 }
188 }
189
Richard Uhler1af86f12015-10-29 14:55:00 -0700190 private void printAllocationSite(Doc doc, Query query, Instance inst) {
Richard Uhlerb730b782015-07-15 16:01:58 -0700191 doc.section("Allocation Site");
192 Site site = mSnapshot.getSiteForInstance(inst);
Richard Uhler1af86f12015-10-29 14:55:00 -0700193 SitePrinter.printSite(mSnapshot, doc, query, ALLOCATION_SITE_ID, site);
Richard Uhlerb730b782015-07-15 16:01:58 -0700194 }
195
196 // Draw the bitmap corresponding to this instance if there is one.
197 private static void printBitmap(Doc doc, Instance inst) {
198 Instance bitmap = InstanceUtils.getAssociatedBitmapInstance(inst);
199 if (bitmap != null) {
200 doc.section("Bitmap Image");
201 doc.println(DocString.image(
Richard Uhlerc21e4e62015-08-31 16:16:14 -0700202 DocString.formattedUri("bitmap?id=%d", bitmap.getId()), "bitmap image"));
Richard Uhlerb730b782015-07-15 16:01:58 -0700203 }
204 }
205
Richard Uhler69286492016-09-20 10:41:47 +0100206 private void printGcRootPath(Doc doc, Query query, Instance inst) {
207 doc.section("Sample Path from GC Root");
208 List<PathElement> path = InstanceUtils.getPathFromGcRoot(inst);
Richard Uhlerb730b782015-07-15 16:01:58 -0700209
210 // Add 'null' as a marker for the root.
Richard Uhler69286492016-09-20 10:41:47 +0100211 path.add(0, null);
Richard Uhlerb730b782015-07-15 16:01:58 -0700212
Richard Uhler69286492016-09-20 10:41:47 +0100213 HeapTable.TableConfig<PathElement> table = new HeapTable.TableConfig<PathElement>() {
Richard Uhlerb730b782015-07-15 16:01:58 -0700214 public String getHeapsDescription() {
Richard Uhler69286492016-09-20 10:41:47 +0100215 return "Bytes Retained by Heap (Dominators Only)";
Richard Uhlerb730b782015-07-15 16:01:58 -0700216 }
217
Richard Uhler69286492016-09-20 10:41:47 +0100218 public long getSize(PathElement element, Heap heap) {
Richard Uhlerb730b782015-07-15 16:01:58 -0700219 if (element == null) {
220 return mSnapshot.getHeapSize(heap);
221 }
Richard Uhler69286492016-09-20 10:41:47 +0100222 if (element.isDominator) {
223 int index = mSnapshot.getHeapIndex(heap);
224 return element.instance.getRetainedSize(index);
225 }
226 return 0;
Richard Uhlerb730b782015-07-15 16:01:58 -0700227 }
228
Richard Uhler69286492016-09-20 10:41:47 +0100229 public List<HeapTable.ValueConfig<PathElement>> getValueConfigs() {
230 HeapTable.ValueConfig<PathElement> value = new HeapTable.ValueConfig<PathElement>() {
Richard Uhlerb730b782015-07-15 16:01:58 -0700231 public String getDescription() {
Richard Uhler69286492016-09-20 10:41:47 +0100232 return "Path Element";
Richard Uhlerb730b782015-07-15 16:01:58 -0700233 }
234
Richard Uhler69286492016-09-20 10:41:47 +0100235 public DocString render(PathElement element) {
Richard Uhlerb730b782015-07-15 16:01:58 -0700236 if (element == null) {
Richard Uhler7a16adb2015-11-11 09:13:23 -0800237 return DocString.link(DocString.uri("rooted"), DocString.text("ROOT"));
Richard Uhlerb730b782015-07-15 16:01:58 -0700238 } else {
Richard Uhler69286492016-09-20 10:41:47 +0100239 DocString label = DocString.text(" → ");
240 label.append(Value.render(mSnapshot, element.instance));
241 label.append(element.field);
242 return label;
Richard Uhlerb730b782015-07-15 16:01:58 -0700243 }
244 }
245 };
246 return Collections.singletonList(value);
247 }
248 };
Richard Uhler1af86f12015-10-29 14:55:00 -0700249 HeapTable.render(doc, query, DOMINATOR_PATH_ID, table, mSnapshot, path);
Richard Uhlerb730b782015-07-15 16:01:58 -0700250 }
251
252 public void printDominatedObjects(Doc doc, Query query, Instance inst) {
253 doc.section("Immediately Dominated Objects");
254 List<Instance> instances = mSnapshot.getDominated(inst);
255 if (instances != null) {
Richard Uhler1af86f12015-10-29 14:55:00 -0700256 DominatedList.render(mSnapshot, doc, query, DOMINATED_OBJECTS_ID, instances);
Richard Uhlerb730b782015-07-15 16:01:58 -0700257 } else {
258 doc.println(DocString.text("(none)"));
259 }
260 }
261}
262