As I wrote in my earlier post, I am running OpenSolaris - Nevada
build 38 on my laptop [And Venky promptly
pasted "I boot OpenSolaris" sticker on it
]. With Nevada, there
is a Java API for
DTrace.
I thought of playing with this API (/usr/share/lib/java/javadoc/dtrace/html/fast.html)
There are simple Java examples under /usr/share/lib/java/javadoc/dtrace/examples.
But, these days I prefer to do exploratory programming
with JavaScript that is bundled in Java SE 6
- particularly if I'm going to write a simple class with just the main method!.
The DTrace Java API has the notion of "consumers" - think of consumer as a particular DTrace session. With a consumer, you register one or more "listeners" and then compile one or more D-scripts. Wait for events in your listener after calling "go" on the consumer...
File: test.js
// import package org.opensolaris.os.dtrace
importPackage(org.opensolaris.os.dtrace);
// create a LocalConsumer
var consumer = new LocalConsumer();
/*
* Register a callback listener. The listener is of the interface
* type org.opensolaris.os.dtrace.ConsumerListener. But, in JavaScript
* we can pass a function and that will be wrapped as interface!
*/
consumer.addConsumerListener(function (evt) {
// if we get probe data, then print it
if (evt instanceof DataEvent) {
println(evt.probeData);
}
});
// open consumer, no special options passed
consumer.open([]);
/*
* Note that jrunscript passed "arguments" array that has command
* line arguments to the current JavaScript.
*
* We take the first command line argument as D-script file to use
* and pass the remaining arguments are passed as macro arguments
* (which can be accessed as $1, $2... in the D-script)
*/
// Compile the D-script file
consumer.compile(new java.io.File(arguments(0), arguments.slice(1));
// enable the consumer
consumer.enable();
// "start" the consumer so that we get notifications in the
// callback registered above
consumer.go();
To run the above script, I used the following command line:
jrunscript -cp /usr/share/lib/java/dtrace.jar -f test.js hello.d
Note that I've put dtrace.jar in the classpath. "hello.d" is the D-script passed as first argument.
File: hello.d:
:::BEGIN {
trace("hello, world");
exit(0);
}
When we run the above script, "hello, world" is printed as expected. How about accessing DTrace aggregates? Consider the following simple D-script that populates an aggregate.
File: histo.d
// object-alloc probe is fired whenever a Java object is allocated
hotspot$1:::object-alloc {
// arg1 for this probe is name of the Java class
// whose object is being allocated
// arg2 is length of the class name string
self->str = (string) copyin(arg1, arg2);
self->str[arg2] = '\0';
// arg3 is size of the object being allocated
// We update an aggregate whose key is the class name
// and the value is total size of objects allocated so far.
@histo[(string) self->str] = sum(arg3);
}
How about a script that prints the above histogram once every second? I copied "test.js" to "histo.js" and added the following lines:
File: histo.js
// same code as in "test.js" followed by these lines..
var a;
do {
java.lang.Thread.sleep(1000);
// get all aggregations from consumer
a = consumer.aggregate;
if (! a.asMap().empty()) {
// get "histo" aggregation
var histo = a.getAggregation("histo");
// get iterator of AggregationRecords
var itr = histo.records.iterator();
while (itr.hasNext()) {
var rec = itr.next();
// in our aggreation, the key tuple has only one component
// - the class name.
println(rec.tuple.get(0) + '\t' + rec.value);
}
}
println("===========================================");
} while (consumer.isRunning());
To enable object-alloc probe, we have to start your Java application
with -XX:+ExtendedDTraceProbes flag. I started the Java2D demo
application (bundled with JDK) with the following command line:
java -XX:+ExtendedDTraceProbes $JDK_HOME/demo/jfc/Java2D/Java2Demo.jar
Then, I ran the above "histo.js" script with the following command line:
jrunscript -cp /usr/share/lib/java/dtrace.jar -f histo.js histo.d 790
where 790 is the process id above mentioned Java2D demo app. (Note: you can find process ids of all your Java apps using jps).
Of course, it is not much fun in just printing the histogram by JavaScript
- you may as well do the same with D-script itself. But, you may want to
show histogram in a fancy GUI or do some "client side" post-processing
of trace data and so on. You can write such programs using DTrace
Java API in Java or
any of the scripting
languages for the Java Platform. With languages that support
UNIX shell style heredocs
(for example,
Groovy, Jython)
it is easier to embed D-script as a string and use
Consumer.compile(String program, String... args) that accepts
D-script as a String rather than file. But, what if you don't want to
code but visualize using DTrace? You may want to check out
Chime!