Remove perflib-based native allocation registry identification.
In preparation for removing dependency on perflib.
Test: m ahat-test, change covered by NativeAllocationTest.
Change-Id: Id91c2be4910699f9d4c90b44210f8d9bdb9c2318
diff --git a/tools/ahat/src/heapdump/AhatClassInstance.java b/tools/ahat/src/heapdump/AhatClassInstance.java
index a2f61ca..0224025 100644
--- a/tools/ahat/src/heapdump/AhatClassInstance.java
+++ b/tools/ahat/src/heapdump/AhatClassInstance.java
@@ -248,6 +248,49 @@
return bitmap;
}
+ @Override
+ public RegisteredNativeAllocation asRegisteredNativeAllocation() {
+ if (!isInstanceOfClass("sun.misc.Cleaner")) {
+ return null;
+ }
+
+ Value vthunk = getField("thunk");
+ if (vthunk == null || !vthunk.isAhatInstance()) {
+ return null;
+ }
+
+ AhatClassInstance thunk = vthunk.asAhatInstance().asClassInstance();
+ if (thunk == null
+ || !thunk.isInstanceOfClass("libcore.util.NativeAllocationRegistry$CleanerThunk")) {
+ return null;
+ }
+
+ Value vregistry = thunk.getField("this$0");
+ if (vregistry == null || !vregistry.isAhatInstance()) {
+ return null;
+ }
+
+ AhatClassInstance registry = vregistry.asAhatInstance().asClassInstance();
+ if (registry == null || !registry.isInstanceOfClass("libcore.util.NativeAllocationRegistry")) {
+ return null;
+ }
+
+ Value size = registry.getField("size");
+ if (!size.isLong()) {
+ return null;
+ }
+
+ Value referent = getField("referent");
+ if (referent == null || !referent.isAhatInstance()) {
+ return null;
+ }
+
+ RegisteredNativeAllocation rna = new RegisteredNativeAllocation();
+ rna.referent = referent.asAhatInstance();
+ rna.size = size.asLong();
+ return rna;
+ }
+
private static class InstanceFieldIterator implements Iterable<FieldValue>,
Iterator<FieldValue> {
// The complete list of instance field values to iterate over, including
diff --git a/tools/ahat/src/heapdump/AhatInstance.java b/tools/ahat/src/heapdump/AhatInstance.java
index 0e78558..05dcc68 100644
--- a/tools/ahat/src/heapdump/AhatInstance.java
+++ b/tools/ahat/src/heapdump/AhatInstance.java
@@ -363,6 +363,19 @@
return null;
}
+ public static class RegisteredNativeAllocation {
+ public AhatInstance referent;
+ public long size;
+ };
+
+ /**
+ * Return the registered native allocation that this instance represents, if
+ * any. This is relevant for instances of sun.misc.Cleaner.
+ */
+ public RegisteredNativeAllocation asRegisteredNativeAllocation() {
+ return null;
+ }
+
/**
* Returns a sample path from a GC root to this instance.
* This instance is included as the last element of the path with an empty
diff --git a/tools/ahat/src/heapdump/AhatSnapshot.java b/tools/ahat/src/heapdump/AhatSnapshot.java
index 1b2cf3c..703ba25 100644
--- a/tools/ahat/src/heapdump/AhatSnapshot.java
+++ b/tools/ahat/src/heapdump/AhatSnapshot.java
@@ -36,7 +36,6 @@
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
-import java.util.Map;
public class AhatSnapshot implements Diffable<AhatSnapshot> {
private final Site mRootSite = new Site("ROOT");
@@ -128,10 +127,9 @@
}
});
- Map<Instance, Long> registeredNative = Perflib.getRegisteredNativeAllocations(snapshot);
-
// Initialize ahat snapshot and instances based on the perflib snapshot
// and instances.
+ List<AhatInstance> cleaners = new ArrayList<AhatInstance>();
for (AhatInstance ahat : mInstances) {
Instance inst = snapshot.findInstance(ahat.getId());
@@ -142,9 +140,9 @@
}
ahat.initialize(this, inst, mRootSite.getSite(frames));
- Long registeredNativeSize = registeredNative.get(inst);
- if (registeredNativeSize != null) {
- ahat.addRegisteredNativeSize(registeredNativeSize);
+ ClassObj classObj = inst.getClassObj();
+ if (classObj != null && "sun.misc.Cleaner".equals(classObj.getClassName())) {
+ cleaners.add(ahat);
}
}
@@ -162,6 +160,14 @@
}
snapshot.dispose();
+ // Update registered native allocation size.
+ for (AhatInstance cleaner : cleaners) {
+ AhatInstance.RegisteredNativeAllocation nra = cleaner.asRegisteredNativeAllocation();
+ if (nra != null) {
+ nra.referent.addRegisteredNativeSize(nra.size);
+ }
+ }
+
AhatInstance.computeReverseReferences(superRoot);
DominatorsComputation.computeDominators(superRoot);
AhatInstance.computeRetainedSize(superRoot, mHeaps.size());
diff --git a/tools/ahat/src/heapdump/Perflib.java b/tools/ahat/src/heapdump/Perflib.java
deleted file mode 100644
index d0264a3..0000000
--- a/tools/ahat/src/heapdump/Perflib.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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;
- }
-}