/* * 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.ahat.heapdump.AhatHeap; import com.android.ahat.heapdump.AhatSnapshot; import com.android.ahat.heapdump.Site; import com.android.ahat.heapdump.Sort; import java.io.IOException; import java.util.Collections; import java.util.Comparator; import java.util.List; class SiteHandler implements AhatHandler { private static final String ALLOCATION_SITE_ID = "frames"; private static final String SITES_CALLED_ID = "called"; private static final String OBJECTS_ALLOCATED_ID = "objects"; private AhatSnapshot mSnapshot; public SiteHandler(AhatSnapshot snapshot) { mSnapshot = snapshot; } @Override public void handle(Doc doc, Query query) throws IOException { int id = query.getInt("id", 0); int depth = query.getInt("depth", 0); Site site = mSnapshot.getSite(id, depth); doc.title("Site"); doc.big(Summarizer.summarize(site)); doc.section("Allocation Site"); SitePrinter.printSite(mSnapshot, doc, query, ALLOCATION_SITE_ID, site); doc.section("Sites Called from Here"); List<Site> children = site.getChildren(); if (children.isEmpty()) { doc.println(DocString.text("(none)")); } else { Collections.sort(children, Sort.defaultSiteCompare(mSnapshot)); HeapTable.TableConfig<Site> table = new HeapTable.TableConfig<Site>() { public String getHeapsDescription() { return "Reachable Bytes Allocated on Heap"; } public long getSize(Site element, AhatHeap heap) { return element.getSize(heap); } public List<HeapTable.ValueConfig<Site>> getValueConfigs() { HeapTable.ValueConfig<Site> value = new HeapTable.ValueConfig<Site>() { public String getDescription() { return "Child Site"; } public DocString render(Site element) { return Summarizer.summarize(element); } }; return Collections.singletonList(value); } }; HeapTable.render(doc, query, SITES_CALLED_ID, table, mSnapshot, children); } doc.section("Objects Allocated"); doc.table( new Column("Reachable Bytes Allocated", Column.Align.RIGHT), new Column("Δ", Column.Align.RIGHT, mSnapshot.isDiffed()), new Column("Instances", Column.Align.RIGHT), new Column("Δ", Column.Align.RIGHT, mSnapshot.isDiffed()), new Column("Heap"), new Column("Class")); List<Site.ObjectsInfo> infos = site.getObjectsInfos(); Comparator<Site.ObjectsInfo> compare = new Sort.WithPriority<Site.ObjectsInfo>( Sort.OBJECTS_INFO_BY_HEAP_NAME, Sort.OBJECTS_INFO_BY_SIZE, Sort.OBJECTS_INFO_BY_CLASS_NAME); Collections.sort(infos, compare); SubsetSelector<Site.ObjectsInfo> selector = new SubsetSelector(query, OBJECTS_ALLOCATED_ID, infos); for (Site.ObjectsInfo info : selector.selected()) { Site.ObjectsInfo baseinfo = info.getBaseline(); String className = info.getClassName(); doc.row( DocString.format("%,14d", info.numBytes), DocString.delta(false, false, info.numBytes, baseinfo.numBytes), DocString.link( DocString.formattedUri("objects?id=%d&depth=%d&heap=%s&class=%s", site.getId(), site.getDepth(), info.heap.getName(), className), DocString.format("%,14d", info.numInstances)), DocString.delta(false, false, info.numInstances, baseinfo.numInstances), DocString.text(info.heap.getName()), Summarizer.summarize(info.classObj)); } doc.end(); selector.render(doc); } }