interface support now turned off by default for stability reasons, esp. on larger projects.

This commit is contained in:
Erik Ostermueller 2016-06-12 14:49:01 -05:00
parent 831929f4dd
commit 8f8bdaa5ee
9 changed files with 149 additions and 24 deletions

View File

@ -423,6 +423,14 @@
<jvmarg value="-javaagent:build/jars/intrace-agent.jar=[instru-true" />
</java>
</target>
<target name="example3" depends="jar,example_build">
<java classname="example.InstrumentMeLaunch" fork="true">
<classpath>
<pathelement path="./build/test" />
</classpath>
<jvmarg value="-javaagent:build/jars/intrace-agent.jar=[instru-true" />
</java>
</target>
<target name="waitexample" depends="jar,example_build">

View File

@ -40,6 +40,7 @@ private InstrCriteria classesToExclude = null;
private boolean instruEnabled = true;
private boolean saveTracedClassfiles = false;
private boolean verboseMode = false;
private boolean _instrumentImplementors = false;
@ -54,6 +55,7 @@ private InstrCriteria classesToExclude = null;
instruEnabled = oldInstance.isInstrumentationEnabled();
saveTracedClassfiles = oldInstance.saveTracedClassfiles();
verboseMode = oldInstance.isVerboseMode();
_instrumentImplementors = oldInstance.instrumentImplementors();
}
public AgentSettings(String args)
{
@ -138,8 +140,17 @@ public void parseArgs(String args)
this.classesToExclude = new InstrCriteria(classExcludeRegexStr);
this.classesToExclude.verboseLogger = this;
}
else if (arg.toLowerCase(Locale.ROOT).equals(
AgentConfigConstants.INSTRUMENT_IMPLEMENTORS
+ "true"))
{
this._instrumentImplementors = true;
}
}
public boolean instrumentImplementors() {
return _instrumentImplementors;
}
public boolean isWaitStart()
{
return waitStart;

View File

@ -21,6 +21,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.intrace.agent.server.AgentClientConnection;
import org.intrace.agent.server.AgentServer;
@ -51,11 +52,21 @@ public class ClassTransformer implements ClassFileTransformer
* Set of modified class names
*/
private final Set<ComparableClassName> modifiedClasses = new ConcurrentSkipListSet<ComparableClassName>();
/**
* Javadoc and stacktraces show that ConcurrentSkipListSet.size() takes up large amount of time.
* This variable will be used to store count.
*/
private final AtomicInteger modifiedClassesCount = new AtomicInteger();
/**
* Map of all seen class names
*/
private final Set<ComparableClassName> allClasses = new ConcurrentSkipListSet<ComparableClassName>();
/**
* Javadoc and stacktraces show that ConcurrentSkipListSet.size() takes up large amount of time.
* This variable will be used to store count.
*/
private final AtomicInteger allClassesCount = new AtomicInteger();
/**
* Instrumentation interface.
@ -90,6 +101,8 @@ public class ClassTransformer implements ClassFileTransformer
{
TraceHandler.INSTANCE.writeTraceOutput("DEBUG: " + settings.toString());
}
this.allClassesCount.set(0);
this.modifiedClassesCount.set(0);
}
/**
@ -110,6 +123,7 @@ public class ClassTransformer implements ClassFileTransformer
ClassAnalysis analysis = new ClassAnalysis();
cr.accept(analysis, 0);
//System.out.println("getInstrumentedClassBytes [" + xiClassName + "]");
InstrumentedClassWriter writer = new InstrumentedClassWriter(xiClassName,
cr, analysis,
shouldInstrument,
@ -152,11 +166,13 @@ public class ClassTransformer implements ClassFileTransformer
ProtectionDomain protectionDomain,
byte[] originalClassfile)
{
// System.out.println("itbcfi [" + className + "] klass [" + klass.getName() + "] protectionDomain [" + protectionDomain + "]");
ComparableClassName compklass = new ComparableClassName(className,
klassloader);
// Record all class names which get this far
allClasses.add(compklass);
allClassesCount.incrementAndGet();
// Don't modify anything if tracing is disabled
if (!settings.isInstrumentationEnabled())
@ -201,13 +217,15 @@ public class ClassTransformer implements ClassFileTransformer
{
// Actually we should modify if any of the interfaces match the regex
boolean matchedInterface = false;
for(String klassInterface : getInterfaces(className, originalClassfile))
{
if ((settings.getClassRegex() != null)
&& matches(settings.getClassRegex(), klassInterface))
{
matchedInterface |= true;
}
if (originalClassfile !=null && settings.instrumentImplementors() ) {
for(String klassInterface : getInterfaces(className, originalClassfile))
{
if ((settings.getClassRegex() != null)
&& matches(settings.getClassRegex(), klassInterface))
{
matchedInterface |= true;
}
}
}
if(!matchedInterface)
@ -300,8 +318,8 @@ public class ClassTransformer implements ClassFileTransformer
{
String className = internalClassName.replace('/', '.');
ComparableClassName compclass = new ComparableClassName(className, loader);
int modifiedSize = modifiedClasses.size();
int allClassesSize = allClasses.size();
int modifiedSize = modifiedClassesCount.get();
int allClassesSize = allClassesCount.get();
boolean shouldInstrument = isToBeConsideredForInstrumentation(classBeingRedefined, loader,
className, protectionDomain,
@ -342,6 +360,7 @@ public class ClassTransformer implements ClassFileTransformer
}
modifiedClasses.add(compclass);
modifiedClassesCount.getAndIncrement();
sendStatusUpdate(modifiedSize, allClassesSize);
@ -350,6 +369,7 @@ public class ClassTransformer implements ClassFileTransformer
else
{
modifiedClasses.remove(compclass);
modifiedClassesCount.decrementAndGet();
sendStatusUpdate(modifiedSize, allClassesSize);
return null;
@ -409,13 +429,13 @@ public class ClassTransformer implements ClassFileTransformer
try
{
StatusUpdate update = statusHolder.getStatus();
int newModifiedSize = modifiedClasses.size();
int newAllClassesSize = allClasses.size();
int newModifiedSize = modifiedClassesCount.get();
int newAllClassesSize = allClassesCount.get();
if (!bulkUpdateActive.get() &&
((newModifiedSize != update.modifiedSize) ||
(newAllClassesSize != update.allClassesSize)))
{
broadcastStatus(modifiedClasses.size(), allClasses.size());
broadcastStatus(modifiedClassesCount.get(), allClassesCount.get());
}
}
catch (InterruptedException e)
@ -524,9 +544,9 @@ public class ClassTransformer implements ClassFileTransformer
{
Map<String, String> settingsMap = settings.getSettingsMap();
settingsMap.put(AgentConfigConstants.STCLS,
Integer.toString(allClasses.size()));
Integer.toString(allClassesCount.get()));
settingsMap.put(AgentConfigConstants.STINST,
Integer.toString(modifiedClasses.size()));
Integer.toString(modifiedClassesCount.get()));
return settingsMap;
}
@ -551,12 +571,12 @@ public class ClassTransformer implements ClassFileTransformer
else if (oldSettings.isInstrumentationEnabled() != settings
.isInstrumentationEnabled())
{
// System.out.println("## Settings Changed");
//System.out.println("## Settings Changed");
setInstrumentationEnabled(settings.isInstrumentationEnabled());
}
else if (!Arrays.equals(oldSettings.getClassRegex(), settings.getClassRegex()))
{
// System.out.println("## Settings Changed");
//System.out.println("## Settings Changed");
Set<ComparableClass> klasses = new HashSet<ComparableClass>(getModifiedClasses());
modifiedClasses.clear();
klasses.addAll(getLoadedClassesForModification());
@ -564,7 +584,7 @@ public class ClassTransformer implements ClassFileTransformer
}
else if (!Arrays.equals(oldSettings.getExcludeClassRegex(), settings.getExcludeClassRegex()))
{
// System.out.println("## Settings Changed");
//System.out.println("## Settings Changed");
Set<ComparableClass> klasses = new HashSet<ComparableClass>(getModifiedClasses());
modifiedClasses.clear();
klasses.addAll(getLoadedClassesForModification());
@ -573,7 +593,7 @@ public class ClassTransformer implements ClassFileTransformer
else if (oldSettings.saveTracedClassfiles() != settings
.saveTracedClassfiles())
{
// System.out.println("## Settings Changed");
//System.out.println("## Settings Changed");
Set<ComparableClass> klasses = getModifiedClasses();
modifiedClasses.clear();
klasses.addAll(getLoadedClassesForModification());
@ -656,7 +676,12 @@ public class ClassTransformer implements ClassFileTransformer
+ loadedClass.getCanonicalName());
}
}
else
else if (settings.instrumentImplementors() || isToBeConsideredForInstrumentation(
loadedClass,
loadedClass.getClassLoader(),
loadedClass.getName(),
loadedClass.getProtectionDomain(),
null ))
{
ComparableClass loadedKlass = new ComparableClass(loadedClass);
unmodifiedKlasses.add(loadedKlass);
@ -665,6 +690,18 @@ public class ClassTransformer implements ClassFileTransformer
return unmodifiedKlasses;
}
/*
The catch block in this method should have caught the following, but it did not.
Need to figure out why.
<pre>
[java] java.lang.VerifyError
[java] at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
[java] at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:144)
[java] at org.intrace.agent.ClassTransformer.instrumentKlasses(ClassTransformer.java:719)
[java] at org.intrace.agent.ClassTransformer.getResponse(ClassTransformer.java:584)
[java] at org.intrace.agent.server.AgentClientConnection.runMethod(AgentClientConnection.java:118)
</pre>
*/
public void instrumentKlasses(Set<ComparableClass> klasses)
{
if (!inst.isRetransformClassesSupported())
@ -692,10 +729,10 @@ public class ClassTransformer implements ClassFileTransformer
inst.retransformClasses(klass.klass);
countNumClasses++;
if ((countNumClasses % 100) == 0)
{
// if ((countNumClasses % 100) == 0)
// {
broadcastProgress(countNumClasses, totalNumClasses);
}
// }
}
catch (Throwable e)
{
@ -711,7 +748,7 @@ public class ClassTransformer implements ClassFileTransformer
finally
{
bulkUpdateActive.set(false);
broadcastStatus(modifiedClasses.size(), allClasses.size());
broadcastStatus(modifiedClasses.size(), allClassesCount.get());
}
}

View File

@ -79,6 +79,7 @@ public class InstrumentedClassWriter extends ClassWriter
sb.append(InstrCriteria.CLASS_METHOD_DELIMITER);
sb.append(name);
sb.append(desc);
//System.out.println("@#%:" + sb.toString() );
TraceHandler.INSTANCE.writeTraceOutput("DEBUG: method signature: " + sb.toString());
}
MethodVisitor mv = super.visitMethod(access, name, desc, signature,

View File

@ -472,7 +472,7 @@ private static final Object STACK_ELE_DELIM = ",";
+ "]:" + xiOutput;
// if (AgentHelper.getOutputSettings().isStdoutOutputEnabled())
// {
//// System.out.println(traceString);
// System.out.println(traceString);
// }
if (AgentHelper.getOutputSettings().isFileOutputEnabled())

View File

@ -24,6 +24,7 @@ public class AgentConfigConstants
public static final String OPT_SERVER_PORT = "[serverport-";
public static final String CALLBACK_PORT = "[callbackport-";
public static final String EXIT_STACK_TRACE = "[exit-stack-trace-";
public static final String INSTRUMENT_IMPLEMENTORS = "[instrument-implementors";
public static final String START_WAIT = "[startwait";
public static final String START_ACTIVATE = "[startactivate";
@ -39,5 +40,6 @@ public class AgentConfigConstants
COMMANDS.add(OPT_SERVER_PORT + "<int>");
COMMANDS.add(CALLBACK_PORT + "<int>");
COMMANDS.add(EXIT_STACK_TRACE + "<true/false>");
COMMANDS.add(INSTRUMENT_IMPLEMENTORS + "<true/false>");
}
}

