Day: March 18, 2008
Technikgeschichte: J. Weizenbaum über den Alptraum Computer (1972) | ZEIT online
heise online – IP-Verwechslung führt zu falschem Kinderporno-Verdacht
Eclipse Test & Performance Tools Platform Project troubles
After using TPTP for about a half year for my bachelor I am at a point where I would remove it. But I don’t have to decide it. I reported so far 6 bugs. Everyone of them detains me on profiling. I can create single traces but if I repeat tracing I am in trouble. JVM crashes, 100% CPU usages and so on. I have now written my own “profiler” two classes that give me the covered lines back of a profiled program. It uses the Java debugging interface (JDI).
The first class is called Agent that starts a event catcher thread (the debugging agent) if it is called without any arguments. This debugging agent waits for a connecting JVM. With a argument it calls a sample method to test profiling. You have to supply the debugging agent port and host like -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:55555. The other class is EventCatcherThread which enables the single step event and waits for a connecting JVM to profile a program. Only 278 lines of java code are necessary.
Agent.java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import com.sun.jdi.connect.VMStartException;
public class Agent {
private ArrayList<String> _linesPassed = new ArrayList<String>();
public void addSourceCodeLine() {
_linesPassed.add("bla");
}
public List<String> getLinesPassed() {
return _linesPassed;
}
public static void debug() throws Exception {
List<String> passedLine = new ArrayList<String>();
EventCatcherThread eventThread = EventCatcherThread.connectToVm(55555);
eventThread.setPassedCodeLines(passedLine);
eventThread.start();
eventThread.resumeVM();
eventThread.join();
for (Iterator<String> iterator = passedLine.iterator(); iterator
.hasNext();) {
String lineKey = (String) iterator.next();
System.out.println(lineKey);
}
}
public static void main(String[] args) throws Exception,
IllegalConnectorArgumentsException, VMStartException {
if (args.length != 0) {
debug();
} else {
Agent agent = new Agent();
agent.traceTest();
}
}
public void traceTest() {
String string = new String();
string = string + " fdgvdf ";
string = string.concat("bla");
System.out.println(string);
}
}
EventCatcherThread.java
package org.projectory.ezunit;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jdi.Bootstrap;
import com.sun.jdi.AbsentInformationException;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.VMDisconnectedException;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import com.sun.jdi.connect.Connector.Argument;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.EventIterator;
import com.sun.jdi.event.EventQueue;
import com.sun.jdi.event.EventSet;
import com.sun.jdi.event.StepEvent;
import com.sun.jdi.event.VMDeathEvent;
import com.sun.jdi.event.VMDisconnectEvent;
import com.sun.jdi.event.VMStartEvent;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.EventRequestManager;
import com.sun.jdi.request.StepRequest;
public class EventCatcherThread extends Thread {
private final VirtualMachine _vm;
private String[] _excludes;
private boolean _connected = true;
private String[] _includes;
private Map<String, Location> _lineStat = new HashMap<String, Location>();
private List<String> _passedCodeLines;
EventCatcherThread(VirtualMachine vm, String[] excludes, String[] includes) {
super("event-handler");
_vm = vm;
_excludes = excludes;
_includes = includes;
}
public void run() {
EventQueue queue = _vm.eventQueue();
List<ThreadReference> allThreads = _vm.allThreads();
for (ThreadReference thread : allThreads) {
if (thread.uniqueID() == 1) {
enableSingleStepEvent(thread);
}
}
while (_connected) {
try {
EventSet eventSet = queue.remove();
EventIterator it = eventSet.eventIterator();
while (it.hasNext()) {
Event nextEvent = it.nextEvent();
handleEvent(nextEvent);
}
eventSet.resume();
} catch (InterruptedException exc) {
// Ignore
} catch (VMDisconnectedException discExc) {
handleDisconnectedException();
break;
}
}
}
private void enableSingleStepEvent(ThreadReference thread) {
EventRequestManager mgr = _vm.eventRequestManager();
StepRequest req = mgr.createStepRequest(thread, StepRequest.STEP_LINE,
StepRequest.STEP_INTO);
req.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
for (int i = 0; i < _excludes.length; ++i) {
req.addClassExclusionFilter(_excludes[i]);
}
for (int i = 0; i < _includes.length; ++i) {
req.addClassFilter(_includes[i]);
}
req.enable();
}
private void singleStepEvent(StepEvent event) {
if (_passedCodeLines != null) {
try {
final String sourcePath = event.location().sourcePath();
final int lineNumber = event.location().lineNumber();
final String method = event.location().method().toString();
final String lineKey = sourcePath + ":" + method + ":" + lineNumber;
if (_lineStat.containsKey(lineKey)) {
Location location = _lineStat.get(lineKey);
location.countCall();
} else {
Location location = new Location(sourcePath, method, lineNumber);
location.countCall();
_lineStat.put(lineKey, location);
}
if (!_passedCodeLines.contains(lineKey)) {
_passedCodeLines.add(lineKey);
}
} catch (AbsentInformationException e) {
e.printStackTrace();
}
} else {
System.err
.println("Cannot set line numbers, because the container is null!");
}
}
/**
* Dispatch incoming events
*/
private void handleEvent(Event event) {
if (event instanceof StepEvent) {
singleStepEvent((StepEvent) event);
} else if (event instanceof VMStartEvent) {
vmStartEvent((VMStartEvent) event);
} else if (event instanceof VMDisconnectEvent) {
vmDisconnectEvent((VMDisconnectEvent) event);
} else if (event instanceof VMDeathEvent) {
// application exit
} else {
System.out.println("Unhandled event type: " + event.getClass());
}
}
private void handleDisconnectedException() {
EventQueue queue = _vm.eventQueue();
while (_connected) {
try {
EventSet eventSet = queue.remove();
EventIterator iter = eventSet.eventIterator();
while (iter.hasNext()) {
Event event = iter.nextEvent();
if (event instanceof VMDisconnectEvent) {
vmDisconnectEvent((VMDisconnectEvent) event);
}
}
eventSet.resume();
} catch (InterruptedException exc) {
// ignore
}
}
}
/**
* Enable the SingleStepEvent if the VM was started in suspend mode.
* @param event
*/
private void vmStartEvent(VMStartEvent event) {
EventRequestManager mgr = _vm.eventRequestManager();
StepRequest req = mgr.createStepRequest(event.thread(),
StepRequest.STEP_LINE, StepRequest.STEP_INTO);
req.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
for (int i = 0; i < _excludes.length; ++i) {
req.addClassExclusionFilter(_excludes[i]);
}
for (int i = 0; i < _includes.length; ++i) {
req.addClassFilter(_includes[i]);
}
req.enable();
}
private void vmDisconnectEvent(VMDisconnectEvent event) {
_connected = false;
}
@SuppressWarnings("unchecked")
public static EventCatcherThread connectToVm(int port) throws Error,
IOException, InterruptedException,
IllegalConnectorArgumentsException {
AttachingConnector c = getConnector();
Map<String, Argument> arguments = c.defaultArguments();
Argument portArg = arguments.get("port");
portArg.setValue("" + port);
// FIXME: localhost doesn't work
Argument hostArg = arguments.get("hostname");
hostArg.setValue("elaste");
VirtualMachine myVM = c.attach(arguments);
myVM.setDebugTraceMode(0);
final String[] excludes = { "org.hibernate.*", "net.sf.cglib.*",
"org.junit.*", "java.*", "javax.*", "sun.*", "com.sun.*" };
final String[] includes = { };
EventCatcherThread eventThread = new EventCatcherThread(myVM, excludes,
includes);
return eventThread;
}
private static AttachingConnector getConnector() {
AttachingConnector result = null;
List<AttachingConnector> allConnectors = Bootstrap
.virtualMachineManager().attachingConnectors();
if (allConnectors.size() > 0) {
result = allConnectors.get(0);
}
return result;
}
public void resumeVM() {
_vm.resume();
}
public List<String> getPassedCodeLines() {
return _passedCodeLines;
}
public void setPassedCodeLines(List<String> codeLines) {
_passedCodeLines = codeLines;
}
public Location getLineStat(String lineKey) {
return _lineStat.get(lineKey);
}
}