Current File : //usr/share/lib/java/javadoc/dtrace/html/fast.html
<!--
   Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
   Use is subject to license terms.

   ident	"%Z%%M%	%I%	%E% SMI"
-->
<html>
<head>
  <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
  <title>Quick Start Guide to the Java DTrace API</title>
</head>
<body>
<h1><a name="Quick_Start_Guide_to_the_Java_DTrace_API_"></a>Quick Start
Guide</h1>
<h1><small><small>to the</small> Java DTrace API</small></h1>
<hr style="width: 100%; height: 2px;">
<h2>Contents</h2>
<ul>
  <li><a href="#Hello_World">"hello, world" Example</a></li>
  <ul>
    <li><a href="#Writing_a_Simple_Consumer">Writing a Simple Consumer</a></li>
    <li><a href="#Running_hello.d_Script">Running the <tt>hello.d</tt>
	Script</a></li>
  </ul>
  <li><a href="#Aggregations">Aggregations</a></li>
  <li><a href="#Target_Process">Target Process ID</a></li>
  <li><a href="#Closing_Consumers">Closing Consumers</a></li>
  <li><a href="#Learning_DTrace">Learning More</a><br>
  </li>
</ul>
<h2><a name="Hello_World"></a>"hello, world" Example</h2>
To demonstrate how to use the Java DTrace API, let's write a simple Java
program that runs a D script, in this case <tt>hello.d</tt> (prints
"hello, world" and exits).  You will need root permission to use the
Java DTrace API (just as you do to use the <tt>dtrace(1M)</tt> command).
You may want to eliminate this inconvenience by adding the following
line to <tt>/etc/user_attr</tt>:
<br>
<br>
<tt><i>user-name</i>::::defaultpriv=basic,dtrace_kernel,dtrace_proc</tt>
<br>
<br>
<i>(Substitute your user name.)</i>  See the <a
href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidln0?a=view>
<b>Security</b></a> chapter of the <i>Solaris Dynamic Tracing Guide</i>
for more information.
<br>
<h4><a name="Writing_a_Simple_Consumer"></a>Writing a Simple Consumer</h4>
Creating a DTrace <a
href="../api/org/opensolaris/os/dtrace/Consumer.html">consumer</a>
is easy:
<pre><tt>
    Consumer consumer = new LocalConsumer();
</tt></pre>
<br>
Before you can do anything with the consumer, you must first open it.
Then you simply compile and enable one or more D programs and run it:
<pre><tt>
    consumer.open();
    consumer.compile(program);
    consumer.enable();
    consumer.go();	// runs in a background thread
</tt></pre>
<br>
To get the data generated by DTrace, you also need to add a <a
href="../api/org/opensolaris/os/dtrace/ConsumerListener.html">listener</a>:
<pre><tt>
    consumer.addConsumerListener(new ConsumerAdapter() {
	public void dataReceived(DataEvent e) {
	    System.out.println(e.getProbeData());
	}
    });
</tt></pre>
<br>
Here is a simple example that runs a given D script:<br>
<br>
<b>Java program (<a href="../examples/TestAPI.java">TestAPI.java</a>)</b>
<pre><tt><font color=#aaaaaa>
    import org.opensolaris.os.dtrace.*;
    import java.io.File;

    public class TestAPI {
	public static void
	main(String[] args)
	{
	    if (args.length &lt; 1) {
		System.err.println("Usage: java TestAPI &lt;script&gt; [ macroargs... ]");
		System.exit(2);
	    }

	    File file = new File(args[0]);
	    String[] macroArgs = new String[args.length - 1];
	    System.arraycopy(args, 1, macroArgs, 0, (args.length - 1));</font>
	
	    Consumer consumer = new LocalConsumer();
	    consumer.addConsumerListener(new ConsumerAdapter() {
		public void dataReceived(DataEvent e) {
		    System.out.println(e.getProbeData());
		}
	    });
<font color=#aaaaaa>
	    try {</font>
		consumer.open();
		consumer.compile(file, macroArgs);
		consumer.enable();
		consumer.go();<font color=#aaaaaa>
	    } catch (Exception e) {
		e.printStackTrace();
		System.exit(1);
	    }
	}
    }</font>
