xref: /illumos-gate/usr/src/lib/libdtrace_jni/java/docs/html/fast.html (revision 445f2479fe3d7435daab18bf2cdc310b86cd6738)
1<!--
2   Copyright 2006 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    java -cp 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>
152On i86:<br>
153<pre><tt>
154    java -cp .:dtrace.jar TestAPI hello.d
155</tt></pre>
156<br>
157On sparc you need to add the <tt>-d64</tt> option to java:
158<pre><tt>
159    java -d64 -cp .:dtrace.jar TestAPI hello.d</span><br>
160</tt></pre>
161<br>
162You may need to set <tt>LD_LIBRARY_PATH</tt> so that Java can find
163<tt>libdtrace_jni.so</tt> on your system.  The output should look like
164this:
165<pre><tt>
166    org.opensolaris.os.dtrace.ProbeData[epid = 1, cpu = 1,
167    enabledProbeDescription = dtrace:::BEGIN, flow = null, records =
168    ["hello, world", 0]]
169</tt></pre>
170<br>
171There is one record in the <a
172href="../api/org/opensolaris/os/dtrace/ProbeData.html"><tt>ProbeData</tt></a>
173for each action in the D script.  The first record is generated by the
174<tt>trace()</tt> action.  The second is generated by the <tt>exit()</tt>
175action.  For prettier output, you could change the <tt>ConsumerAdapter <a
176	href="../api/org/opensolaris/os/dtrace/ConsumerAdapter.html#dataReceived%28org.opensolaris.os.dtrace.DataEvent%29">dataReceived()</a></tt>
177implementation as follows:
178<pre><tt><font color=#aaaaaa>
179    consumer.addConsumerListener(new ConsumerAdapter() {
180	public void dataReceived(DataEvent e) {
181	    // System.out.println(e.getProbeData());</font>
182	    ProbeData data = e.getProbeData();
183	    java.util.List &lt; Record &gt; records = data.getRecords();
184	    for (Record r : records) {
185		if (r instanceof ExitRecord) {
186		} else {
187		    System.out.println(r);
188		}
189	    }<font color=#aaaaaa>
190	}
191    });</font>
192</tt></pre>
193<br>
194<h2><a name="Aggregations"></a>Aggregations</h2>
195The example Java program can just as easily run a more complex script,
196such as an aggregation:<br>
197<b>D script (<a href="../examples/syscall.d">syscall.d</a>)</b>
198<pre><tt>
199    syscall:::entry
200    / execname == $$1 /
201    {
202	    @[probefunc] = count();
203    }
204
205    profile:::tick-1sec
206    {
207	    printa(@);
208	    clear(@);
209    }
210</tt></pre>
211<br>
212The above script uses the <tt>$$1</tt> macro variable as a placeholder
213for whatever executable you'd like to trace.  See the <a
214href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidliq?a=view><b>
215Macro Arguments</b></a> section of the <b>Scripting</b> chapter of the
216<i>Solaris Dynamic Tracing Guide</i>.  Using two dollar signs (<tt>$$1</tt>)
217instead of one (<tt>$1</tt>) forces expansion of the macro variable to
218type string.<br>
219<br>
220To run the example Java program using the above D script, you need to
221specify an argument to the <tt>execname</tt> placeholder.  To be sure of
222getting output, let's use "java":<br>
223On i86:
224<pre><tt>
225    java -cp .:dtrace.jar TestAPI syscall.d java
226</tt></pre>
227<br>
228On sparc:
229<pre><tt>
230    java -d64 -cp .:dtrace.jar TestAPI syscall.d java
231</tt></pre>
232<br>
233A data record generated by the <tt>printa()</tt> action is printed to
234the console once every second.  It contains counts of system calls by
235function name made by java.  No record is generated by the
236<tt>clear()</tt> action.<br>
237<br>
238If you omit the argument to the <tt>execname</tt> placeholder, the
239program fails to compile and the API throws the following exception:
240<pre><tt>
241    org.opensolaris.os.dtrace.DTraceException: failed to compile script
242    syscall.d: line 2: macro argument $$1 is not defined
243	at org.opensolaris.os.dtrace.LocalConsumer._compileFile(Native Method)
244	at org.opensolaris.os.dtrace.LocalConsumer.compile(LocalConsumer.java:342)
245	at TestAPI.main(TestAPI.java:26)
246</tt></pre>
247<br>
248A DTrace script may have more than one aggregation.  In that case, each
249aggregation needs a distinct name:<br>
250<b>D script (<a href="../examples/intrstat.d">intrstat.d</a>)</b>
251<pre><tt>
252    sdt:::interrupt-start
253    {
254	    self-&gt;ts = vtimestamp;
255    }
256
257    sdt:::interrupt-complete
258    / self-&gt;ts &amp;&amp; arg0 /
259    {
260	    this-&gt;devi = (struct dev_info *)arg0;
261	    @counts[stringof(`devnamesp[this-&gt;devi-&gt;devi_major].dn_name),
262		this-&gt;devi-&gt;devi_instance, cpu] = count();
263	    @times[stringof(`devnamesp[this-&gt;devi-&gt;devi_major].dn_name),
264		this-&gt;devi-&gt;devi_instance, cpu] = sum(vtimestamp - self-&gt;ts);
265	    self-&gt;ts = 0;
266    }
267</tt></pre>
268<br>
269The <tt>@counts</tt> and <tt>@times</tt> aggregations both accumulate
270values for each unique combination of device name, device instance, and
271CPU (a three-element tuple).  In this example we drop the <tt>tick</tt>
272probe to demonstrate a more convenient way to get aggregation data
273without the use of the <tt>printa()</tt> action.  The <a
274href="../api/org/opensolaris/os/dtrace/Consumer.html#getAggregate%28%29">
275<tt>getAggregate()</tt></a> method allows us to get all aggregations at
276once on a programmatic interval.<br>
277<b>Java program (<a href="../examples/TestAPI2.java">TestAPI2.java</a>)</b>
278<pre><tt><font color=#aaaaaa>
279    ...
280
281    try {
282	consumer.open();
283	consumer.compile(file, macroArgs);
284	consumer.enable();
285	consumer.go();</font>
286
287	Aggregate a;
288	do {
289	    Thread.sleep(1000); // 1 second
290	    a = consumer.getAggregate();
291	    if (!a.asMap().isEmpty()) {
292		System.out.println(a);
293	    }
294	} while (consumer.isRunning());<font color=#aaaaaa>
295    } catch (Exception e) {
296	e.printStackTrace();
297	System.exit(1);
298    }
299
300    ...</font>
301</tt></pre>
302<br>
303Compile and run:
304<pre><tt>
305    javac -cp dtrace.jar TestAPI2.java
306</tt></pre>
307<br>
308On i86:
309<pre><tt>
310    java -cp .:dtrace.jar TestAPI2 intrstat.d
311</tt></pre>
312<br>
313On sparc:
314<pre><tt>
315    java -d64 -cp .:dtrace.jar TestAPI2 intrstat.d
316</tt></pre>
317<br>
318Try removing the <tt>tick</tt> probe from the <tt>syscall.d</tt> example
319and running it again with the above modification (<tt>TestAPI2</tt>).<br>
320<br>
321By default, the requested aggregate includes every aggregation and
322accumulates running totals.  To display values per time interval
323(instead of running totals), clear the aggregations each time you call
324<tt>getAggregate()</tt>.  Clearing an aggregation resets all counts to
325zero without removing any tuples.  The following modification to the
326example above clears all aggregations:
327<pre><tt><font color=#aaaaaa>
328	    // a = consumer.getAggregate();</font>
329	    a = consumer.getAggregate(null, null); // included, cleared
330</tt></pre>
331<br>
332Each <tt>Set</tt> of aggregation names, <tt>included</tt> and
333<tt>cleared</tt>, specifies <i>all</i> aggregations if <tt>null</tt> and
334no aggregations if empty.  Any subset is possible.  However, if an
335aggregation has ever been used in the <tt>printa()</tt> action, it is no
336longer available to the <tt>getAggregate()</tt> method.<br>
337<br>
338Be aware that you cannot call <tt>getAggregate()</tt> on an interval
339faster that the <tt>aggrate</tt> setting.  See the <a
340href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidlis?a=view>
341<b>Options and Tunables</b></a> chapter of the <i>Solaris Dynamic
342Tracing Guide</i>.  See also the <a
343href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidlhf?a=view>
344<b>Minimizing Drops</b></a> section of the <b>Aggregations</b> chapter
345for specific information about the <tt>aggrate</tt> option.  The default
346<tt>aggrate</tt> is once per second.  Here's an example of how you might
347double the <tt>aggrate</tt> to minimize drops:
348<pre><tt>
349    consumer.setOption(Option.aggrate, Option.millis(500)); // every half second
350</tt></pre>
351<br>
352Even a single drop terminates the consumer unless you override the <a
353href="../api/org/opensolaris/os/dtrace/ConsumerAdapter.html#dataDropped%28org.opensolaris.os.dtrace.DropEvent%29">
354<tt>dataDropped()</tt></a> method of <tt>ConsumerAdapter</tt> to handle
355drops differently.  To avoid drops, it is probably better to increase
356the <tt>aggsize</tt> option, since increasing the <tt>aggrate</tt> makes
357the consumer work harder.  In most cases, the <tt>aggrate</tt> should
358only be increased when you need to update a display of aggregation data
359more frequently than once per second.  Many runtime options, including
360<tt>aggrate</tt>, can be changed dynamically while the consumer is
361running.<br>
362<br>
363It's also worth mentioning that a D aggregation may omit square
364brackets and aggregate only a single value:
365<pre><tt>
366    @total = count();
367</tt></pre>
368<br>
369The resulting singleton <a
370href="../api/org/opensolaris/os/dtrace/Aggregation.html">
371<tt>Aggregation</tt></a> instance has one record that may be obtained as
372follows:
373<pre><tt>
374    Aggregate a = consumer.getAggregate();
375    Aggregation total = a.getAggregation("total");
376    AggregationRecord totalRecord = total.getRecord(Tuple.EMPTY);
377</tt></pre>
378<br>
379<h2><a name="Target_Process"></a>Target Process ID</h2>
380In addition to supporting macro arguments (see the <tt>syscall.d</tt>
381aggregation example above), the Java DTrace API also supports the
382<tt>$target</tt> macro variable.  (See the <a
383href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidlir?a=view>
384<b>Target Process ID</b></a> section of the <b>Scripting</b> chapter of
385the <i>Solaris Dynamic Tracing Guide</i>.)  This allows you to trace a
386process from the very beginning of its execution, rather than sometime
387after you manually obtain its process ID.  The API does this by creating
388a process that is initially suspended and allowed to start only after <a
389href="../api/org/opensolaris/os/dtrace/Consumer.html#go%28%29">
390<tt>go()</tt></a> has initiated tracing.  For example, we might want to
391aggregate all the system calls from start to finish made by the
392<tt>date</tt> command:<br>
393<b>D script (<a href="../examples/target.d">target.d</a>)</b>
394<pre><tt>
395    syscall:::entry
396    / pid == $target /
397    {
398	    @[probefunc] = count();
399    }
400</tt></pre>
401<br>
402A modified version of the <tt>TestAPI.java</tt> program adds the <a
403href="../api/org/opensolaris/os/dtrace/Consumer.html#createProcess%28java.lang.String%29">
404<tt>createProcess()</tt></a> call to execute the given command but
405prevent it from starting until the consumer is running:<br>
406<b>Java program (<a href="../examples/TestTarget.java">TestTarget.java</a>)</b>
407<pre><tt><font color=#aaaaaa>
408    ...
409    consumer.open();</font>
410    consumer.createProcess(command);<font color=#aaaaaa>
411    consumer.compile(file);
412    consumer.enable();
413    consumer.go();
414    ...</font>
415</tt></pre>
416<br>
417It also overrides the <a
418href="../api/org/opensolaris/os/dtrace/ConsumerAdapter.html#processStateChanged%28org.opensolaris.os.dtrace.ProcessEvent%29">
419<tt>processStateChanged()</tt></a> method of the
420<tt>ConsumerAdapter</tt> to print a notification when the process has
421ended:
422<pre><tt><font color=#aaaaaa>
423    ...
424    consumer.addConsumerListener(new ConsumerAdapter() {
425	public void dataReceived(DataEvent e) {
426	    System.out.println(e.getProbeData());
427	}
428	public void consumerStopped(ConsumerEvent e) {
429	    try {
430		Aggregate a = consumer.getAggregate();
431		for (Aggregation agg : a.asMap().values()) {
432		    for (AggregationRecord rec : agg.asMap().values()) {
433			System.out.println(rec.getTuple() + " " +
434				rec.getValue());
435		    }
436		}
437	    } catch (Exception x) {
438		x.printStackTrace();
439		System.exit(1);
440	    }
441	    consumer.close();
442	}</font>
443	public void processStateChanged(ProcessEvent e) {
444	    System.out.println(e.getProcessState());
445	}<font color=#aaaaaa>
446    });
447    ...</font>
448</tt></pre>
449<br>
450Compile and run:
451<pre><tt>
452    javac -cp dtrace.jar TestTarget.java
453</tt></pre>
454<br>
455On i86:
456<pre><tt>
457    java -cp .:dtrace.jar TestTarget target.d date
458</tt></pre>
459<br>
460On sparc:
461<pre><tt>
462    java -d64 -cp .:dtrace.jar TestTarget target.d date
463</tt></pre>
464<br>
465The consumer exits automatically when the target <tt>date</tt> process
466completes.<br>
467<h2><a name="Closing_Consumers"></a>Closing Consumers</h2>
468An application using the Java DTrace API may run multiple consumers
469simultaneously.  When a consumer stops running, the programmer is
470responsible for closing it in order to release the system resources it
471holds.  A consumer may stop running for any of the following reasons:
472<ul>
473  <li>It was stopped explicitly by a call to its <a
474href=../api/org/opensolaris/os/dtrace/Consumer.html#stop()>
475<tt>stop()</tt></a> method</li>
476  <li>It encountered the <tt>exit()</tt> action</li>
477  <li>Its <tt>$target</tt> process or processes (if any) all completed</li>
478  <li>It encountered an exception</li>
479</ul>
480By default, an exception prints a stack trace to <tt>stderr</tt> before
481notifying listeners that the consumer has stopped.  You can define
482different behavior by setting an <a
483href=../api/org/opensolaris/os/dtrace/ExceptionHandler.html>
484<tt>ExceptionHandler</tt></a>, but the consumer is still stopped.<br>
485<br>
486The same listener that receives probe data generated by DTrace is also
487notified when the consumer stops.  This is a good place to close the
488consumer:
489<pre><tt><font color=#aaaaaa>
490    consumer.addConsumerListener(new ConsumerAdapter() {
491	public void dataReceived(DataEvent e) {
492	    System.out.println(e.getProbeData());
493	}</font>
494	public void consumerStopped(ConsumerEvent e) {
495	    Consumer consumer = (Consumer)e.getSource();
496		consumer.close();
497	    }
498	}<font color=#aaaaaa>
499    });</font>
500</tt></pre>
501<br>
502This releases the resources held by the consumer in all cases, i.e.
503after it exits for <i>any</i> of the reasons listed above.<br>
504<br>
505You can request the last aggregate snapshot made by a stopped consumer,
506as long as it has not yet been closed:
507<pre><tt>
508    Aggregate a = consumer.getAggregate();
509</tt></pre>
510<br>
511Note however that any aggregation that has already appeared in a <a
512href=../api/org/opensolaris/os/dtrace/PrintaRecord.html>
513<tt>PrintaRecord</tt></a> as a result of the <tt>printa()</tt> action
514action will not be included in the requested aggregate.
515<h2><a name="Learning_DTrace"></a>Learning More</h2>
516<br>
517The <a href="http://www.opensolaris.org/os/community/dtrace/">
518OpenSolaris DTrace page</a> has links to resources to help you learn
519DTrace.  In particular, you should read the <a
520href="http://docs.sun.com/db/doc/817-6223"><i>Solaris Dynamic Tracing
521    Guide</i></a>.<br>
522<br>
523Try the example Java programs on this page with other D scripts.  You
524need not remove <tt>#!/usr/sbin/dtrace -s</tt> from the top of an
525executable script.  You may want to remove <tt>profile:::tick*</tt>
526clauses if you plan to use the <tt>Consumer</tt> <a
527href="../api/org/opensolaris/os/dtrace/Consumer.html#getAggregate%28%29">
528<tt>getAggregate()</tt></a> method and control the aggregating interval
529programmatically.  If the script uses the pre-compiler, you will need to
530call the <tt>Consumer</tt> <a
531href="../api/org/opensolaris/os/dtrace/Consumer.html#setOption%28java.lang.String%29">
532<tt>setOption()</tt></a> method with the <a
533href="../api/org/opensolaris/os/dtrace/Option.html#cpp">
534<tt>Option.cpp</tt></a> argument.<br>
535<br>
536To quickly familiarize yourself with the Java DTrace API, take a look at
537the overview <a href="JavaDTraceAPI.html">diagram</a>.<br>
538<br>
539<a href="#Quick_Start_Guide_to_the_Java_DTrace_API_">Back to top</a><br>
540<br>
541</body>
542</html>
543