« December 2009
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today
XML

Blog::Navigation

GetJava Download Button
Get the Source
Personal Blog

Blog::Referers

Today's Page Hits: 1091

Powered by Roller Weblogger.
« doesNotUnderstand in... | Main | JSR-223 script engin... »
20060814 Monday August 14, 2006

Using DTrace Java API

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!

References



( Aug 14 2006, 01:44:09 PM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

Comments:

Post a Comment:

Comments are closed for this entry.
Copyright (C) 2005, A. Sundararajan's Weblog