</tt></pre>
<br>
Compile the test program as follows:
<pre><tt>
    javac -cp /usr/share/lib/java/dtrace.jar TestAPI.java
</tt></pre>
<br>
<h4><a name="Running_hello.d_Script"></a>Running the <tt>hello.d</tt> Script</h4>
Now we need a D script for the program to run.  The following is a
simple example that prints "hello, world" and exits:<br>
<b>D script (<a href="../examples/hello.d">hello.d</a>)</b>
<pre><tt>
    dtrace:::BEGIN
    {
	    trace("hello, world");
	    exit(0);
    }
</tt></pre>
<br>
Run as follows:<br>
<pre><tt>
    java -cp .:/usr/share/lib/java/dtrace.jar TestAPI hello.d
</tt></pre>
<br>
The output should look like this:
<pre><tt>
    org.opensolaris.os.dtrace.ProbeData[epid = 1, cpu = 1,
    enabledProbeDescription = dtrace:::BEGIN, flow = null, records =
    ["hello, world", 0]]
</tt></pre>
<br>
There is one record in the <a
href="../api/org/opensolaris/os/dtrace/ProbeData.html"><tt>ProbeData</tt></a>
for each action in the D script.  The first record is generated by the
<tt>trace()</tt> action.  The second is generated by the <tt>exit()</tt>
action.  For prettier output, you could change the <tt>ConsumerAdapter <a
	href="../api/org/opensolaris/os/dtrace/ConsumerAdapter.html#dataReceived%28org.opensolaris.os.dtrace.DataEvent%29">dataReceived()</a></tt>
implementation as follows:
<pre><tt><font color=#aaaaaa>
    consumer.addConsumerListener(new ConsumerAdapter() {
	public void dataReceived(DataEvent e) {
	    // System.out.println(e.getProbeData());</font>
	    ProbeData data = e.getProbeData();
	    java.util.List &lt; Record &gt; records = data.getRecords();
	    for (Record r : records) {
		if (r instanceof ExitRecord) {
		} else {
		    System.out.println(r);
		}
	    }<font color=#aaaaaa>
	}
    });</font>
</tt></pre>
<br>
<h2><a name="Aggregations"></a>Aggregations</h2>
The example Java program can just as easily run a more complex script,
such as an aggregation:<br>
<b>D script (<a href="../examples/syscall.d">syscall.d</a>)</b>
<pre><tt>
    syscall:::entry
    / execname == $$1 /
    {
	    @[probefunc] = count();
    }

    profile:::tick-1sec
    {
	    printa(@);
	    clear(@);
    }
</tt></pre>
<br>
The above script uses the <tt>$$1</tt> macro variable as a placeholder
for whatever executable you'd like to trace.  See the <a
href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidliq?a=view><b>
Macro Arguments</b></a> section of the <b>Scripting</b> chapter of the
<i>Solaris Dynamic Tracing Guide</i>.  Using two dollar signs (<tt>$$1</tt>)
instead of one (<tt>$1</tt>) forces expansion of the macro variable to
type string.<br>
<br>
To run the example Java program using the above D script, you need to
specify an argument to the <tt>execname</tt> placeholder, such as
"java":<br>
<pre><tt>
    java -cp .:/usr/share/lib/java/dtrace.jar TestAPI syscall.d java
</tt></pre>
<br>
A data record generated by the <tt>printa()</tt> action is printed to
the console once every second.  It contains counts of system calls by
function name made by java.  No record is generated by the
<tt>clear()</tt> action.<br>
<br>
If you omit the argument to the <tt>execname</tt> placeholder, the
program fails to compile and the API throws the following exception:
<pre><tt>
    org.opensolaris.os.dtrace.DTraceException: failed to compile script
    syscall.d: line 2: macro argument $$1 is not defined
	at org.opensolaris.os.dtrace.LocalConsumer._compileFile(Native Method)
	at org.opensolaris.os.dtrace.LocalConsumer.compile(LocalConsumer.java:342)
	at TestAPI.main(TestAPI.java:26)
