1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 package org.opensolaris.os.dtrace;
27 
28 import java.io.Serializable;
29 import java.io.ObjectInputStream;
30 import java.io.InvalidObjectException;
31 import java.io.IOException;
32 import java.beans.*;
33 
34 /**
35  * A DTrace option and its value.  Compile-time options must be set
36  * before calling {@code Consumer} {@link Consumer#compile(String
37  * program, String[] macroArgs) compile(String program, ...)} or {@link
38  * Consumer#compile(File program, String[] macroArgs) compile(File
39  * program, ...)} in order to affect program compilation.  Runtime
40  * options may be set anytime before calling {@code Consumer} {@link
41  * Consumer#go() go()}, and some of them may be changed while a consumer
42  * is running.
43  * <p>
44  * See the <a
45  * href=http://dtrace.org/guide/chp-opt.html>
46  * <b>Options and Tunables</b></a> chapter of the <i>Dynamic
47  * Tracing Guide</i>.
48  * <p>
49  * Immutable.  Supports persistence using {@link java.beans.XMLEncoder}.
50  *
51  * @author Tom Erickson
52  */
53 public final class Option implements Serializable {
54     static final long serialVersionUID = 2734100173861424920L;
55 
56     /**
57      * Value returned by {@link Consumer#getOption(String option)} when
58      * the given boolean option is unset.
59      */
60     public static final long UNSET = -2L;
61 
62     /**
63      * Value returned by {@link Consumer#getOption(String option)} for
64      * the {@link #bufpolicy} option when the {@link #VALUE_RING ring}
65      * buffer policy is set.
66      */
67     public static final long BUFPOLICY_RING = 0L;
68 
69     /**
70      * Value returned by {@link Consumer#getOption(String option)} for
71      * the {@link #bufpolicy} option when the {@link #VALUE_FILL fill}
72      * buffer policy is set.
73      */
74     public static final long BUFPOLICY_FILL = 1L;
75 
76     /**
77      * Value returned by {@link Consumer#getOption(String option)} for
78      * the {@link #bufpolicy} option when the default {@link
79      * #VALUE_SWITCH switch} buffer policy is set.
80      */
81     public static final long BUFPOLICY_SWITCH = 2L;
82 
83     /**
84      * Value returned by {@link Consumer#getOption(String option)} for
85      * the {@link #bufresize} option when the default {@link #VALUE_AUTO
86      * auto} buffer resize policy is set.
87      */
88     public static final long BUFRESIZE_AUTO = 0L;
89 
90     /**
91      * Value returned by {@link Consumer#getOption(String option)} for
92      * the {@link #bufresize} option when the {@link #VALUE_MANUAL
93      * manual} buffer resize policy is set.
94      */
95     public static final long BUFRESIZE_MANUAL = 1L;
96 
97     static {
98 	try {
99 	    BeanInfo info = Introspector.getBeanInfo(Option.class);
100 	    PersistenceDelegate persistenceDelegate =
101 		    new DefaultPersistenceDelegate(
102 		    new String[] {"name", "value"})
103 	    {
104 		/*
105 		 * Need to prevent DefaultPersistenceDelegate from using
106 		 * overridden equals() method, resulting in a
107 		 * StackOverFlowError.  Revert to PersistenceDelegate
108 		 * implementation.  See
109 		 * http://forum.java.sun.com/thread.jspa?threadID=
110 		 * 477019&tstart=135
111 		 */
112 		protected boolean
113 		mutatesTo(Object oldInstance, Object newInstance)
114 		{
115 		    return (newInstance != null && oldInstance != null &&
116 			    oldInstance.getClass() == newInstance.getClass());
117 		}
118 	    };
119 	    BeanDescriptor d = info.getBeanDescriptor();
120 	    d.setValue("persistenceDelegate", persistenceDelegate);
121 	} catch (IntrospectionException e) {
122 	    System.out.println(e);
123 	}
124     }
125 
126     //
127     // See lib/libdtrace/common/dt_options.c
128     //
129 
130     /**
131      * Gets a size option value indicating the given number of
132      * kilobytes.
133      *
134      * @param n number of kilobytes
135      * @return size option value indicating the given number of
136      * kilobytes
137      */
138     public static String
kb(int n)139     kb(int n)
140     {
141 	return (Integer.toString(n) + "k");
142     }
143 
144     /**
145      * Gets a size option value indicating the given number of
146      * megabytes.
147      *
148      * @param n number of megabytes
149      * @return size option value indicating the given number of
150      * megabytes
151      */
152     public static String
mb(int n)153     mb(int n)
154     {
155 	return (Integer.toString(n) + "m");
156     }
157 
158     /**
159      * Gets a size option value indicating the given number of
160      * gigabytes.
161      *
162      * @param n number of gigabytes
163      * @return size option value indicating the given number of
164      * gigabytes
165      */
166     public static String
gb(int n)167     gb(int n)
168     {
169 	return (Integer.toString(n) + "g");
170     }
171 
172     /**
173      * Gets a size option value indicating the given number of
174      * terabytes.
175      *
176      * @param n number of terabytes
177      * @return size option value indicating the given number of
178      * terabytes
179      */
180     public static String
tb(int n)181     tb(int n)
182     {
183 	return (Integer.toString(n) + "t");
184     }
185 
186     /**
187      * Gets a time option value indicating the given number of
188      * nanoseconds.
189      *
190      * @param n number of nanoseconds
191      * @return time option value indicating the given number of
192      * nanoseconds
193      */
194     public static String
nanos(int n)195     nanos(int n)
196     {
197 	return (Integer.toString(n) + "ns");
198     }
199 
200     /**
201      * Gets a time option value indicating the given number of
202      * microseconds.
203      *
204      * @param n number of microseconds
205      * @return time option value indicating the given number of
206      * microseconds
207      */
208     public static String
micros(int n)209     micros(int n)
210     {
211 	return (Integer.toString(n) + "us");
212     }
213 
214     /**
215      * Gets a time option value indicating the given number of
216      * milliseconds.
217      *
218      * @param n number of milliseconds
219      * @return time option value indicating the given number of
220      * milliseconds
221      */
222     public static String
millis(int n)223     millis(int n)
224     {
225 	return (Integer.toString(n) + "ms");
226     }
227 
228     /**
229      * Gets a time option value indicating the given number of seconds.
230      *
231      * @param n number of seconds
232      * @return time option value indicating the given number of seconds
233      */
234     public static String
seconds(int n)235     seconds(int n)
236     {
237 	return (Integer.toString(n) + "s");
238     }
239 
240     /**
241      * Gets a time option value indicating the given number of minutes.
242      *
243      * @param n number of minutes
244      * @return time option value indicating the given number of minutes
245      */
246     public static String
minutes(int n)247     minutes(int n)
248     {
249 	return (Integer.toString(n) + "m");
250     }
251 
252     /**
253      * Gets a time option value indicating the given number of hours.
254      *
255      * @param n number of hours
256      * @return time option value indicating the given number of hours
257      */
258     public static String
hours(int n)259     hours(int n)
260     {
261 	return (Integer.toString(n) + "h");
262     }
263 
264     /**
265      * Gets a time option value indicating the given number of days.
266      *
267      * @param n number of days
268      * @return time option value indicating the given number of days
269      */
270     public static String
days(int n)271     days(int n)
272     {
273 	return (Integer.toString(n) + "d");
274     }
275 
276     /**
277      * Gets a time option value indicating the given rate per second.
278      *
279      * @param n number of cycles per second (hertz)
280      * @return time option value indicating rate per second
281      */
282     public static String
hz(int n)283     hz(int n)
284     {
285 	return (Integer.toString(n) + "hz");
286     }
287 
288     /**
289      * May be passed to {@link Consumer#setOption(String option, String
290      * value)} to set a boolean option such as {@link #flowindent}.
291      * However, a more convenient way to set boolean options is {@link
292      * Consumer#setOption(String option)}.
293      */
294     public static final String VALUE_SET = "set";
295 
296     /**
297      * May be passed to {@link Consumer#setOption(String option, String
298      * value)} to unset a boolean option such as {@link #flowindent}.
299      * However, a more convenient way to unset boolean options is {@link
300      * Consumer#unsetOption(String option)}.
301      */
302     public static final String VALUE_UNSET = "unset";
303 
304     /**
305      * {@link #bufpolicy} value: use {@code ring} principal buffer
306      * policy.
307      */
308     public static final String VALUE_RING = "ring";
309     /**
310      * {@link #bufpolicy} value: use {@code fill} principal buffer
311      * policy.
312      */
313     public static final String VALUE_FILL = "fill";
314     /**
315      * {@link #bufpolicy} default value: use {@code switch} principal
316      * buffer policy.
317      */
318     public static final String VALUE_SWITCH = "switch";
319 
320     /**
321      * {@link #bufresize} default value: use {@code auto} buffer
322      * resizing policy.
323      */
324     public static final String VALUE_AUTO = "auto";
325     /**
326      * {@link #bufresize} value: use {@code manual} buffer resizing
327      * policy.
328      */
329     public static final String VALUE_MANUAL = "manual";
330 
331     //
332     // See lib/libdtrace/common/dt_options.c
333     //
334 
335     /**
336      * Set program attribute minimum (compile-time).  The format of the
337      * option value is defined by the {@link
338      * InterfaceAttributes#toString()} method.
339      *
340      * @see Program#getInfo()
341      */
342     public static final String amin = "amin";
343     /**
344      * Do not require all macro args to be used (compile-time; no option
345      * value).
346      *
347      * @see Consumer#compile(String program, String[] macroArgs)
348      * @see Consumer#compile(File program, String[] macroArgs)
349      */
350     public static final String argref = "argref";
351     /**
352      * Run cpp(1) preprocessor on D script files (compile-time; no
353      * option value).
354      */
355     public static final String cpp = "cpp";
356     /**
357      * Used together with {@link #cpp} option, specifies which {@code
358      * cpp} to run by its pathname (compile-time).
359      */
360     public static final String cpppath = "cpppath";
361     /**
362      * Use zero (0) or empty string ("") as the value for unspecified macro args
363      * (compile-time; no option value).
364      *
365      * @see Consumer#compile(String program, String[] macroArgs)
366      * @see Consumer#compile(File program, String[] macroArgs)
367      */
368     public static final String defaultargs = "defaultargs";
369     /**
370      * Define symbol when invoking preprocessor (compile-time).
371      */
372     public static final String define = "define";
373     /**
374      * Permit compilation of empty D source files (compile-time; no
375      * option value).
376      */
377     public static final String empty = "empty";
378     /**
379      * Adds error tags to default error messages (compile-time; no
380      * option value).
381      */
382     public static final String errtags = "errtags";
383     /**
384      * Add include directory to preprocessor search path (compile-time).
385      */
386     public static final String incdir = "incdir";
387     /**
388      * Permit unresolved kernel symbols (compile-time; no option value).
389      */
390     public static final String knodefs = "knodefs";
391     /**
392      * Add library directory to library search path (compile-time).
393      */
394     public static final String libdir = "libdir";
395     /**
396      * Specify ISO C conformance settings for preprocessor
397      * (compile-time).
398      */
399     public static final String stdc = "stdc";
400     /**
401      * Undefine symbol when invoking preprocessor (compile-time).
402      */
403     public static final String undef = "undef";
404     /**
405      * Permit unresolved user symbols (compile-time; no option value).
406      */
407     public static final String unodefs = "unodefs";
408     /**
409      * Request specific version of native DTrace library (compile-time).
410      */
411     public static final String version = "version";
412     /**
413      * Permit probe definitions that match zero probes (compile-time; no
414      * option value).
415      */
416     public static final String zdefs = "zdefs";
417 
418     /** Rate of aggregation reading (time).  Runtime option. */
419     public static final String aggrate = "aggrate";
420     /** Aggregation buffer size (size).  Runtime option. */
421     public static final String aggsize = "aggsize";
422     /**
423      * Denotes that aggregation data should be sorted in tuple order,
424      * with ties broken by value order (no option value).  Runtime
425      * option.
426      *
427      * @see AggregationRecord
428      * @see Option#aggsortkeypos
429      * @see Option#aggsortpos
430      * @see Option#aggsortrev
431      */
432     public static final String aggsortkey = "aggsortkey";
433     /**
434      * When multiple aggregation tuple elements are present, the
435      * position of the tuple element that should act as the primary sort
436      * key (zero-based index).  Runtime option.
437      *
438      * @see Option#aggsortkey
439      * @see Option#aggsortpos
440      * @see Option#aggsortrev
441      */
442     public static final String aggsortkeypos = "aggsortkeypos";
443     /**
444      * When multiple aggregations are being printed, the position of the
445      * aggregation that should act as the primary sort key (zero-based
446      * index).  Runtime option.
447      * <p>
448      * Here "position" refers to the position of the aggregation in the
449      * {@code printa()} argument list after the format string (if
450      * any).  For example, given the following statement:
451      * <pre><code>
452      * printa("%d %@7d %@7d\n", @a, @b);
453      * </code></pre>
454      * setting {@code aggsortpos} to {@code "0"} indicates that output
455      * should be sorted using the values of {@code @a} as the primary
456      * sort key, while setting {@code aggsortpos} to {@code "1"}
457      * indicates that output should be sorted using the values of
458      * {@code @b} as the primary sort key.
459      *
460      * @see Option#aggsortkey
461      * @see Option#aggsortkeypos
462      * @see Option#aggsortrev
463      */
464     public static final String aggsortpos = "aggsortpos";
465     /**
466      * Denotes that aggregation data should be sorted in descending
467      * order (no option value).  Runtime option.
468      * <p>
469      * The {@code aggsortrev} option is useful in combination with the
470      * {@code aggsortkey}, {@code aggsortkeypos}, and {@code aggsortpos}
471      * options, which define the ascending sort reversed by this option.
472      *
473      * @see Option#aggsortkey
474      * @see Option#aggsortkeypos
475      * @see Option#aggsortpos
476      */
477     public static final String aggsortrev = "aggsortrev";
478     /** Principal buffer size (size).  Runtime option. */
479     public static final String bufsize = "bufsize";
480     /**
481      * Buffering policy ({@link #VALUE_SWITCH switch}, {@link
482      * #VALUE_FILL fill}, or {@link #VALUE_RING ring}).  Runtime option.
483      * <p>
484      * See the <a
485      * href=http://dtrace.org/guide/chp-buf.html#chp-buf-2>
486      * <b>Principal Buffer Policies</b></a> section of the
487      * <b>Buffers and Buffering</b> chapter of the <i>Dynamic
488      * Tracing Guide</i>.
489      */
490     public static final String bufpolicy = "bufpolicy";
491     /**
492      * Buffer resizing policy ({@link #VALUE_AUTO auto} or {@link
493      * #VALUE_MANUAL manual}).  Runtime option.
494      * <p>
495      * See the <a
496      * href=http://dtrace.org/guide/chp-buf.html#chp-buf-5>
497      * <b>Buffer Resizing Policy</b></a> section of the <b>Buffers
498      * and Buffering</b> chapter of the <i>Dynamic Tracing
499      * Guide</i>.
500      */
501     public static final String bufresize = "bufresize";
502     /** Cleaning rate (time).  Runtime option. */
503     public static final String cleanrate = "cleanrate";
504     /** CPU on which to enable tracing (scalar).  Runtime option. */
505     public static final String cpu = "cpu";
506     /** Permit destructive actions (no option value).  Runtime option. */
507     public static final String destructive = "destructive";
508     /** Dynamic variable space size (size).  Runtime option. */
509     public static final String dynvarsize = "dynvarsize";
510     /**
511      * Adds {@link Flow} information to generated {@link ProbeData}
512      * indicating direction of control flow (entry or return) across
513      * function boundaries and depth in call stack (no option value).
514      * Runtime option.
515      */
516     public static final String flowindent = "flowindent";
517     /** Number of speculations (scalar).  Runtime option. */
518     public static final String nspec = "nspec";
519     /**
520      * Only output explicitly traced data (no option value).  Makes no
521      * difference to generated {@link ProbeData}, but user apps may use
522      * the {@code quiet} flag as a rendering hint similar to the {@code
523      * -q} {@code dtrace(8)} command option.  Runtime option.
524      */
525     public static final String quiet = "quiet";
526     /** Speculation buffer size (size).  Runtime option. */
527     public static final String specsize = "specsize";
528     /** Number of stack frames (scalar).  Runtime option. */
529     public static final String stackframes = "stackframes";
530     /** Rate of status checking (time).  Runtime option. */
531     public static final String statusrate = "statusrate";
532     /** String size (size).  Runtime option. */
533     public static final String strsize = "strsize";
534     /** Rate of buffer switching (time).  Runtime option. */
535     public static final String switchrate = "switchrate";
536     /** Number of user stack frames (scalar).  Runtime option. */
537     public static final String ustackframes = "ustackframes";
538 
539     /** @serial */
540     private final String name;
541     /** @serial */
542     private final String value;
543 
544     /**
545      * Creates an option without an associated value.  The created
546      * boolean option has the value {@link Option#VALUE_SET}.  To
547      * specify that the named option be unset, use {@link
548      * Option#VALUE_UNSET}.
549      *
550      * @param optionName DTrace option name
551      * @throws NullPointerException if the given option name is {@code
552      * null}
553      * @see #Option(String optionName, String optionValue)
554      */
555     public
Option(String optionName)556     Option(String optionName)
557     {
558 	this(optionName, Option.VALUE_SET);
559     }
560 
561     /**
562      * Creates an option with the given name and value.
563      *
564      * @param optionName DTrace option name
565      * @param optionValue DTrace option value
566      * @throws NullPointerException if the given option name or value is
567      * {@code null}
568      */
569     public
Option(String optionName, String optionValue)570     Option(String optionName, String optionValue)
571     {
572 	name = optionName;
573 	value = optionValue;
574 	validate();
575     }
576 
577     private final void
validate()578     validate()
579     {
580 	if (name == null) {
581 	    throw new NullPointerException("option name is null");
582 	}
583 	if (value == null) {
584 	    throw new NullPointerException("option value is null");
585 	}
586     }
587 
588     /**
589      * Gets the option name.
590      *
591      * @return non-null option name
592      */
593     public String
getName()594     getName()
595     {
596 	return name;
597     }
598 
599     /**
600      * Gets the option value.
601      *
602      * @return option value, or {@code null} if no value is associated
603      * with the option
604      */
605     public String
getValue()606     getValue()
607     {
608 	return value;
609     }
610 
611     /**
612      * Compares the specified object with this option for equality.
613      * Defines equality as having equal names and values.
614      *
615      * @return {@code true} if and only if the specified object is an
616      * {@code Option} with the same name and the same value as this
617      * option.  Option values are the same if they are both {@code null}
618      * or if they are equal as defined by {@link String#equals(Object o)
619      * String.equals()}.
620      */
621     public boolean
equals(Object o)622     equals(Object o)
623     {
624 	if (o instanceof Option) {
625 	    Option opt = (Option)o;
626 	    return (name.equals(opt.name) &&
627 		    value.equals(opt.value));
628 	}
629 	return false;
630     }
631 
632     /**
633      * Overridden to ensure that equal options have equal hashcodes.
634      */
635     @Override
636     public int
hashCode()637     hashCode()
638     {
639 	int hash = 17;
640 	hash = (37 * hash) + name.hashCode();
641 	hash = (37 * hash) + value.hashCode();
642 	return hash;
643     }
644 
645     private void
readObject(ObjectInputStream s)646     readObject(ObjectInputStream s)
647             throws IOException, ClassNotFoundException
648     {
649 	s.defaultReadObject();
650 	// check invariants
651 	try {
652 	    validate();
653 	} catch (Exception e) {
654 	    InvalidObjectException x = new InvalidObjectException(
655 		    e.getMessage());
656 	    x.initCause(e);
657 	    throw x;
658 	}
659     }
660 
661     /**
662      * Gets a string representation of this option useful for logging
663      * and not intended for display.  The exact details of the
664      * representation are unspecified and subject to change, but the
665      * following format may be regarded as typical:
666      * <pre><code>
667      * class-name[property1 = value1, property2 = value2]
668      * </code></pre>
669      */
670     public String
toString()671     toString()
672     {
673 	StringBuilder buf = new StringBuilder();
674 	buf.append(Option.class.getName());
675 	buf.append("[name = ");
676 	buf.append(name);
677 	buf.append(", value = ");
678 	buf.append(value);
679 	buf.append(']');
680 	return buf.toString();
681     }
682 }
683