Skip to content
Browse files

Some updates to the memory introspection tool.

git-svn-id: https://svn.neo4j.org/laboratory/users/tobias/deepintrospect@7161 0b971d98-bb2f-0410-8247-b05b2b5feb2a
  • Loading branch information...
1 parent cdf7b21 commit f3325259820814ac992e473558c764a4c429ae61 @thobe committed Nov 23, 2010
View
1 build
View
8 pom.xml
@@ -16,13 +16,13 @@
<groupId>org.neo4j</groupId>
<artifactId>neo4j-kernel</artifactId>
<version>1.2-SNAPSHOT</version>
- <scope>provided</scope>
+ <!--scope>provided</scope-->
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-management</artifactId>
<version>1.2-SNAPSHOT</version>
- <scope>provided</scope>
+ <!--scope>provided</scope-->
</dependency>
<dependency>
<groupId>junit</groupId>
@@ -39,8 +39,8 @@
<configuration>
<archive>
<manifestEntries>
- <Premain-Class>org.neo4j.deepintrospect.IntrospectorImpl</Premain-Class>
- <Agent-Class>org.neo4j.deepintrospect.IntrospectorImpl</Agent-Class>
+ <Premain-Class>org.neo4j.deepintrospect.InspectAgent</Premain-Class>
+ <Agent-Class>org.neo4j.deepintrospect.InspectAgent</Agent-Class>
</manifestEntries>
</archive>
</configuration>
View
5 rebuild
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+cd `dirname $0`
+
+mvn clean package dependency:copy-dependencies -Dmaven.javadoc.skip=true
View
5 run
@@ -8,6 +8,7 @@ while [ -L "$EXE" ]; do
done
LIBDIR=$(cd `dirname $EXE`; pwd)
+JAR=$LIBDIR/target/deep-java-introspection-0.1-SNAPSHOT.jar
#cd `dirname $EXE`
@@ -27,5 +28,5 @@ LIBDIR=$(cd `dirname $EXE`; pwd)
# -Dexec.args="-agentpath:'`pwd`/target/native/libdeep-java-introspection.jnilib' -cp %classpath:$WORKDIR/build $*"
java -d64 -agentpath:"$LIBDIR/target/native/libdeep-java-introspection.jnilib"\
- -cp $LIBDIR/target/dependency/\*:$LIBDIR/target/classes:$WORKDIR/build\
- -ea:org.neo4j.memtest -Xmx1024m "$@"
+ -javaagent:$JAR -cp $LIBDIR/target/dependency/\*:$JAR:$WORKDIR/build\
+ -Xmx1024m "$@"
View
58 src/main/java/org/neo4j/deepintrospect/InspectAgent.java
@@ -0,0 +1,58 @@
+package org.neo4j.deepintrospect;
+
+import java.lang.instrument.Instrumentation;
+import java.lang.reflect.Field;
+
+@SuppressWarnings( "restriction" )
+class InspectAgent
+{
+ public static void premain( String agentArguments, Instrumentation instrumentation )
+ {
+ agentmain( agentArguments, instrumentation );
+ }
+
+ public static void agentmain( String agentArguments, Instrumentation instrumentation )
+ {
+ if ( instrumentation != null ) InspectAgent.instrumentation = instrumentation;
+ }
+
+ private static volatile Instrumentation instrumentation;
+
+ static long sizeOf( Object obj )
+ {
+ Instrumentation inst = instrumentation;
+ return inst == null ? 0 : inst.getObjectSize( obj );
+ }
+
+ private static final sun.misc.Unsafe unsafe;
+ static
+ {
+ sun.misc.Unsafe theUnsafe = null;
+ try
+ {
+ theUnsafe = sun.misc.Unsafe.getUnsafe();
+ }
+ catch ( Throwable retry )
+ {
+ try
+ {
+ Field UNSAFE = sun.misc.Unsafe.class.getDeclaredField( "theUnsafe" );
+ UNSAFE.setAccessible( true );
+ theUnsafe = (sun.misc.Unsafe) UNSAFE.get( null );
+ }
+ catch ( Throwable fail )
+ {
+ }
+ }
+ finally
+ {
+ unsafe = theUnsafe;
+ }
+ }
+
+ static long offset( Field field )
+ {
+ if ( unsafe == null ) return -1;
+ return unsafe.objectFieldOffset( field );
+ }
+}
View
4 src/main/java/org/neo4j/deepintrospect/Introspector.java
@@ -12,5 +12,9 @@
String computeRelCacheSize( String className );
+ String getCachedNodeSize( long id );
+
+ String getCachedRelationshipSize( long id );
+
// String getObjectSize( Class<?> type );
}
View
36 src/main/java/org/neo4j/deepintrospect/IntrospectorImpl.java
@@ -1,11 +1,11 @@
package org.neo4j.deepintrospect;
-import java.lang.instrument.Instrumentation;
import java.lang.reflect.Field;
import javax.management.NotCompliantMBeanException;
import org.neo4j.kernel.KernelExtension.KernelData;
+import org.neo4j.kernel.impl.cache.Cache;
import org.neo4j.kernel.impl.core.NodeManager;
import org.neo4j.management.impl.ManagementBeanProvider;
import org.neo4j.management.impl.Neo4jMBean;
@@ -22,17 +22,18 @@
REL_IMPL = getClass( "org.neo4j.kernel.impl.core.RelationshipImpl" );
}
- private final Object nodeCache, relCache;
+ private final Cache<Integer, ?> nodeCache, relCache;
+ @SuppressWarnings( "unchecked" )
IntrospectorImpl( ManagementBeanProvider provider, KernelData kernel )
throws NotCompliantMBeanException
{
super( provider, kernel );
NodeManager nm = kernel.getConfig().getGraphDbModule().getNodeManager();
try
{
- nodeCache = NODE_CACHE.get( nm );
- relCache = REL_CACHE.get( nm );
+ nodeCache = (Cache<Integer, ?>) NODE_CACHE.get( nm );
+ relCache = (Cache<Integer, ?>) REL_CACHE.get( nm );
}
catch ( Exception e )
{
@@ -67,19 +68,6 @@ private static Field nmField( String name )
}
}
- public static void premain( String agentArguments, Instrumentation instrumentation )
- {
- agentmain( agentArguments, instrumentation );
- }
-
- public static void agentmain( String agentArguments, Instrumentation instrumentation )
- {
- if ( instrumentation != null ) IntrospectorImpl.instrumentation = instrumentation;
- }
-
- private static volatile Instrumentation instrumentation;
- private static final ToolingInterface tooling = ToolingInterface.getInstance();
-
public String getNodeCacheSize()
{
return nodeCacheSize( NODE_IMPL );
@@ -102,12 +90,22 @@ public String computeRelCacheSize( String className )
private String nodeCacheSize( Class<?> payloadLimit )
{
- return tooling.getTransitiveSize( nodeCache, payloadLimit ).toString();
+ return ToolingInterface.instance().getTransitiveSize( nodeCache, payloadLimit ).toString();
}
private String relCacheSize( Class<?> payloadLimit )
{
- return tooling.getTransitiveSize( relCache, payloadLimit ).toString();
+ return ToolingInterface.instance().getTransitiveSize( relCache, payloadLimit ).toString();
+ }
+
+ public String getCachedNodeSize( long id )
+ {
+ return ToolingInterface.instance().getTransitiveSize( nodeCache.get( (int) id ), NODE_IMPL ).toString();
+ }
+
+ public String getCachedRelationshipSize( long id )
+ {
+ return ToolingInterface.instance().getTransitiveSize( relCache.get( (int) id ), REL_IMPL ).toString();
}
/*
View
119 src/main/java/org/neo4j/deepintrospect/SizeCount.java
@@ -1,26 +1,121 @@
package org.neo4j.deepintrospect;
-class SizeCount
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.neo4j.kernel.impl.util.ArrayMap;
+
+public class SizeCount
{
- final long size;
- final long count;
- final long objSize;
- final long objCount;
+ private final long totSize;
+ private final long totCount;
+ private final long tagSize;
+ private final long tagCount;
+ private final long objCount;
+ private final List<String> objectSizes = new ArrayList<String>();
- SizeCount( long size, long count, long objSize, long objCount )
+ SizeCount( long totSize, long totCount, long tagSize, long tagCount, long objCount )
{
- this.size = size;
- this.count = count;
- this.objSize = objSize;
+ this.totSize = totSize;
+ this.totCount = totCount;
+ this.tagSize = tagSize;
+ this.tagCount = tagCount;
this.objCount = objCount;
}
+ void specSize( Object obj, long size, long count )
+ {
+ Class<?> type = obj.getClass();
+ StringBuilder repr;
+ if ( type.isArray() )
+ {
+ int depth;
+ for ( depth = 0; type.isArray(); depth++ )
+ type = type.getComponentType();
+ repr = new StringBuilder( type.isPrimitive() ? type.getSimpleName() : type.getName() );
+ for ( ; depth > 1; depth-- )
+ repr.append( "[]" );
+ repr.append( "[" );
+ repr.append( Array.getLength( obj ) );
+ repr.append( "]" );
+ }
+ else
+ {
+ repr = new StringBuilder( obj.getClass().getName() );
+ if ( obj instanceof String )
+ {
+ repr.append( " length=" );
+ repr.append( Integer.toString( ( (String) obj ).length() ) );
+ }
+ else if ( obj instanceof Collection<?> )
+ {
+ repr.append( " size=" );
+ repr.append( Integer.toString( ( (Collection<?>) obj ).size() ) );
+ }
+ else if ( obj instanceof Map<?, ?> )
+ {
+ repr.append( " size=" );
+ repr.append( Integer.toString( ( (Map<?, ?>) obj ).size() ) );
+ }
+ else if ( obj instanceof ArrayMap<?, ?> )
+ {
+ repr.append( " size=" );
+ repr.append( Integer.toString( ( (ArrayMap<?, ?>) obj ).size() ) );
+ }
+ }
+ long objSize = InspectAgent.sizeOf( obj );
+ if ( objSize == 0 )
+ {
+ repr.append( " [Object size unknown] " );
+ }
+ else
+ {
+ repr.append( " " );
+ repr.append( format( objSize ) );
+ if ( count != 0 ) repr.append( " + " );
+ }
+ if ( count != 0 )
+ {
+ repr.append( format( size ) );
+ repr.append( " in " );
+ repr.append( Long.toString( count ) );
+ repr.append( " referenced objects" );
+ }
+ objectSizes.add( repr.toString() );
+ }
+
@Override
public String toString()
{
- return String.format( "total: %s, payload objects: %s, overhead: %s",
- format( size, count ), format( objSize, objCount ), format( size - objSize,
- count - objCount ) );
+ StringBuilder result;
+ if ( totCount == tagCount )
+ {
+ result = new StringBuilder( format( tagSize, tagCount, objCount ) );
+ }
+ else
+ {
+ result = new StringBuilder( String.format(
+ "\n total: %s\n payload: %s\n overhead: %s",//
+ format( totSize, totCount ), format( tagSize, tagCount, objCount ),//
+ format( totSize - tagSize, totCount - tagCount ) ) );
+ }
+ if ( !objectSizes.isEmpty() )
+ {
+ result.append( "\n Objects:" );
+ for ( String size : objectSizes )
+ {
+ result.append( "\n " + size );
+ }
+ }
+ return result.toString();
+ }
+
+ private static String format( long size, long count, long elementCount )
+ {
+ return format( size ) + " (in " + count + " objects, " + elementCount + " elements)";
}
private static String format( long size, long count )
View
20 src/main/java/org/neo4j/deepintrospect/ToolingInterface.java
@@ -1,8 +1,10 @@
package org.neo4j.deepintrospect;
-final class ToolingInterface
+import java.lang.reflect.Field;
+
+public final class ToolingInterface
{
- static ToolingInterface getInstance()
+ public static ToolingInterface instance()
{
if ( isAvailable )
{
@@ -14,14 +16,22 @@ static ToolingInterface getInstance()
}
}
- native SizeCount getTransitiveSize( Object obj, Class<?> type );
-
- // native SizeCount getSizeOfAll( Class<?> type );
+ public native SizeCount getTransitiveSize( Object obj, Class<?> type );
private ToolingInterface()
{
}
+ public long sizeOf( Object obj )
+ {
+ return InspectAgent.sizeOf( obj );
+ }
+
+ long getOffset( Field field )
+ {
+ return InspectAgent.offset( field );
+ }
+
private static native boolean setupNative( String options );
private static final String NATIVE_LIBRARY_NAME = "deep-java-introspection";
View
88 src/main/native/tooli.c
@@ -135,9 +135,10 @@ Java_org_neo4j_deepintrospect_ToolingInterface_setupNative
}
typedef struct {
- jlong size;
- jlong count;
- jlong obj_total;
+ jlong tot_size;
+ jlong tot_count;
+ jlong tag_size;
+ jlong tag_count;
jlong obj_count;
} InstanceCounter;
@@ -150,15 +151,18 @@ jvmtiIterationControl JNICALL sum_object_sizes
reference_kind != JVMTI_REFERENCE_ARRAY_ELEMENT)
return JVMTI_ITERATION_IGNORE;
- ((InstanceCounter*)user_data)->size += size;
- ((InstanceCounter*)user_data)->count += 1;
+ ((InstanceCounter*)user_data)->tot_size += size;
+ ((InstanceCounter*)user_data)->tot_count += 1;
if (class_tag) {
- ((InstanceCounter*)user_data)->obj_total += size;
((InstanceCounter*)user_data)->obj_count += 1;
+
+ ((InstanceCounter*)user_data)->tag_size += size;
+ ((InstanceCounter*)user_data)->tag_count += 1;
(*tag_ptr) = class_tag;
} else if (referrer_tag) {
- ((InstanceCounter*)user_data)->obj_total += size;
+ ((InstanceCounter*)user_data)->tag_size += size;
+ ((InstanceCounter*)user_data)->tag_count += 1;
(*tag_ptr) = referrer_tag;
}
@@ -176,27 +180,77 @@ JNIEXPORT jobject JNICALL
Java_org_neo4j_deepintrospect_ToolingInterface_getTransitiveSize
(JNIEnv *env, jobject this, jobject obj, jclass type)
{
+ jlong TAG = 1;
jclass clazz;
- jmethodID init;
+ jmethodID method;
+ jobject java_result;
+ jobject* tagged_objects = NULL;
+ jint n_tagged_objects = 0;
+ int i;
+
InstanceCounter result;
- result.size = 0;
- result.count = 0;
- result.obj_total = 0;
+
+ if (obj == NULL) return NULL;
+
+ (*(globalData->jvmti))->GetObjectSize(globalData->jvmti,
+ obj, &(result.tot_size));
+ result.tot_count = 1;
+ result.tag_size = 0;
+ result.tag_count = 0;
result.obj_count = 0;
- (*(globalData->jvmti))->SetTag(globalData->jvmti, type, 1);
+ if (type != NULL) {
+ (*(globalData->jvmti))->SetTag(globalData->jvmti, type, TAG);
+ if ((*env)->IsInstanceOf(env, obj, type)) {
+ (*(globalData->jvmti))->SetTag(globalData->jvmti, obj, TAG);
+ result.tag_count = 1;
+ result.obj_count = 1;
+ result.tag_size = result.tot_size;
+ }
+ }
(*(globalData->jvmti))->IterateOverObjectsReachableFromObject(
globalData->jvmti, obj, &sum_object_sizes, (void*)&result );
+ if (type != NULL) {
+ (*(globalData->jvmti))->SetTag(globalData->jvmti, type, 0);
+ if ((*env)->IsInstanceOf(env, obj, type)) {
+ (*(globalData->jvmti))->GetObjectsWithTags(globalData->jvmti, 1, &TAG,
+ &n_tagged_objects,
+ &tagged_objects, NULL );
+ }
+ }
+
+ clazz = (*env)->FindClass(env, "org/neo4j/deepintrospect/SizeCount");
+ method = (*env)->GetMethodID(env, clazz, "<init>", "(JJJJJ)V");
+
+ java_result = (*env)->NewObject(env, clazz, method,
+ result.tot_size, result.tot_count,
+ result.tag_size, result.tag_count,
+ result.obj_count);
+
+ method = (*env)->GetMethodID(env,clazz,"specSize","(Ljava/lang/Object;JJ)V");
+
(*(globalData->jvmti))->IterateOverHeap(
globalData->jvmti, JVMTI_HEAP_OBJECT_TAGGED, clear_tag, NULL );
- (*(globalData->jvmti))->SetTag(globalData->jvmti, type, 0);
+ for ( i = 0; i < n_tagged_objects; i++ ) {
+ result.tot_size = 0;
+ result.tot_count = 0;
+ result.tag_size = 0;
+ result.tag_count = 0;
+ result.obj_count = 0;
- clazz = (*env)->FindClass(env, "org/neo4j/deepintrospect/SizeCount");
- init = (*env)->GetMethodID(env, clazz, "<init>", "(JJJJ)V");
+ (*(globalData->jvmti))->IterateOverObjectsReachableFromObject(
+ globalData->jvmti, tagged_objects[i], &sum_object_sizes, (void*)&result);
+
+ (*env)->CallVoidMethod(env, java_result, method, tagged_objects[i],
+ result.tot_size, result.tot_count);
+ }
+
+ if (tagged_objects)
+ (*(globalData->jvmti))->Deallocate( globalData->jvmti,
+ (unsigned char*)(void*)tagged_objects );
- return (*env)->NewObject(env, clazz, init, result.size, result.count,
- result.obj_total, result.obj_count);
+ return java_result;
}
View
83 src/test/java/org/neo4j/deepintrospect/Main.java
@@ -0,0 +1,83 @@
+package org.neo4j.deepintrospect;
+
+import java.lang.reflect.Field;
+
+public class Main
+{
+ private static class OneLong
+ {
+ long value;
+ }
+
+ private static class FourShorts
+ {
+ short value1, value2, value3, value4;
+ }
+
+ private static class OneIntAndTwoShorts
+ {
+ int value;
+ short value1, value2;
+ }
+
+ private static class BaseInt
+ {
+ int a;
+ }
+
+ private static class InheritedInt extends BaseInt
+ {
+ int b;
+ }
+
+ private static class PackedInt
+ {
+ int a, b;
+ }
+
+ private static class Ordered
+ {
+ int a;
+ int b;
+ Object l;
+ }
+
+ private static class Unordered
+ {
+ int a;
+ Object l;
+ int x;
+ }
+
+ public static void main( String[] args )
+ {
+ equals( new OneLong(), new FourShorts() );
+ equals( new OneLong(), new OneIntAndTwoShorts() );
+ equals( new InheritedInt(), new PackedInt() );
+ equals( new Ordered(), new Unordered() );
+ System.out.println( "Size of Empty string: "
+ + ToolingInterface.instance().getTransitiveSize( "", String.class ) );
+ for ( Class<?> type : Main.class.getDeclaredClasses() )
+ {
+ fieldOffsets( type );
+ }
+ }
+
+ private static void fieldOffsets( Class<?> type )
+ {
+ ToolingInterface tool = ToolingInterface.instance();
+ System.out.println( "Field offsets in " + type.getSimpleName() + ":" );
+ for ( Field field : type.getDeclaredFields() )
+ {
+ System.out.println( " " + field.getName() + ": " + tool.getOffset( field ) );
+ }
+ }
+
+ private static void equals( Object one, Object two )
+ {
+ ToolingInterface tool = ToolingInterface.instance();
+ long oneSize = tool.sizeOf( one ), twoSize = tool.sizeOf( two );
+ System.out.printf( "%s: %d %s= %s: %d\n", one.getClass().getSimpleName(), oneSize,
+ ( oneSize == twoSize ? '=' : '!' ), two.getClass().getSimpleName(), twoSize );
+ }
+}

0 comments on commit f332525

Please sign in to comment.
Something went wrong with that request. Please try again.