</tt></pre>
<br>
A DTrace script may have more than one aggregation.  In that case, each
aggregation needs a distinct name:<br>
<b>D script (<a href="../examples/intrstat.d">intrstat.d</a>)</b>
<pre><tt>
    sdt:::interrupt-start
    {
	    self-&gt;ts = vtimestamp;
    }

    sdt:::interrupt-complete
    / self-&gt;ts &amp;&amp; arg0 /
    {
	    this-&gt;devi = (struct dev_info *)arg0;
	    @counts[stringof(`devnamesp[this-&gt;devi-&gt;devi_major].dn_name),
		this-&gt;devi-&gt;devi_instance, cpu] = count();
	    @times[stringof(`devnamesp[this-&gt;devi-&gt;devi_major].dn_name),
		this-&gt;devi-&gt;devi_instance, cpu] = sum(vtimestamp - self-&gt;ts);
	    self-&gt;ts = 0;
    }
</tt></pre>
<br>
The <tt>@counts</tt> and <tt>@times</tt> aggregations both accumulate
values for each unique combination of device name, device instance, and
CPU (a three-element tuple).  In this example we drop the <tt>tick</tt>
probe to demonstrate a more convenient way to get aggregation data
without the use of the <tt>printa()</tt> action.  The <a
href="../api/org/opensolaris/os/dtrace/Consumer.html#getAggregate%28%29">
<tt>getAggregate()</tt></a> method allows us to get a read-consistent
snapshot of all aggregations at once on a programmatic interval.<br>
<b>Java program (<a href="../examples/TestAPI2.java">TestAPI2.java</a>)</b>
<pre><tt><font color=#aaaaaa>
    ...

    try {
	consumer.open();
	consumer.compile(file, macroArgs);
	consumer.enable();
	consumer.go();</font>

	Aggregate a;
	do {
	    Thread.sleep(1000); // 1 second
	    a = consumer.getAggregate();
	    if (!a.asMap().isEmpty()) {
		System.out.println(a);
	    }
	} while (consumer.isRunning());<font color=#aaaaaa>
    } catch (Exception e) {
	e.printStackTrace();
	System.exit(1);
    }

    ...</font>
</tt></pre>
<br>
Compile and run:
<pre><tt>
    javac -cp /usr/share/lib/java/dtrace.jar TestAPI2.java
</tt></pre>
<pre><tt>
    java -cp .:/usr/share/lib/java/dtrace.jar TestAPI2 intrstat.d
</tt></pre>
<br>
Try removing the <tt>tick</tt> probe from the <tt>syscall.d</tt> example
and running it again with the above modification (<tt>TestAPI2</tt>).<br>
<br>
By default, the requested aggregate includes every aggregation and
accumulates running totals.  To display values per time interval
(instead of running totals), clear the aggregations each time you call
<tt>getAggregate()</tt>.  Clearing an aggregation resets all counts to
zero without removing any elements.  The following modification to the
example above clears all aggregations:
<pre><tt><font color=#aaaaaa>
	    // a = consumer.getAggregate();</font>
	    a = consumer.getAggregate(null, null); // included, cleared
</tt></pre>
<br>
Each <tt>Set</tt> of aggregation names, <tt>included</tt> and
<tt>cleared</tt>, specifies <i>all</i> aggregations if <tt>null</tt> and
no aggregations if empty.  Any subset is possible.  However, if an
aggregation has ever been used in the <tt>printa()</tt> action, it is no
longer available to the <tt>getAggregate()</tt> method.<br>
<br>
Be aware that you cannot call <tt>getAggregate()</tt> on an interval
faster that the <tt>aggrate</tt> setting.  See the <a
href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidlis?a=view>
<b>Options and Tunables</b></a> chapter of the <i>Solaris Dynamic
Tracing Guide</i>.  See also the <a
href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidlhf?a=view>
<b>Minimizing Drops</b></a> section of the <b>Aggregations</b> chapter
for specific information about the <tt>aggrate</tt> option.  The default
<tt>aggrate</tt> is once per second.  Here's an example of how you might
double the <tt>aggrate</tt> to minimize drops:
<pre><tt>
    consumer.setOption(Option.aggrate, Option.millis(500)); // every half second
