/* * 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.ClassObj; import com.android.tools.perflib.heap.Heap; import com.android.tools.perflib.heap.Instance; import com.android.tools.perflib.heap.StackFrame; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; class Site { // The site that this site was directly called from. // mParent is null for the root site. private Site mParent; // A description of the Site. Currently this is used to uniquely identify a // site within its parent. private String mName; // To identify this site, we pick one stack trace where we have seen the // site. mStackId is the id for that stack trace, and mStackDepth is the // depth of this site in that stack trace. // For the root site, mStackId is 0 and mStackDepth is 0. private int mStackId; private int mStackDepth; // Mapping from heap name to the total size of objects allocated in this // site (including child sites) on the given heap. private Map<String, Long> mSizesByHeap; // Mapping from child site name to child site. private Map<String, Site> mChildren; // List of all objects allocated in this site (including child sites). private List<Instance> mObjects; private List<ObjectsInfo> mObjectsInfos; private Map<Heap, Map<ClassObj, ObjectsInfo>> mObjectsInfoMap; public static class ObjectsInfo { public Heap heap; public ClassObj classObj; public long numInstances; public long numBytes; public ObjectsInfo(Heap heap, ClassObj classObj, long numInstances, long numBytes) { this.heap = heap; this.classObj = classObj; this.numInstances = numInstances; this.numBytes = numBytes; } } /** * Construct a root site. */ public Site(String name) { this(null, name, 0, 0); } public Site(Site parent, String name, int stackId, int stackDepth) { mParent = parent; mName = name; mStackId = stackId; mStackDepth = stackDepth; mSizesByHeap = new HashMap<String, Long>(); mChildren = new HashMap<String, Site>(); mObjects = new ArrayList<Instance>(); mObjectsInfos = new ArrayList<ObjectsInfo>(); mObjectsInfoMap = new HashMap<Heap, Map<ClassObj, ObjectsInfo>>(); } /** * Add an instance to this site. * Returns the site at which the instance was allocated. */ public Site add(int stackId, int stackDepth, Iterator<StackFrame> path, Instance inst) { mObjects.add(inst); String heap = inst.getHeap().getName(); mSizesByHeap.put(heap, getSize(heap) + inst.getSize()); Map<ClassObj, ObjectsInfo> classToObjectsInfo = mObjectsInfoMap.get(inst.getHeap()); if (classToObjectsInfo == null) { classToObjectsInfo = new HashMap<ClassObj, ObjectsInfo>(); mObjectsInfoMap.put(inst.getHeap(), classToObjectsInfo); } ObjectsInfo info = classToObjectsInfo.get(inst.getClassObj()); if (info == null) { info = new ObjectsInfo(inst.getHeap(), inst.getClassObj(), 0, 0); mObjectsInfos.add(info); classToObjectsInfo.put(inst.getClassObj(), info); } info.numInstances++; info.numBytes += inst.getSize(); if (path.hasNext()) { String next = path.next().toString(); Site child = mChildren.get(next); if (child == null) { child = new Site(this, next, stackId, stackDepth + 1); mChildren.put(next, child); } return child.add(stackId, stackDepth + 1, path, inst); } else { return this; } } // Get the size of a site for a specific heap. public long getSize(String heap) { Long val = mSizesByHeap.get(heap); if (val == null) { return 0; } return val; } /** * Get the list of objects allocated under this site. Includes objects * allocated in children sites. */ public Collection<Instance> getObjects() { return mObjects; } public List<ObjectsInfo> getObjectsInfos() { return mObjectsInfos; } // Get the combined size of the site for all heaps. public long getTotalSize() { long size = 0; for (Long val : mSizesByHeap.values()) { size += val; } return size; } /** * Return the site this site was called from. * Returns null for the root site. */ public Site getParent() { return mParent; } public String getName() { return mName; } // Returns the hprof id of a stack this site appears on. public int getStackId() { return mStackId; } // Returns the stack depth of this site in the stack whose id is returned // by getStackId(). public int getStackDepth() { return mStackDepth; } List<Site> getChildren() { return new ArrayList<Site>(mChildren.values()); } // Get the child at the given path relative to this site. // Returns null if no such child found. Site getChild(Iterator<StackFrame> path) { if (path.hasNext()) { String next = path.next().toString(); Site child = mChildren.get(next); return (child == null) ? null : child.getChild(path); } else { return this; } } }