This is a guide for writing DTrace scripts in the style used
by the DTraceToolkit -
a collection of useful DTrace scripts for Solaris 10.
Note: This document is not written by Sun.
Brendan Gregg, 20-Apr-2006, version 0.20.
Contents
1. Intro
Many languages have well defined styles to follow, they help the programmer write in a neat consistant way and in the long run make fewer mistakes. They also help other programmers rapidly understand what they have written. These styles are documented in style guides, or "programming best practices".
Styles are bourne from experience - finding out, often the hard way, what does and doesn't work. Since early 2004 I've written over a thousand DTrace scripts, around a hundred of which are in the DTraceToolkit. I've learnt a lot about what does and doesn't work, and have adapted my style numerous times. My last few style changes were costly, as it meant updating and retesting dozens of scripts from the DTraceToolkit. Hopefully I can save you similar pain, by documenting what I have learnt.
Some of this style is derived from cstyle, the tool used to check the style of the Solaris and OpenSolaris source to ensure it matches "Bill Joy Normal Form". I often run cstyle itself on DTrace scripts, as most of the warnings are still appropriate (thanks to the similarity of D to C programming).
This style will help if you wish to publish your scripts on the Internet, and is crucial for scripts in the DTraceToolkit. It is similar but not the same as the style used in the DTrace Guide (which was written by the authors of DTrace itself). For that reason this is known as the "DTraceToolkit Style", not the official "DTrace Style" as used in the DTrace Guide.
When using this guide, you may find that you don't agree on every point made. I don't agree on all the details of other programming style guides, however I follow them nonetheless as obeying a standard provides greater value than to use my own pecularities.
Lastly, if for any of the following points you wonder if I'm serious - the answer is YES.
2. Generic coding
The following are the same as C programmang in the style enforced by cstyle.
2.1. Line width of 80 chars
Each line must not exceed 80 characters (with a tabstop of 8). The entire Solaris kernel is <= 80 chars, so your small DTrace script should have no problem. A soft limit of 79 characters is encouraged, for a few reasons, including copy-n-pasting from some terminals will auto-join lines that have hit 80 chars.
The following is BAD,
printf("%-20s %7s %7s %7s %7s\n", "Time", "scall/s", "sread/s", "swrit/s", "fork/s"); |
The following is GOOD,
printf("%-20s %7s %7s %7s %7s\n", "Time", "scall/s", "sread/s", "swrit/s", "fork/s"); |
I dropped "Time" to the next line to keep all the headers together.
2.2. Line continuation of 4 chars
If a line exceeds the line width (80 chars), the remaining data can be placed on the following line with an indentation of 4 characters.
The following is BAD,
printf("%-20s %7s %7s %7s %7s\n", ________"Time", "scall/s", "sread/s", "swrit/s", "fork/s"); |
The following is GOOD,
printf("%-20s %7s %7s %7s %7s\n", "Time", "scall/s", "sread/s", "swrit/s", "fork/s"); |
2.3. Term seperator
Terms seperated by a comma must have a space after the comma.
The following is BAD,
printf("%6s %-16s %1s %s\n","PID","CMD","D","BYTES"); |
The following is GOOD,
printf("%6s %-16s %1s %s\n", "PID", "CMD", "D", "BYTES"); |
2.4. Comments
Comments are either a line comment or a block comment, of a very particular style (cstyle).
The following is BAD,
/****************** * Process io start ******************/ io:::start { /* fetch details */ this->size = args[0]->b_bcount; /*** b_count is bytes ***/ |
The following is GOOD,
/* * Process io start */ io:::start { /* fetch details */ this->size = args[0]->b_bcount; /* b_count is bytes */ |
The cstyle tool is very strict with comment formatting. For example, the first line in the above GOOD example must not have a trailing space.
2.5. cstyle
The remaining rules for coding can be learned from using the cstyle tool.
The following is BAD,
# cstyle cputypes.d cputypes.d: 42: missing space around assignment operator cputypes.d: 47: comma or semicolon followed by non-blank cputypes.d: 48: missing space around assignment operator cputypes.d: 55: continuation line not indented by 4 spaces cputypes.d: 59: line > 80 characters cputypes.d: 62: improper first line of block comment cputypes.d: 62: missing blank after open comment cputypes.d: 66: indent by spaces instead of tabs cputypes.d: 68: last line in file is blank |
The following is GOOD,
# cstyle cputypes.d cputypes.d: 42: missing space around assignment operator |
We allow the warning for line 42 as it is a DTrace directive that cstyle does not understand,
# sed '42!d' cputypes.d #pragma D option bufsize=64k |
3. DTrace specific
The following are specific to the D programming language.
3.1. Fully qualified probe names
When specifying probes, you must use all four fields (if available), provider:module:function:name. The shortcuts that DTrace allows are suitable for when hacking at the command line, however for scripting it is both clearer and safer to specify the full name.
The following is BAD,
fork1:entry |
The following is GOOD,
syscall::fork1:entry |
In fact, the BAD example above is especially bad as it matches the fork1 probe in both the fbt and the syscall providers - producing duplicated results. If you write such a shortcut that only matches the desired probes now, in a future version of Solaris more probes may be added such that it becomes incorrect. To be safe, always fully qualify.
For consistancy, fully qualify the BEGIN probe as well,
dtrace:::BEGIN |
This is the greatest deviation to the DTrace Guide style, which often uses just "BEGIN" to specify this probe.
3.2. BEGIN with a printf
When you run scripts that use the quiet pragma, the BEGIN statement must print something to let the user know when DTrace has begun tracing. This may be a header, or a message to say that tracing has begun.
The following is BAD,
# ./awkward_silence.d _ |
The following is GOOD,
# ./bitesize.d Tracing... Hit Ctrl-C to end. |
The following is also GOOD,
# ./dnlcsnoop.d PID CMD TIME HIT PATH |
And the following is FINE,
# ./readbytes.d dtrace: script './readbytes.d' matched 4 probes |
which is the default behaviour of DTrace, and does indeed note when tracing has begun.
3.3. Sampling/Tracing...
Following on from 3.2, scripts that collect data and then print a report when Ctrl-C is hit must print a BEGIN message. That BEGIN message should convey the behaviour of your script.
The following is BAD,
# ./mystery.d Somehow gathering data... Hit Ctrl-C to end. |
If your script traces events (eg, io:::start), then the following is GOOD,
# ./bitesize.d Tracing... Hit Ctrl-C to end. |
If your script samples data (eg, profile:::profile-1000hz), then the following is GOOD,
# ./pridist.d Sampling... Hit Ctrl-C to end. |
Whenever the user sees "Sampling", it informs them that the script may be subject to sampling errors and that the rate may need to be customised.
3.4. Units
Scripts that output numbers are encouraged to provide units in the output if space permits. The following points explain usage.
The following is BAD,
# ./measure.d Tracing... Hit Ctrl-C to end. ^C Average: 152 ____ |
The following is GOOD,
# ./measure.d Tracing... Hit Ctrl-C to end. ^C Average: 152 Kbytes/sec |
10. Links
For more Solaris 10 DTrace see,
Back to Brendan Gregg's Homepage