Mercurial > hg > truffle
changeset 13966:be0d961e3a88
New methods for querying memory usage of individual objects and object graphs in Graal API (MetaAccessProvider#getMemorySize, MetaUtil#getMemorySizeRecursive).
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Mon, 17 Feb 2014 17:06:41 +0100 |
parents | d68f5d0c97f0 |
children | 4cd7c6629841 |
files | CHANGELOG.md graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java |
diffstat | 5 files changed, 149 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/CHANGELOG.md Mon Feb 17 13:48:41 2014 +0100 +++ b/CHANGELOG.md Mon Feb 17 17:06:41 2014 +0100 @@ -2,6 +2,7 @@ ## `tip` ### Graal +* New methods for querying memory usage of individual objects and object graphs in Graal API (MetaAccessProvider#getMemorySize, MetaUtil#getMemorySizeRecursive). * ... ### Truffle
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java Mon Feb 17 13:48:41 2014 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java Mon Feb 17 17:06:41 2014 +0100 @@ -383,6 +383,19 @@ } /** + * Number of bytes that are necessary to represent a value of this kind. + * + * @return the number of bytes + */ + public int getByteCount() { + if (this == Boolean) { + return 1; + } else { + return getBitCount() >> 3; + } + } + + /** * Number of bits that are necessary to represent a value of this kind. * * @return the number of bits
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Mon Feb 17 13:48:41 2014 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Mon Feb 17 17:06:41 2014 +0100 @@ -60,6 +60,14 @@ ResolvedJavaType lookupJavaType(Constant constant); /** + * Returns the number of bytes occupied by this constant value or constant object. + * + * @param constant the constant whose bytes should be measured + * @return the number of bytes occupied by this constant + */ + long getMemorySize(Constant constant); + + /** * Parses a <a * href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3">method * descriptor</a> into a {@link Signature}. The behavior of this method is undefined if the
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Mon Feb 17 13:48:41 2014 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Mon Feb 17 17:06:41 2014 +0100 @@ -24,6 +24,7 @@ import static java.lang.reflect.Modifier.*; +import java.io.*; import java.lang.annotation.*; import java.lang.reflect.*; import java.util.*; @@ -36,6 +37,104 @@ */ public class MetaUtil { + private static class ClassInfo { + public long totalSize; + public long instanceCount; + + @Override + public String toString() { + return "totalSize=" + totalSize + ", instanceCount=" + instanceCount; + } + } + + /** + * Returns the number of bytes occupied by this constant value or constant object and + * recursively all values reachable from this value. + * + * @param constant the constant whose bytes should be measured + * @param printTopN print total size and instance count of the top n classes is desired + * @return the number of bytes occupied by this constant + */ + public static long getMemorySizeRecursive(MetaAccessProvider access, Constant constant, PrintStream out, int printTopN) { + IdentityHashMap<Object, Boolean> marked = new IdentityHashMap<>(); + Stack<Constant> stack = new Stack<>(); + if (constant.getKind() == Kind.Object && constant.isNonNull()) { + marked.put(constant.asObject(), Boolean.TRUE); + } + final HashMap<Class, ClassInfo> histogram = new HashMap<>(); + stack.push(constant); + long sum = 0; + while (!stack.isEmpty()) { + Constant c = stack.pop(); + long memorySize = access.getMemorySize(constant); + sum += memorySize; + if (c.getKind() == Kind.Object && c.isNonNull()) { + Class<?> clazz = c.asObject().getClass(); + if (!histogram.containsKey(clazz)) { + histogram.put(clazz, new ClassInfo()); + } + ClassInfo info = histogram.get(clazz); + info.instanceCount++; + info.totalSize += memorySize; + ResolvedJavaType type = access.lookupJavaType(c); + if (type.isArray()) { + if (!type.getComponentType().isPrimitive()) { + Object[] array = (Object[]) c.asObject(); + for (Object value : array) { + Constant forObject = Constant.forObject(value); + pushConstant(marked, stack, forObject); + } + } + } else { + ResolvedJavaField[] instanceFields = type.getInstanceFields(true); + for (ResolvedJavaField f : instanceFields) { + if (f.getKind() == Kind.Object) { + Constant value = f.readValue(c); + pushConstant(marked, stack, value); + } + } + } + } + } + ArrayList<Class> clazzes = new ArrayList<>(); + clazzes.addAll(histogram.keySet()); + Collections.sort(clazzes, new Comparator<Class>() { + + @Override + public int compare(Class o1, Class o2) { + long l1 = histogram.get(o1).totalSize; + long l2 = histogram.get(o2).totalSize; + if (l1 > l2) { + return -1; + } else if (l1 == l2) { + return 0; + } else { + return 1; + } + } + }); + + int z = 0; + for (Class c : clazzes) { + if (z > printTopN) { + break; + } + out.println("Class " + c + ", " + histogram.get(c)); + ++z; + } + + return sum; + } + + private static void pushConstant(IdentityHashMap<Object, Boolean> marked, Stack<Constant> stack, Constant value) { + if (value.isNonNull()) { + if (!marked.containsKey(value.asObject())) { + marked.put(value.asObject(), Boolean.TRUE); + stack.push(value); + } + } + } + /** * Returns true if the specified typed is exactly the type {@link java.lang.Object}. */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java Mon Feb 17 13:48:41 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java Mon Feb 17 17:06:41 2014 +0100 @@ -26,9 +26,11 @@ import java.lang.reflect.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.replacements.*; /** * HotSpot implementation of {@link MetaAccessProvider}. @@ -284,4 +286,30 @@ } throw GraalInternalError.shouldNotReachHere(Integer.toHexString(reason)); } + + @Override + public long getMemorySize(Constant constant) { + if (constant.getKind() == Kind.Object) { + HotSpotResolvedObjectType lookupJavaType = (HotSpotResolvedObjectType) this.lookupJavaType(constant); + + if (lookupJavaType == null) { + return 0; + } else { + if (lookupJavaType.isArray()) { + // TODO(tw): Add compressed pointer support. + int length = Array.getLength(constant.asObject()); + ResolvedJavaType elementType = lookupJavaType.getComponentType(); + Kind elementKind = elementType.getKind(); + final int headerSize = HotSpotGraalRuntime.getArrayBaseOffset(elementKind); + int sizeOfElement = HotSpotGraalRuntime.runtime().getTarget().arch.getSizeInBytes(elementKind); + int alignment = HotSpotGraalRuntime.runtime().getTarget().wordSize; + int log2ElementSize = CodeUtil.log2(sizeOfElement); + return NewObjectSnippets.computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); + } + return lookupJavaType.instanceSize(); + } + } else { + return constant.getKind().getByteCount(); + } + } }