/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ahat;
import com.android.tools.perflib.heap.Heap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Class for rendering a table that includes sizes of some kind for each heap.
*/
class HeapTable {
/**
* Configuration for a value column of a heap table.
*/
public interface ValueConfig<T> {
String getDescription();
DocString render(T element);
}
/**
* Configuration for the HeapTable.
*/
public interface TableConfig<T> {
String getHeapsDescription();
long getSize(T element, Heap heap);
List<ValueConfig<T>> getValueConfigs();
}
/**
* Render the table to the given document.
* @param query - The page query.
* @param id - A unique identifier for the table on the page.
*/
public static <T> void render(Doc doc, Query query, String id,
TableConfig<T> config, AhatSnapshot snapshot, List<T> elements) {
// Only show the heaps that have non-zero entries.
List<Heap> heaps = new ArrayList<Heap>();
for (Heap heap : snapshot.getHeaps()) {
if (hasNonZeroEntry(snapshot, heap, config, elements)) {
heaps.add(heap);
}
}
List<ValueConfig<T>> values = config.getValueConfigs();
// Print the heap and values descriptions.
boolean showTotal = heaps.size() > 1;
List<Column> subcols = new ArrayList<Column>();
for (Heap heap : heaps) {
subcols.add(new Column(heap.getName(), Column.Align.RIGHT));
}
if (showTotal) {
subcols.add(new Column("Total", Column.Align.RIGHT));
}
List<Column> cols = new ArrayList<Column>();
for (ValueConfig value : values) {
cols.add(new Column(value.getDescription()));
}
doc.table(DocString.text(config.getHeapsDescription()), subcols, cols);
// Print the entries up to the selected limit.
SubsetSelector<T> selector = new SubsetSelector(query, id, elements);
ArrayList<DocString> vals = new ArrayList<DocString>();
for (T elem : selector.selected()) {
vals.clear();
long total = 0;
for (Heap heap : heaps) {
long size = config.getSize(elem, heap);
total += size;
vals.add(DocString.format("%,14d", size));
}
if (showTotal) {
vals.add(DocString.format("%,14d", total));
}
for (ValueConfig<T> value : values) {
vals.add(value.render(elem));
}
doc.row(vals.toArray(new DocString[0]));
}
// Print a summary of the remaining entries if there are any.
List<T> remaining = selector.remaining();
if (!remaining.isEmpty()) {
Map<Heap, Long> summary = new HashMap<Heap, Long>();
for (Heap heap : heaps) {
summary.put(heap, 0L);
}
for (T elem : remaining) {
for (Heap heap : heaps) {
summary.put(heap, summary.get(heap) + config.getSize(elem, heap));
}
}
vals.clear();
long total = 0;
for (Heap heap : heaps) {
long size = summary.get(heap);
total += size;
vals.add(DocString.format("%,14d", size));
}
if (showTotal) {
vals.add(DocString.format("%,14d", total));
}
for (ValueConfig<T> value : values) {
vals.add(DocString.text("..."));
}
doc.row(vals.toArray(new DocString[0]));
}
doc.end();
selector.render(doc);
}
// Returns true if the given heap has a non-zero size entry.
public static <T> boolean hasNonZeroEntry(AhatSnapshot snapshot, Heap heap,
TableConfig<T> config, List<T> elements) {
if (snapshot.getHeapSize(heap) > 0) {
for (T element : elements) {
if (config.getSize(element, heap) > 0) {
return true;
}
}
}
return false;
}
}