xref: /illumos-gate/usr/src/lib/libdtrace_jni/java/docs/html/fast.html (revision 3c30f56df862431210f98c7c8f13cf1362b9c574)
1<!--
2   Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3   Use is subject to license terms.
4
5   ident	"%Z%%M%	%I%	%E% SMI"
6
7   CDDL HEADER START
8
9   The contents of this file are subject to the terms of the
10   Common Development and Distribution License (the "License").
11   You may not use this file except in compliance with the License.
12
13   You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
14   or http://www.opensolaris.org/os/licensing.
15   See the License for the specific language governing permissions
16   and limitations under the License.
17
18   When distributing Covered Code, include this CDDL HEADER in each
19   file and include the License file at usr/src/OPENSOLARIS.LICENSE.
20   If applicable, add the following below this CDDL HEADER, with the
21   fields enclosed by brackets "[]" replaced with your own identifying
22   information: Portions Copyright [yyyy] [name of copyright owner]
23
24   CDDL HEADER END
25-->
26<html>
27<head>
28  <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
29  <title>Quick Start Guide to the Java DTrace API</title>
30</head>
31<body>
32<h1><a name="Quick_Start_Guide_to_the_Java_DTrace_API_"></a>Quick Start
33Guide</h1>
34<h1><small><small>to the</small> Java DTrace API</small></h1>
35<hr style="width: 100%; height: 2px;">
36<h2>Contents</h2>
37<ul>
38  <li><a href="#Hello_World">"hello, world" Example</a></li>
39  <ul>
40    <li><a href="#Writing_a_Simple_Consumer">Writing a Simple Consumer</a></li>
41    <li><a href="#Running_hello.d_Script">Running the <tt>hello.d</tt>
42	Script</a></li>
43  </ul>
44  <li><a href="#Aggregations">Aggregations</a></li>
45  <li><a href="#Target_Process">Target Process ID</a></li>
46  <li><a href="#Closing_Consumers">Closing Consumers</a></li>
47  <li><a href="#Learning_DTrace">Learning More</a><br>
48  </li>
49</ul>
50<h2><a name="Hello_World"></a>"hello, world" Example</h2>
51To demonstrate how to use the Java DTrace API, let's write a simple Java
52program that runs a D script, in this case <tt>hello.d</tt> (prints
53"hello, world" and exits).  You will need root permission to use the
54Java DTrace API (just as you do to use the <tt>dtrace(1M)</tt> command).
55You may want to eliminate this inconvenience by adding the following
56line to <tt>/etc/user_attr</tt>:
57<br>
58<br>
59<tt><i>user-name</i>::::defaultpriv=basic,dtrace_kernel,dtrace_proc</tt>
60<br>
61<br>
62<i>(Substitute your user name.)</i>  See the <a
63href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidln0?a=view>
64<b>Security</b></a> chapter of the <i>Solaris Dynamic Tracing Guide</i>
65for more information.
66<br>
67<h4><a name="Writing_a_Simple_Consumer"></a>Writing a Simple Consumer</h4>
68Creating a DTrace <a
69href="../api/org/opensolaris/os/dtrace/Consumer.html">consumer</a>
70is easy:
71<pre><tt>
72    Consumer consumer = new LocalConsumer();
73</tt></pre>
74<br>
75Before you can do anything with the consumer, you must first open it.
76Then you simply compile and enable one or more D programs and run it:
77<pre><tt>
78    consumer.open();
79    consumer.compile(program);
80    consumer.enable();
81    consumer.go();	// runs in a background thread
82</tt></pre>
83<br>
84To get the data generated by DTrace, you also need to add a <a
85href="../api/org/opensolaris/os/dtrace/ConsumerListener.html">listener</a>:
86<pre><tt>
87    consumer.addConsumerListener(new ConsumerAdapter() {
88	public void dataReceived(DataEvent e) {
89	    System.out.println(e.getProbeData());
90	}
91    });
92</tt></pre>
93<br>
94Here is a simple example that runs a given D script:<br>
95<br>
96<b>Java program (<a href="../examples/TestAPI.java">TestAPI.java</a>)</b>
97<pre><tt><font color=#aaaaaa>
98    import org.opensolaris.os.dtrace.*;
99    import java.io.File;
100
101    public class TestAPI {
102	public static void
103	main(String[] args)
104	{
105	    if (args.length &lt; 1) {
106		System.err.println("Usage: java TestAPI &lt;script&gt; [ macroargs... ]");
107		System.exit(2);
108	    }
109
110	    File file = new File(args[0]);
111	    String[] macroArgs = new String[args.length - 1];
112	    System.arraycopy(args, 1, macroArgs, 0, (args.length - 1));</font>
113
114	    Consumer consumer = new LocalConsumer();
115	    consumer.addConsumerListener(new ConsumerAdapter() {
116		public void dataReceived(DataEvent e) {
117		    System.out.println(e.getProbeData());
118		}
119	    });
120<font color=#aaaaaa>
121	    try {</font>
122		consumer.open();
123		consumer.compile(file, macroArgs);
124		consumer.enable();
125		consumer.go();<font color=#aaaaaa>
126	    } catch (Exception e) {
127		e.printStackTrace();
128		System.exit(1);
129	    }
130	}
131    }</font>
132</tt></pre>
133<br>
134Compile the test program as follows:
135<pre><tt>
136    javac -cp /usr/share/lib/java/dtrace.jar TestAPI.java
137</tt></pre>
138<br>
139<h4><a name="Running_hello.d_Script"></a>Running the <tt>hello.d</tt> Script</h4>
140Now we need a D script for the program to run.  The following is a
141simple example that prints "hello, world" and exits:<br>
142<b>D script (<a href="../examples/hello.d">hello.d</a>)</b>
143<pre><tt>
144    dtrace:::BEGIN
145    {
146	    trace("hello, world");
147	    exit(0);
148    }
149</tt></pre>
150<br>
151Run as follows:<br>
152<pre><tt>
153    java -cp .:/usr/share/lib/java/dtrace.jar TestAPI hello.d
154</tt></pre>
155<br>
156The output should look like this:
157<pre><tt>
158    org.opensolaris.os.dtrace.ProbeData[epid = 1, cpu = 1,
159    enabledProbeDescription = dtrace:::BEGIN, flow = null, records =
160    ["hello, world", 0]]
161</tt></pre>
162<br>
163There is one record in the <a
164href="../api/org/opensolaris/os/dtrace/ProbeData.html"><tt>ProbeData</tt></a>
165for each action in the D script.  The first record is generated by the
166<tt>trace()</tt> action.  The second is generated by the <tt>exit()</tt>
167action.  For prettier output, you could change the <tt>ConsumerAdapter <a
168	href="../api/org/opensolaris/os/dtrace/ConsumerAdapter.html#dataReceived%28org.opensolaris.os.dtrace.DataEvent%29">dataReceived()</a></tt>
169implementation as follows:
170<pre><tt><font color=#aaaaaa>
171    consumer.addConsumerListener(new ConsumerAdapter() {
172	public void dataReceived(DataEvent e) {
173	    // System.out.println(e.getProbeData());</font>
174	    ProbeData data = e.getProbeData();
175	    java.util.List &lt; Record &gt; records = data.getRecords();
176	    for (Record r : records) {
177		if (r instanceof ExitRecord) {
178		} else {
179		    System.out.println(r);
180		}
181	    }<font color=#aaaaaa>
182	}
183    });</font>
184</tt></pre>
185<br>
186<h2><a name="Aggregations"></a>Aggregations</h2>
187The example Java program can just as easily run a more complex script,
188such as an aggregation:<br>
189<b>D script (<a href="../examples/syscall.d">syscall.d</a>)</b>
190<pre><tt>
191    syscall:::entry
192    / execname == $$1 /
193    {
194	    @[probefunc] = count();
195    }
196
197    profile:::tick-1sec
198    {
199	    printa(@);
200	    clear(@);
201    }
202</tt></pre>
203<br>
204The above script uses the <tt>$$1</tt> macro variable as a placeholder
205for whatever executable you'd like to trace.  See the <a
206href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidliq?a=view><b>
207Macro Arguments</b></a> section of the <b>Scripting</b> chapter of the
208<i>Solaris Dynamic Tracing Guide</i>.  Using two dollar signs (<tt>$$1</tt>)
209instead of one (<tt>$1</tt>) forces expansion of the macro variable to
210type string.<br>
211<br>
212To run the example Java program using the above D script, you need to
213specify an argument to the <tt>execname</tt> placeholder, such as
214"java":<br>
215<pre><tt>
216    java -cp .:/usr/share/lib/java/dtrace.jar TestAPI syscall.d java
217</tt></pre>
218<br>
219A data record generated by the <tt>printa()</tt> action is printed to
220the console once every second.  It contains counts of system calls by
221function name made by java.  No record is generated by the
222<tt>clear()</tt> action.<br>
223<br>
224If you omit the argument to the <tt>execname</tt> placeholder, the
225program fails to compile and the API throws the following exception:
226<pre><tt>
227    org.opensolaris.os.dtrace.DTraceException: failed to compile script
228    syscall.d: line 2: macro argument $$1 is not defined
229	at org.opensolaris.os.dtrace.LocalConsumer._compileFile(Native Method)
230	at org.opensolaris.os.dtrace.LocalConsumer.compile(LocalConsumer.java:342)
231	at TestAPI.main(TestAPI.java:26)
232</tt></pre>
233<br>
234A DTrace script may have more than one aggregation.  In that case, each
235aggregation needs a distinct name:<br>
236<b>D script (<a href="../examples/intrstat.d">intrstat.d</a>)</b>
237<pre><tt>
238    sdt:::interrupt-start
239    {
240	    self-&gt;ts = vtimestamp;
241    }
242
243    sdt:::interrupt-complete
244    / self-&gt;ts &amp;&amp; arg0 /
245    {
246	    this-&gt;devi = (struct dev_info *)arg0;
247	    @counts[stringof(`devnamesp[this-&gt;devi-&gt;devi_major].dn_name),
248		this-&gt;devi-&gt;devi_instance, cpu] = count();
249	    @times[stringof(`devnamesp[this-&gt;devi-&gt;devi_major].dn_name),
250		this-&gt;devi-&gt;devi_instance, cpu] = sum(vtimestamp - self-&gt;ts);
251	    self-&gt;ts = 0;
252    }
253</tt></pre>
254<br>
255The <tt>@counts</tt> and <tt>@times</tt> aggregations both accumulate
256values for each unique combination of device name, device instance, and
257CPU (a three-element tuple).  In this example we drop the <tt>tick</tt>
258probe to demonstrate a more convenient way to get aggregation data
259without the use of the <tt>printa()</tt> action.  The <a
260href="../api/org/opensolaris/os/dtrace/Consumer.html#getAggregate%28%29">
261<tt>getAggregate()</tt></a> method allows us to get a read-consistent
262snapshot of all aggregations at once on a programmatic interval.<br>
263<b>Java program (<a href="../examples/TestAPI2.java">TestAPI2.java</a>)</b>
264<pre><tt><font color=#aaaaaa>
265    ...
266
267    try {
268	consumer.open();
269	consumer.compile(file, macroArgs);
270	consumer.enable();
271	consumer.go();</font>
272
273	Aggregate a;
274	do {
275	    Thread.sleep(1000); // 1 second
276	    a = consumer.getAggregate();
277	    if (!a.asMap().isEmpty()) {
278		System.out.println(a);
279	    }
280	} while (consumer.isRunning());<font color=#aaaaaa>
281    } catch (Exception e) {
282	e.printStackTrace();
283	System.exit(1);
284    }
285
286    ...</font>
287</tt></pre>
288<br>
289Compile and run:
290<pre><tt>
291    javac -cp /usr/share/lib/java/dtrace.jar TestAPI2.java
292</tt></pre>
293<pre><tt>
294    java -cp .:/usr/share/lib/java/dtrace.jar TestAPI2 intrstat.d
295</tt></pre>
296<br>
297Try removing the <tt>tick</tt> probe from the <tt>syscall.d</tt> example
298and running it again with the above modification (<tt>TestAPI2</tt>).<br>
299<br>
300By default, the requested aggregate includes every aggregation and
301accumulates running totals.  To display values per time interval
302(instead of running totals), clear the aggregations each time you call
303<tt>getAggregate()</tt>.  Clearing an aggregation resets all counts to
304zero without removing any elements.  The following modification to the
305example above clears all aggregations:
306<pre><tt><font color=#aaaaaa>
307	    // a = consumer.getAggregate();</font>
308	    a = consumer.getAggregate(null, null); // included, cleared
309</tt></pre>
310<br>
311Each <tt>Set</tt> of aggregation names, <tt>included</tt> and
312<tt>cleared</tt>, specifies <i>all</i> aggregations if <tt>null</tt> and
313no aggregations if empty.  Any subset is possible.  However, if an
314aggregation has ever been used in the <tt>printa()</tt> action, it is no
315longer available to the <tt>getAggregate()</tt> method.<br>
316<br>
317Be aware that you cannot call <tt>getAggregate()</tt> on an interval
318faster that the <tt>aggrate</tt> setting.  See the <a
319href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidlis?a=view>
320<b>Options and Tunables</b></a> chapter of the <i>Solaris Dynamic
321Tracing Guide</i>.  See also the <a
322href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidlhf?a=view>
323<b>Minimizing Drops</b></a> section of the <b>Aggregations</b> chapter
324for specific information about the <tt>aggrate</tt> option.  The default
325<tt>aggrate</tt> is once per second.  Here's an example of how you might
326double the <tt>aggrate</tt> to minimize drops:
327<pre><tt>
328    consumer.setOption(Option.aggrate, Option.millis(500)); // every half second
329</tt></pre>
330<br>
331Even a single drop terminates the consumer unless you override the <a
332href="../api/org/opensolaris/os/dtrace/ConsumerAdapter.html#dataDropped%28org.opensolaris.os.dtrace.DropEvent%29">
333<tt>dataDropped()</tt></a> method of <tt>ConsumerAdapter</tt> to handle
334drops differently.  To avoid drops, it is probably better to increase
335the <tt>aggsize</tt> option, since increasing the <tt>aggrate</tt> makes
336the consumer work harder.  In most cases, the <tt>aggrate</tt> should
337only be increased when you need to update a display of aggregation data
338more frequently than once per second.  Many runtime options, including
339<tt>aggrate</tt>, can be changed dynamically while the consumer is
340running.<br>
341<br>
342It's also worth mentioning that a D aggregation may omit square
343brackets and aggregate only a single value:
344<pre><tt>
345    @total = count();
346</tt></pre>
347<br>
348The resulting singleton <a
349href="../api/org/opensolaris/os/dtrace/Aggregation.html">
350<tt>Aggregation</tt></a> has one record that may be obtained as follows:
351<pre><tt>
352    Aggregate a = consumer.getAggregate();
353    Aggregation total = a.getAggregation("total");
354    AggregationRecord totalRecord = total.getRecord(Tuple.EMPTY);
355</tt></pre>
356<br>
357<h2><a name="Target_Process"></a>Target Process ID</h2>
358In addition to supporting macro arguments (see the <tt>syscall.d</tt>
359aggregation example above), the Java DTrace API also supports the
360<tt>$target</tt> macro variable.  (See the <a
361href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidlir?a=view>
362<b>Target Process ID</b></a> section of the <b>Scripting</b> chapter of
363the <i>Solaris Dynamic Tracing Guide</i>.)  This allows you to trace a
364process from the very beginning of its execution, rather than sometime
365after you manually obtain its process ID.  The API does this by creating
366a process that is initially suspended and allowed to start only after <a
367href="../api/org/opensolaris/os/dtrace/Consumer.html#go%28%29">
368<tt>go()</tt></a> has initiated tracing.  For example, you can aggregate
369all the system calls from start to finish made by the <tt>date</tt>
370command:<br>
371<b>D script (<a href="../examples/target.d">target.d</a>)</b>
372<pre><tt>
373    syscall:::entry
374    / pid == $target /
375    {
376	    @[probefunc] = count();
377    }
378</tt></pre>
379<br>
380A modified version of the <tt>TestAPI.java</tt> program adds the <a
381href="../api/org/opensolaris/os/dtrace/Consumer.html#createProcess%28java.lang.String%29">
382<tt>createProcess()</tt></a> call to execute the given command but
383prevent it from starting until the consumer is running:<br>
384<b>Java program (<a href="../examples/TestTarget.java">TestTarget.java</a>)</b>
385<pre><tt><font color=#aaaaaa>
386    ...
387    consumer.open();</font>
388    consumer.createProcess(command);<font color=#aaaaaa>
389    consumer.compile(file);
390    consumer.enable();
391    consumer.go();
392    ...</font>
393</tt></pre>
394<br>
395It also overrides the <a
396href="../api/org/opensolaris/os/dtrace/ConsumerAdapter.html#processStateChanged%28org.opensolaris.os.dtrace.ProcessEvent%29">
397<tt>processStateChanged()</tt></a> method of the
398<tt>ConsumerAdapter</tt> to print a notification when the process has
399ended:
400<pre><tt><font color=#aaaaaa>
401    ...
402    consumer.addConsumerListener(new ConsumerAdapter() {
403	public void dataReceived(DataEvent e) {
404	    System.out.println(e.getProbeData());
405	}
406	public void consumerStopped(ConsumerEvent e) {
407	    try {
408		Aggregate a = consumer.getAggregate();
409		for (Aggregation agg : a.asMap().values()) {
410		    for (AggregationRecord rec : agg.asMap().values()) {
411			System.out.println(rec.getTuple() + " " +
412				rec.getValue());
413		    }
414		}
415	    } catch (Exception x) {
416		x.printStackTrace();
417		System.exit(1);
418	    }
419	    consumer.close();
420	}</font>
421	public void processStateChanged(ProcessEvent e) {
422	    System.out.println(e.getProcessState());
423	}<font color=#aaaaaa>
424    });
425    ...</font>
426</tt></pre>
427<br>
428Compile and run:
429<pre><tt>
430    javac -cp /usr/share/lib/java/dtrace.jar TestTarget.java
431</tt></pre>
432<pre><tt>
433    java -cp .:/usr/share/lib/java/dtrace.jar TestTarget target.d date
434</tt></pre>
435<br>
436The consumer exits automatically when the target <tt>date</tt> process
437completes.<br>
438<h2><a name="Closing_Consumers"></a>Closing Consumers</h2>
439An application using the Java DTrace API may run multiple consumers
440simultaneously.  When a consumer stops running, the programmer is
441responsible for closing it in order to release the system resources it
442holds.  A consumer may stop running for any of the following reasons:
443<ul>
444  <li>It was stopped explicitly by a call to its <a
445href=../api/org/opensolaris/os/dtrace/Consumer.html#stop()>
446<tt>stop()</tt></a> method</li>
447  <li>It encountered the <tt>exit()</tt> action</li>
448  <li>Its <tt>$target</tt> process or processes (if any) all completed</li>
449  <li>It encountered an exception</li>
450</ul>
451By default, an exception prints a stack trace to <tt>stderr</tt> before
452notifying listeners that the consumer has stopped.  You can define
453different behavior by setting an <a
454href=../api/org/opensolaris/os/dtrace/ExceptionHandler.html>
455<tt>ExceptionHandler</tt></a>, but the consumer is still stopped.<br>
456<br>
457The same listener that receives probe data generated by DTrace is also
458notified when the consumer stops.  This is a good place to close the
459consumer:
460<pre><tt><font color=#aaaaaa>
461    consumer.addConsumerListener(new ConsumerAdapter() {
462	public void dataReceived(DataEvent e) {
463	    System.out.println(e.getProbeData());
464	}</font>
465	public void consumerStopped(ConsumerEvent e) {
466	    Consumer consumer = (Consumer)e.getSource();
467		consumer.close();
468	    }
469	}<font color=#aaaaaa>
470    });</font>
471</tt></pre>
472<br>
473This releases the resources held by the consumer in all cases, i.e.
474after it exits for <i>any</i> of the reasons listed above.<br>
475<br>
476You can request the last aggregate snapshot made by a stopped consumer,
477as long as it has not yet been closed:
478<pre><tt>
479    Aggregate a = consumer.getAggregate();
480</tt></pre>
481<br>
482Note however that any aggregation that has already appeared in a <a
483href=../api/org/opensolaris/os/dtrace/PrintaRecord.html>
484<tt>PrintaRecord</tt></a> as a result of the <tt>printa()</tt> action
485action will not be included in the requested aggregate.
486<h2><a name="Learning_DTrace"></a>Learning More</h2>
487<br>
488The <a href="http://www.opensolaris.org/os/community/dtrace/">
489OpenSolaris DTrace page</a> has links to resources to help you learn
490DTrace.  In particular, you should read the <a
491href="http://docs.sun.com/app/docs/doc/817-6223"><i>Solaris Dynamic Tracing
492    Guide</i></a>.<br>
493<br>
494Try the example Java programs on this page with other D scripts.  You
495need not remove <tt>#!/usr/sbin/dtrace -s</tt> from the top of an
496executable script.  You may want to remove <tt>profile:::tick*</tt>
497clauses if you plan to use the <tt>Consumer</tt> <a
498href="../api/org/opensolaris/os/dtrace/Consumer.html#getAggregate%28%29">
499<tt>getAggregate()</tt></a> method and control the data interval
500programmatically.  If the script uses the pre-compiler, you will need to
501call the <tt>Consumer</tt> <a
502href="../api/org/opensolaris/os/dtrace/Consumer.html#setOption%28java.lang.String%29">
503<tt>setOption()</tt></a> method with the <a
504href="../api/org/opensolaris/os/dtrace/Option.html#cpp">
505<tt>Option.cpp</tt></a> argument.<br>
506<br>
507To quickly familiarize yourself with the Java DTrace API, take a look at
508the overview <a href="JavaDTraceAPI.html">diagram</a>.<br>
509<br>
510<a href="#Quick_Start_Guide_to_the_Java_DTrace_API_">Back to top</a><br>
511<br>
512</body>
513</html>
514