</tt></pre>
<br>
Even a single drop terminates the consumer unless you override the <a
href="../api/org/opensolaris/os/dtrace/ConsumerAdapter.html#dataDropped%28org.opensolaris.os.dtrace.DropEvent%29">
<tt>dataDropped()</tt></a> method of <tt>ConsumerAdapter</tt> to handle
drops differently.  To avoid drops, it is probably better to increase
the <tt>aggsize</tt> option, since increasing the <tt>aggrate</tt> makes
the consumer work harder.  In most cases, the <tt>aggrate</tt> should
only be increased when you need to update a display of aggregation data
more frequently than once per second.  Many runtime options, including
<tt>aggrate</tt>, can be changed dynamically while the consumer is
running.<br>
<br>
It's also worth mentioning that a D aggregation may omit square
brackets and aggregate only a single value:
<pre><tt>
    @total = count();
</tt></pre>
<br>
The resulting singleton <a
href="../api/org/opensolaris/os/dtrace/Aggregation.html">
<tt>Aggregation</tt></a> has one record that may be obtained as follows:
<pre><tt>
    Aggregate a = consumer.getAggregate();
    Aggregation total = a.getAggregation("total");
    AggregationRecord totalRecord = total.getRecord(Tuple.EMPTY);
</tt></pre>
<br>
<h2><a name="Target_Process"></a>Target Process ID</h2>
In addition to supporting macro arguments (see the <tt>syscall.d</tt>
aggregation example above), the Java DTrace API also supports the
<tt>$target</tt> macro variable.  (See the <a
href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidlir?a=view>
<b>Target Process ID</b></a> section of the <b>Scripting</b> chapter of
the <i>Solaris Dynamic Tracing Guide</i>.)  This allows you to trace a
process from the very beginning of its execution, rather than sometime
after you manually obtain its process ID.  The API does this by creating
a process that is initially suspended and allowed to start only after <a
href="../api/org/opensolaris/os/dtrace/Consumer.html#go%28%29">
<tt>go()</tt></a> has initiated tracing.  For example, you can aggregate
all the system calls from start to finish made by the <tt>date</tt>
command:<br>
<b>D script (<a href="../examples/target.d">target.d</a>)</b>
<pre><tt>
    syscall:::entry
    / pid == $target /
    {
	    @[probefunc] = count();
    }
</tt></pre>
<br>
A modified version of the <tt>TestAPI.java</tt> program adds the <a
href="../api/org/opensolaris/os/dtrace/Consumer.html#createProcess%28java.lang.String%29">
<tt>createProcess()</tt></a> call to execute the given command but
prevent it from starting until the consumer is running:<br>
<b>Java program (<a href="../examples/TestTarget.java">TestTarget.java</a>)</b>
<pre><tt><font color=#aaaaaa>
    ...
    consumer.open();</font>
    consumer.createProcess(command);<font color=#aaaaaa>
    consumer.compile(file);
    consumer.enable();
    consumer.go();
    ...</font>
</tt></pre>
<br>
It also overrides the <a
href="../api/org/opensolaris/os/dtrace/ConsumerAdapter.html#processStateChanged%28org.opensolaris.os.dtrace.ProcessEvent%29">
<tt>processStateChanged()</tt></a> method of the
<tt>ConsumerAdapter</tt> to print a notification when the process has
ended:
<pre><tt><font color=#aaaaaa>
    ...
    consumer.addConsumerListener(new ConsumerAdapter() {
	public void dataReceived(DataEvent e) {
	    System.out.println(e.getProbeData());
	}
	public void consumerStopped(ConsumerEvent e) {
	    try {
		Aggregate a = consumer.getAggregate();
		for (Aggregation agg : a.asMap().values()) {
		    for (AggregationRecord rec : agg.asMap().values()) {
			System.out.println(rec.getTuple() + " " +
				rec.getValue());
		    }
		}
	    } catch (Exception x) {
		x.printStackTrace();
		System.exit(1);
	    }
	    consumer.close();
	}</font>
	public void processStateChanged(ProcessEvent e) {
	    System.out.println(e.getProcessState());
	}<font color=#aaaaaa>
    });
    ...</font>
