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 17package com.android.ahat; 18 19import com.android.tools.perflib.heap.Heap; 20import java.util.ArrayList; 21import java.util.HashMap; 22import java.util.List; 23import java.util.Map; 24 25/** 26 * Class for rendering a table that includes sizes of some kind for each heap. 27 */ 28class HeapTable { 29 /** 30 * Configuration for a value column of a heap table. 31 */ 32 public interface ValueConfig<T> { 33 String getDescription(); 34 DocString render(T element); 35 } 36 37 /** 38 * Configuration for the HeapTable. 39 */ 40 public interface TableConfig<T> { 41 String getHeapsDescription(); 42 long getSize(T element, Heap heap); 43 List<ValueConfig<T>> getValueConfigs(); 44 } 45 46 /** 47 * Render the table to the given document. 48 * @param query - The page query. 49 * @param id - A unique identifier for the table on the page. 50 */ 51 public static <T> void render(Doc doc, Query query, String id, 52 TableConfig<T> config, AhatSnapshot snapshot, List<T> elements) { 53 // Only show the heaps that have non-zero entries. 54 List<Heap> heaps = new ArrayList<Heap>(); 55 for (Heap heap : snapshot.getHeaps()) { 56 if (hasNonZeroEntry(snapshot, heap, config, elements)) { 57 heaps.add(heap); 58 } 59 } 60 61 List<ValueConfig<T>> values = config.getValueConfigs(); 62 63 // Print the heap and values descriptions. 64 boolean showTotal = heaps.size() > 1; 65 List<Column> subcols = new ArrayList<Column>(); 66 for (Heap heap : heaps) { 67 subcols.add(new Column(heap.getName(), Column.Align.RIGHT)); 68 } 69 if (showTotal) { 70 subcols.add(new Column("Total", Column.Align.RIGHT)); 71 } 72 List<Column> cols = new ArrayList<Column>(); 73 for (ValueConfig value : values) { 74 cols.add(new Column(value.getDescription())); 75 } 76 doc.table(DocString.text(config.getHeapsDescription()), subcols, cols); 77 78 // Print the entries up to the selected limit. 79 SubsetSelector<T> selector = new SubsetSelector(query, id, elements); 80 ArrayList<DocString> vals = new ArrayList<DocString>(); 81 for (T elem : selector.selected()) { 82 vals.clear(); 83 long total = 0; 84 for (Heap heap : heaps) { 85 long size = config.getSize(elem, heap); 86 total += size; 87 vals.add(DocString.format("%,14d", size)); 88 } 89 if (showTotal) { 90 vals.add(DocString.format("%,14d", total)); 91 } 92 93 for (ValueConfig<T> value : values) { 94 vals.add(value.render(elem)); 95 } 96 doc.row(vals.toArray(new DocString[0])); 97 } 98 99 // Print a summary of the remaining entries if there are any. 100 List<T> remaining = selector.remaining(); 101 if (!remaining.isEmpty()) { 102 Map<Heap, Long> summary = new HashMap<Heap, Long>(); 103 for (Heap heap : heaps) { 104 summary.put(heap, 0L); 105 } 106 107 for (T elem : remaining) { 108 for (Heap heap : heaps) { 109 summary.put(heap, summary.get(heap) + config.getSize(elem, heap)); 110 } 111 } 112 113 vals.clear(); 114 long total = 0; 115 for (Heap heap : heaps) { 116 long size = summary.get(heap); 117 total += size; 118 vals.add(DocString.format("%,14d", size)); 119 } 120 if (showTotal) { 121 vals.add(DocString.format("%,14d", total)); 122 } 123 124 for (ValueConfig<T> value : values) { 125 vals.add(DocString.text("...")); 126 } 127 doc.row(vals.toArray(new DocString[0])); 128 } 129 doc.end(); 130 selector.render(doc); 131 } 132 133 // Returns true if the given heap has a non-zero size entry. 134 public static <T> boolean hasNonZeroEntry(AhatSnapshot snapshot, Heap heap, 135 TableConfig<T> config, List<T> elements) { 136 if (snapshot.getHeapSize(heap) > 0) { 137 for (T element : elements) { 138 if (config.getSize(element, heap) > 0) { 139 return true; 140 } 141 } 142 } 143 return false; 144 } 145} 146 147