/*
* Distributable under LGPL license. See terms of license at gnu.org.
*/
package org.jboss.profiler.jvmtitest;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.WeakHashMap;
import junit.framework.TestCase;
import org.jboss.profiler.jvmti.InventoryDataPoint;
import org.jboss.profiler.jvmti.JVMTICallBack;
import org.jboss.profiler.jvmti.JVMTIInterface;
import org.jboss.profiler.jvmti.ReferenceDataPoint;
import org.jboss.profiler.memoryprofiler.engine.MemorySnapshotController;
import org.jboss.profiler.memoryprofiler.engine.MemorySnapshotEngine;
import org.jboss.profiler.memoryprofiler.model.MemoryClass;
class B
{
}
class Dummy
{
String a;
String b;
B b12 = null;
String c;
static B staticB ;
}
class A extends Dummy
{
public A()
{
b = new B();
staticB=b;
}
B b;
B b1 = null;
String str = null;
}
class Holder
{
int count = 0;
UsedByHolder[] objs = new UsedByHolder[100000];
public void addInstance(UsedByHolder obj)
{
objs[count++] = obj;
}
public void print()
{
for (int i = 0; i < count; i++)
{
System.out.println("class=" + objs[i].toString());
}
}
}
class UsedByHolder
{
int x;
static int count = 0;
public UsedByHolder()
{
x = count++;
}
public String toString()
{
return "value " + x;
}
}
/**
* To run this test, you need to use -agentlib:jbossAgent in you IDE
* @author Clebert Suconic
*/
public class JVMTITest extends TestCase
{
static class LocalCallbackTestOnClasses implements JVMTICallBack
{
int count=0;
public void notifyReference(long referenceHolder, long referencedObject, long classTag, long index, long method, byte referenceType) {
fail("Shouldn't be called");
}
public void notifyClass(long classTag, Class clazz) {
count++;
}
public void notifyObject(long classTag, long objectId, long bytes) {
fail("Shouldn't be called");
}
}
static class LocalCallbackTestOnObjects implements JVMTICallBack
{
int count=0;
public void notifyReference(long referenceHolder, long referencedObject, long classTag, long index, long method, byte referenceType) {
fail("Shouldn't be called");
}
public void notifyClass(long classTag, Class clazz) {
fail("Shouldn't be called");
}
public void notifyObject(long classTag, long objectId, long bytes) {
count++;
}
}
public void testNotifyOnClasses()
{
JVMTIInterface jvmti = new JVMTIInterface();
LocalCallbackTestOnClasses localTest = new LocalCallbackTestOnClasses();
jvmti.notifyInventory(true,null,null,localTest);
assertEquals(jvmti.getLoadedClasses().length,localTest.count);
}
public void testInventoryReport() throws Exception
{
JVMTIInterface jvmti = new JVMTIInterface();
System.out.println(jvmti.inventoryReport());
}
public void testProduceInventoryMinimal() throws Exception
{
JVMTIInterface jvmti = new JVMTIInterface(); // The JVMTIWrapper used to produce inventories
Map map = jvmti.produceInventory();
Map map2 = jvmti.produceInventory();
assertTrue( jvmti.compareInventories(System.out,map,map2,null,null,null));
}
public void testProduceInventory() throws Exception
{
class TestClass
{
}
JVMTIInterface jvmti = new JVMTIInterface(); // The JVMTIWrapper used to produce inventories
Map map = jvmti.produceInventory();
Map map2 = jvmti.produceInventory();
jvmti.compareInventories(System.out,map,map2,null,null,null);
System.out.println("size=" + map.size());
map=null;
map2=null;
TestClass keepr = new TestClass(); // at least one instance, so point2 won't be null
Map firstMap = jvmti.produceInventory(); // The inventory of classes, this is HashMap<Class,InventoryDataPoint>
TestClass [] tests = new TestClass[1000];
for (int i=0;i<1000;i++)
{
tests[i] = new TestClass(); // allocating 1000 objects
}
Map secondMap = jvmti.produceInventory(); // the second inventory
InventoryDataPoint point1 = (InventoryDataPoint)secondMap.get(TestClass.class);
InventoryDataPoint point2 = (InventoryDataPoint)firstMap.get(TestClass.class);
assertEquals(1000,point1.getInstances()-point2.getInstances()); // you can manually compare it
assertTrue(jvmti.compareInventories(System.out,firstMap,secondMap,new Class[]{WeakHashMap.class},new String[]{"[Ljava.util.WeakHashMap$Entry;","java.lang.ref"}, new InventoryDataPoint[]{new InventoryDataPoint(TestClass.class,2000)}));
assertFalse(jvmti.compareInventories(System.out,firstMap,secondMap,new Class[]{WeakHashMap.class},new String[]{"[Ljava.util.WeakHashMap$Entry;","java.lang.ref"}, new InventoryDataPoint[]{new InventoryDataPoint(TestClass.class,100)}));
}
public void testExploreObject() throws Exception
{
A a = new A();
B b = a.b;
JVMTIInterface jvmti = new JVMTIInterface();
HashMap map = jvmti.createIndexMatrix();
jvmti.exploreClassReferences(B.class.getName(),-1,true,true,true,true,false,map);
System.out.println(jvmti.exploreObjectReferences(map,b,1,true));
/*map=null;
jvmti.releaseTags();
System.out.println(jvmti.exploreObjectReferences(B.class.getName(),2,true)); */
}
public void notestNotify()
{
A a = new A();
B b = a.b;
final ArrayList list = new ArrayList();
JVMTIInterface jvmti = new JVMTIInterface();
jvmti.notifyOnReferences("/tmp/tst.refs",new JVMTICallBack(){
int count=0;
public void notifyReference(long referenceHolder, long referencedObject,long classTag, long index, long method, byte referenceType)
{
list.add(new ReferenceDataPoint(referenceHolder, referencedObject,classTag, index, method, referenceType));
}
public void notifyClass(long classTag, Class clazz) {
fail("This shouldn't be called now");
}
public void notifyObject(long classTag, long objectId, long bytes) {
fail("This shouldn't be called now");
}
});
long tag = jvmti.getTagOnObject(a);
Object newObject = jvmti.getObjectOnTag(tag);
assertSame(a,newObject);
int count=0;
Iterator iter = list.iterator();
while (iter.hasNext())
{
ReferenceDataPoint point = (ReferenceDataPoint)iter.next();
//System.out.println("point=" + point);
if (point.getClassTag()!=0 )
{
Object obj = jvmti.getObjectOnTag(point.getClassTag());
if (!(obj instanceof Class))
{
System.out.println("point=" + point);
System.out.println("obj=" + obj);
fail("Object was supposed to be a Class");
}
}
if (point.getReferenceType()==JVMTICallBack.JVMTI_REFERENCE_STATIC_FIELD || point.getReferenceType()==JVMTICallBack.JVMTI_REFERENCE_FIELD)
{
try
{
Object referenced = jvmti.getObjectOnTag(point.getReferencedObject());
Object obj = jvmti.getObjectOnTag(point.getReferenceHolder());
Field field = jvmti.getObjectField(obj .getClass(),(int)point.getIndex());
Class clazz = (Class)jvmti.getObjectOnTag(point.getClassTag());
/*if (field==null)
{
System.out.println(point);
System.out.println(referenced + " couldn't find field " +point.getIndex() + " on " + obj);
Field field2 = jvmti.getObjectField(obj .getClass(),(int)point.getIndex());
}
assertNotNull(field); -- I would like to enforce this, but it seems impossible due to internal classes on JVM */
}
catch (NullPointerException e)
{
}
}
else if (point.getReferenceType()==JVMTICallBack.THREAD_REFERENCE)
{
try
{
Object classTag = jvmti.getObjectOnTag(point.getClassTag());
Object objReferenced = jvmti.getObjectOnTag(point.getReferencedObject());
Object objHolder = jvmti.getObjectOnTag(point.getReferenceHolder());
String methodName= jvmti.getMethodClass(point.getMethod()).getName() + "::" +
jvmti.getMethodName(point.getMethod()) + jvmti.getMethodSignature(point.getMethod());
//System.out.println(objReferenced + " being referenced at "+methodName);
}
catch (NullPointerException e)
{
// this can happen here;
}
}
}
System.out.println();
long tagOnA = jvmti.getTagOnObject(a.b);
iter = list.iterator();
while (iter.hasNext())
{
ReferenceDataPoint point = (ReferenceDataPoint)iter.next();
if (tagOnA == point.getReferencedObject() && (point.getReferenceType()==JVMTICallBack.JVMTI_REFERENCE_FIELD || point.getReferenceType()==JVMTICallBack.JVMTI_REFERENCE_STATIC_FIELD))
{
Object obj = jvmti.getObjectOnTag(point.getReferenceHolder());
Field field = null;
if (point.getReferenceType()==JVMTICallBack.JVMTI_REFERENCE_FIELD)
{
field = jvmti.getObjectField((Class)obj.getClass() ,(int)point.getIndex());
}
else
{
field = jvmti.getObjectField((Class)obj ,(int)point.getIndex());
}
System.out.println(obj + " being referenced at " + field);
}
else if (tagOnA == point.getReferencedObject() && (point.getReferenceType()==JVMTICallBack.THREAD_REFERENCE))
{
Object classTag = jvmti.getObjectOnTag(point.getClassTag());
Object objReferenced = jvmti.getObjectOnTag(point.getReferencedObject());
Object objHolder = jvmti.getObjectOnTag(point.getReferenceHolder());
System.out.println("classTag=" + classTag);
System.out.println("objReferenced=" + objReferenced);
System.out.println("objHolder=" + objHolder);
System.out.println("name=" +jvmti.getMethodClass(point.getMethod()).getName() + "::" +
jvmti.getMethodName(point.getMethod()) + jvmti.getMethodSignature(point.getMethod()));
}
}
try
{
jvmti.getObjectOnTag(0);
fail("Supposed to throw an exception");
}
catch (Throwable e)
{
}
try
{
jvmti.getObjectOnTag(-1);
fail("Supposed to throw an exception");
}
catch (Throwable e)
{
}
jvmti.releaseTags();
assertEquals(0,jvmti.getTagOnObject(a));
}
public void testGetReferenceHolders()
{
JVMTIInterface jvmti = new JVMTIInterface();
A a = new A();
Object[] objects = jvmti.getReferenceHolders(new Object[]{a.b});
assertEquals(2,objects.length);
assertSame(a,objects[0]);
}
public void testGetObjects()
{
JVMTIInterface interfaceJVMTI = new JVMTIInterface();
Object[] result = interfaceJVMTI.getAllObjects(java.lang.String.class);
for (int i = 0; i < result.length; i++)
{
System.out.println("String result[" + i + "]=" + result[i]);
}
result = interfaceJVMTI.getAllObjects(java.lang.Class.class);
assertTrue(result.length>0);
for (int i = 0; i < result.length; i++)
{
System.out.println("class result[" + i + "]=" + result[i]);
}
}
ThreadLocal local = new ThreadLocal();
static Holder holder[] = new Holder[100];
static
{
for (int i=0;i<holder.length;i++)
{
holder[i] = new Holder();
}
}
public void testHolders() throws Exception
{
JVMTIInterface interfaceJVMTI = new JVMTIInterface();
Object holders[] = interfaceJVMTI.getReferenceHolders(new Object[]{this});
System.out.println("There are " + holders.length + " holding a reference");
}
public void testNavigation() throws Exception
{
JVMTIInterface interfaceJVMTI = new JVMTIInterface();
Class classes[] = interfaceJVMTI.getLoadedClasses();
System.out.println("length=" + classes.length);
ArrayList stringVer = new ArrayList();
stringVer.add(new String("tst"));
try
{
Thread.sleep(1000);
} catch (Exception e)
{
e.printStackTrace();
}
Holder holder = new Holder();
holder.addInstance(new UsedByHolder());
holder.addInstance(new UsedByHolder());
Holder holder2 = new Holder();
holder2.addInstance(new UsedByHolder());
holder2.addInstance(new UsedByHolder());
Holder holder3 = new Holder();
holder3=null;
local.set(holder3);
JVMTIInterface jvmti = new JVMTIInterface();
jvmti.forceGC();
//File tmpFile = File.createTempFile("profiler","");
File tmpFile = new File("tst","");
System.out.println("Generating data to " + tmpFile.getAbsolutePath());
jvmti.heapSnapshot(tmpFile.getAbsolutePath(), "log");
holder.print();
holder2.print();
MemorySnapshotEngine engine = new MemorySnapshotEngine();
engine.processFiles(tmpFile.getAbsolutePath(),"log");
MemorySnapshotController controller = new MemorySnapshotController(engine);
Collection coll = controller.filterRoots(false);
Iterator iter = coll.iterator();
int i=0;
while (iter.hasNext())
{
MemoryClass clazz = (MemoryClass)iter.next();
if ((i++)==1)
{
Collection collResult = controller.summarizeReferenceByPath(true,new String[]{"C" + clazz.getId()});
//assertTrue(collResult.size()>0);
}
if (clazz.getClassLoaderId()!=0)
{
Collection collClassLoader = controller.solveLoadedClass(clazz.getClassLoaderId(),false);
}
}
}
public static void main(String arg[])
{
JVMTITest test = new JVMTITest();
try
{
test.testGetObjects();
} catch (Throwable e1)
{
e1.printStackTrace();
}
try
{
test.testNavigation();
} catch (Throwable e)
{
e.printStackTrace();
}
}
}