View File

@ -0,0 +1,20 @@
package example;
import java.util.Arrays;
public class InstrumentMe implements Runnable
{
private byte myField = 1;
@Override
public void run()
{
byteArg((byte) 0);
}
private void byteArg(byte arg)
{
this.myField = arg;
}
}

View File

@ -0,0 +1,27 @@
package example;
public class InstrumentMeLaunch
{
public static void main(String args[]) throws Exception {
System.out.println("Currently running sample code in background thread.");
System.out.println("Make sure this program has -javaagent:./path/to/intrace-agent.jar on its command line.");
System.out.println("Start InTrace GUI, download-able at https://mchr3k.github.io/org.intrace/");
System.out.println("'Connect' & then configure GUI to trace any of these patterns:\n\n");
System.out.println("example.InstrumentMe -- to trace all methods in class example.InstrumentMe");
System.out.println("example.InstrumentMe -- to trace all methods in class example.InstrumentMeLaunch");
System.out.println("example.InstrumentMe#<init>()V -- to trace this single method.");
System.out.println("example.InstrumentMe#run()V -- to trace this single method.");
System.out.println("example.InstrumentMe#byteArg(B)V -- to trace this single method.");
System.out.println("example.InstrumentMeLaunch#<init>()V -- to trace this single method.");
System.out.println("example.InstrumentMeLaunch#main([Ljava/lang/String;)V -- to trace this single method.\n\n");
System.out.println("Press Ctrl+C to quit this program.");
Runnable r = new InstrumentMe();
while(true) {
System.out.println("About to start thread.");
new Thread(r).start();
Thread.sleep(2000);
}
}
}

View File

@ -64,6 +64,25 @@ public class AgentSettingsTest extends TestCase
assertEquals(settingsMap.get(AgentConfigConstants.VERBOSE_MODE), "true");
}
public void testInstrumentImplementorsSetting() {
AgentSettings as1 = new AgentSettings(
AgentConfigConstants.INSTRUMENT_IMPLEMENTORS
+ "true"
);
assertTrue( "unable to recognize parameter that instruments implementors of interfaces", as1.instrumentImplementors() );
AgentSettings as2 = new AgentSettings(
AgentConfigConstants.INSTRUMENT_IMPLEMENTORS
+ "false"
);
assertFalse( "unable to recognize parameter that instruments implementors of interfaces",as2.instrumentImplementors() );
AgentSettings as3 = new AgentSettings("");
assertFalse( "unable to recognize parameter that instruments implementors of interfaces", as3.instrumentImplementors() );
}
public void testInstrCriteria() {
InstrCriteria ic = new InstrCriteria("foo|bar");