</tt></pre>
<br>
Compile and run:
<pre><tt>
    javac -cp /usr/share/lib/java/dtrace.jar TestTarget.java
</tt></pre>
<pre><tt>
    java -cp .:/usr/share/lib/java/dtrace.jar TestTarget target.d date
</tt></pre>
<br>
The consumer exits automatically when the target <tt>date</tt> process
completes.<br>
<h2><a name="Closing_Consumers"></a>Closing Consumers</h2>
An application using the Java DTrace API may run multiple consumers
simultaneously.  When a consumer stops running, the programmer is
responsible for closing it in order to release the system resources it
holds.  A consumer may stop running for any of the following reasons:
<ul>
  <li>It was stopped explicitly by a call to its <a
href=../api/org/opensolaris/os/dtrace/Consumer.html#stop()>
<tt>stop()</tt></a> method</li>
  <li>It encountered the <tt>exit()</tt> action</li>
  <li>Its <tt>$target</tt> process or processes (if any) all completed</li>
  <li>It encountered an exception</li>
</ul>
By default, an exception prints a stack trace to <tt>stderr</tt> before
notifying listeners that the consumer has stopped.  You can define
different behavior by setting an <a
href=../api/org/opensolaris/os/dtrace/ExceptionHandler.html>
<tt>ExceptionHandler</tt></a>, but the consumer is still stopped.<br>
<br>
The same listener that receives probe data generated by DTrace is also
notified when the consumer stops.  This is a good place to close the
consumer:
<pre><tt><font color=#aaaaaa>
    consumer.addConsumerListener(new ConsumerAdapter() {
	public void dataReceived(DataEvent e) {
	    System.out.println(e.getProbeData());
	}</font>
	public void consumerStopped(ConsumerEvent e) {
	    Consumer consumer = (Consumer)e.getSource();
		consumer.close();
	    }
	}<font color=#aaaaaa>
    });</font>
</tt></pre>
<br>
This releases the resources held by the consumer in all cases, i.e.
after it exits for <i>any</i> of the reasons listed above.<br>
<br>
You can request the last aggregate snapshot made by a stopped consumer,
as long as it has not yet been closed:
<pre><tt>
    Aggregate a = consumer.getAggregate();
</tt></pre>
<br>
Note however that any aggregation that has already appeared in a <a
href=../api/org/opensolaris/os/dtrace/PrintaRecord.html>
<tt>PrintaRecord</tt></a> as a result of the <tt>printa()</tt> action
action will not be included in the requested aggregate.
<h2><a name="Learning_DTrace"></a>Learning More</h2>
<br>
The <a href="http://www.opensolaris.org/os/community/dtrace/">
OpenSolaris DTrace page</a> has links to resources to help you learn
DTrace.  In particular, you should read the <a
href="http://docs.sun.com/app/docs/doc/817-6223"><i>Solaris Dynamic Tracing
    Guide</i></a>.<br>
<br>
Try the example Java programs on this page with other D scripts.  You
need not remove <tt>#!/usr/sbin/dtrace -s</tt> from the top of an
executable script.  You may want to remove <tt>profile:::tick*</tt>
clauses if you plan to use the <tt>Consumer</tt> <a
href="../api/org/opensolaris/os/dtrace/Consumer.html#getAggregate%28%29">
<tt>getAggregate()</tt></a> method and control the data interval
programmatically.  If the script uses the pre-compiler, you will need to
call the <tt>Consumer</tt> <a
href="../api/org/opensolaris/os/dtrace/Consumer.html#setOption%28java.lang.String%29">
<tt>setOption()</tt></a> method with the <a
href="../api/org/opensolaris/os/dtrace/Option.html#cpp">
<tt>Option.cpp</tt></a> argument.<br>
<br>
To quickly familiarize yourself with the Java DTrace API, take a look at
the overview <a href="JavaDTraceAPI.html">diagram</a>.<br>
<br>
<a href="#Quick_Start_Guide_to_the_Java_DTrace_API_">Back to top</a><br>
<br>
</body>
</html>