blob: d0264a3b39bbd99313227114443902251f4aeb5e [file] [log] [blame]
/*
* Copyright (C) 2017 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.heapdump;
import com.android.tools.perflib.heap.ClassInstance;
import com.android.tools.perflib.heap.ClassObj;
import com.android.tools.perflib.heap.Instance;
import com.android.tools.perflib.heap.Snapshot;
import java.util.HashMap;
import java.util.Map;
/**
* Collection of utilities that may be suitable to have in perflib instead of
* ahat.
*/
public class Perflib {
/**
* Return a collection of instances in the given snapshot that are tied to
* registered native allocations and their corresponding registered native
* sizes.
*/
public static Map<Instance, Long> getRegisteredNativeAllocations(Snapshot snapshot) {
Map<Instance, Long> allocs = new HashMap<Instance, Long>();
ClassObj cleanerClass = snapshot.findClass("sun.misc.Cleaner");
if (cleanerClass != null) {
for (Instance cleanerInst : cleanerClass.getInstancesList()) {
ClassInstance cleaner = (ClassInstance)cleanerInst;
Object referent = getField(cleaner, "referent");
if (referent instanceof Instance) {
Instance inst = (Instance)referent;
Object thunkValue = getField(cleaner, "thunk");
if (thunkValue instanceof ClassInstance) {
ClassInstance thunk = (ClassInstance)thunkValue;
ClassObj thunkClass = thunk.getClassObj();
String cleanerThunkClassName = "libcore.util.NativeAllocationRegistry$CleanerThunk";
if (thunkClass != null && cleanerThunkClassName.equals(thunkClass.getClassName())) {
for (ClassInstance.FieldValue thunkField : thunk.getValues()) {
if (thunkField.getValue() instanceof ClassInstance) {
ClassInstance registry = (ClassInstance)thunkField.getValue();
ClassObj registryClass = registry.getClassObj();
String registryClassName = "libcore.util.NativeAllocationRegistry";
if (registryClass != null
&& registryClassName.equals(registryClass.getClassName())) {
Object sizeValue = getField(registry, "size");
if (sizeValue instanceof Long) {
long size = (Long)sizeValue;
if (size > 0) {
Long old = allocs.get(inst);
allocs.put(inst, old == null ? size : old + size);
}
}
break;
}
}
}
}
}
}
}
}
return allocs;
}
/**
* Helper function to read a single field from a perflib class instance.
* Returns null if field not found. Note there is no way to distinguish
* between field not found an a field value of null.
*/
private static Object getField(ClassInstance cls, String name) {
for (ClassInstance.FieldValue field : cls.getValues()) {
if (name.equals(field.getField().getName())) {
return field.getValue();
}
}
return null;
}
}