dtrace - TclDTrace extension: Tcl front-end to the DTrace facility
DTrace is a system profiling suite created by Sun Microsystems. It allows the user to profile a program without modifying its text, or even without the need to distract it if it is running. It consists of a set of library hooks called providers, a set of tools, a C API (libdtrace) and its own specially crafted scripting language called D.
TclDTrace is a Tcl binding to libdtrace. It allows users to run D scripts and process their results directly from Tcl. Together with DTrace providers already present in Tcl, it forms an efficient and convenient tool for performance analysis and has the potential to increase the productivity of Tcl developers.
All TclDTrace commands are in the dtrace namespace.
Returns handle. Opens DTrace. If everything went OK, then handle gets returned. If instrument is 0, then no instrumentation will be possible. This can be useful to just check if a script compiles. Initial configuration options may be passed, see the dtrace::configure call below for the options.
Side note: the name open is derived from the fact that it internally opens /dev/dtrace/ devices.
Closes DTrace. Tidies up. If you forget to do it, it will be fired automatically on Tcl exit. Calling this explicitly when your program is running may come handy if you want to release resources - this is the only way to free claimed memory.
If no options are supplied, the command returns a list containing alternating option names and values. If -option is supplied but no value then the command returns the current value of the given option. If one or more pairs of -option and value are supplied, the command sets each of the named -options to the corresponding value; in this case the return value is an empty string.
For binary options you can use the values 1 and 0. For complete options list consider LibDTrace Options - note that you can use every option of the underlaying libdtrace api, just prepend it with a -.
List of basic options (these get returned in the alternating list by the first type of invocation):
libdtrace options may also be changed from within the scripts using a #pragma directive.
Lear more: Solaris Dynamic Tracing Guide
Grabs the process identified by pid. If it's a first call to dtrace::grab, then the $target macro will be set to pid. You should run dtrace::go quickly, as it's the command to continue the grabbed processes.
This creates a grabbed process by executing cmd and grabbing it immediately. Unlike a call to Tcl's exec and then dtrace::grab, this does not create race conditions. Like in dtrace::grab, process is continued on dtrace::go.
Compiles D program, which should be in the same format as a file passed to dtrace(1) -s. You can pass additional string arguments to the program. Returns a handle compiled_program if successful.
Executes the compiled_program (enables instrumentation points). This might be called multiple times, all the programs will get run (i.e. generate data for processing) after dtrace::go. Returns an alternating name/value list of program info:
Returns an alternating name/value list of program info for the compiled_program (this is the same as previous call, but it doesn't enable the instrumentation - can be used for handles with instrument set to 0):
Enables tracing. This is more or less equal to actually running the executed programs - without it you will not get any data from them. Furthermore this command continues the grabbed processes.
It also registers callbacks. For each callback you need to specify a list containing the callback proc name and possible additional argument. Learn more about callbacks at Callbacks. Possible callbacks names are:
probe_desc
probe_output
drop
error
proc
Stops things ticking.
If sleep is set to 1 sleeps a while. Wakes up if something interesting happens. Note that eventually it will not be necessary to use this kind of sleeping - event loop will do. But, at the moment, you need to manually schedule dtrace::process frequently enough to avoid drops (buffer holds around 60K records), or even DTrace aborting (after 30secs without a call to dtrace::process). This should change in future versions.
This command triggers processing data accumulated in the buffer. For each record a relevant Callbacks is called.
Returns a list containing alternating tuple - value pairs. Tuples are what is found in script between [ and ]. In this list, each tuple is represented by a simple list, whose members are the tuple members, divided by , in D code. Values are simple numerics. dtrace::aggregations output can (and should) be interpreted as a Tcl dict.
For each of the probes matched by the compiled_program, runs the list_callback.
This returns a probe description. If -foldpdesc is set to 1, it is a single string with format [[[provider:] module:] function:] name [[predicate] action]. If -foldpdesc is set to 0, this is an alternating list containing:
This is called for each firing probe. Meaning of the arguments:
the probe description string (see list_callback)
on which cpu did the probe fire
the probe id number
extra argument, empty string if none
This is called for each probe that produced some output. That may be just a trace, printfed string or a stack. At present the output is returned directly as the string given by libdtrace and needs to be parsed by the user. Meaning of the arguments:
the probe description string (see list_callback)
on which cpu did the probe fire
the probe id number
extra argument, empty string if none
the output type (see LibDTrace Buffered Output), without the DTRACEACT_ prefix.
the actual output data
Some of the most interesting output types are:
result of ustack()
result of jstack()
result of stack()
result of printf()
Meaning of the arguments:
on which cpu did the drop occur
what kind of drop it is (see below)
message preconstructed for you by libdtrace
extra argument, empty string if none
Kind is a string meaning:
drop to aggregation buffer
dynamic drop
dyn drop due to rinsing
dyn drop due to dirty
speculative drop
spec drop due to busy
spec drop due to unavail
stack string tab overflow
error in ERROR probe
Meaning of the arguments:
the probe description string (see list_callback)
on which cpu did the probe fire
message preconstructed for you by libdtrace
extra argument, empty string if none
Meaning of the arguments:
pid of the process the message is about
message preconstructed for you by libdtrace
extra argument, empty string if none
package require Tcl 8.5 package require dtrace # Display instructions puts {Please input probes in the standard one-liner format:} puts {[[[provider:] module:] function:] name [[predicate] action]} puts {Empty probe (just enter) ends the input,} # Get sources set probes_sources [list] set probes_count 1 puts "probe $probes_count:" gets stdin probe_line while {$probe_line != ""} { set probes_sources [linsert $probes_sources end $probe_line] set probes_count [expr {$probes_count + 1}] puts "probe $probes_count:" gets stdin probe_line } set probes_count [expr {$probes_count - 1}] # Get them compiled and executed set dhandle [dtrace open -foldpdesc 1] set OK_count 0 set i 1 set compiled_probes [list] foreach probe_line $probes_sources { if { [ catch { puts -nonewline "Processing probe $i: $probe_line " set i [expr {$i + 1}] puts -nonewline . set compiled [dtrace compile $dhandle $probe_line] puts -nonewline . set running [dtrace exec $compiled] puts -nonewline . set OK_count [expr {$OK_count + 1}] puts -nonewline " OK" } ] } { puts -nonewline "FAILED"} puts {} } if {$OK_count == 0} { puts "No probes run - exiting." dtrace close $dhandle exit } # Simple to show the output puts "CPU\tProbe" proc callback {probe cpu id args} { puts "$cpu\t$probe" } # Go go go! dtrace go $dhandle probe_desc {callback {}} set counter 10 while {$counter} { dtrace process $dhandle 1 set counter [expr {$counter - 1}] } dtrace stop $dhandle dtrace close $dhandle
One of the good features of Tcl is really easy networking. So here you go: an example of how easy it is to create a telnet-operated DTrace server for multiple clients.
Usage: Run the script with DTrace privileges. Then connect to the port 1986 with something telnet-compatible. Now you can enter your script. Enter a line containing just GO to finish and enable tracing. Disconnect (close the application) to finish - the server cleans up by itself.
package require Tcl 8.5 package require dtrace proc accept {sock addr port} { global handles scripts set handles($sock) [::dtrace::open -foldpdesc 1] set scripts($sock) "" fconfigure $sock -buffering line fileevent $sock readable [list receive $sock $addr $port] puts "Client connected from $addr:$port" } proc receive {sock addr port} { global handles scripts if {[eof $sock] || [catch {gets $sock line}]} { close $sock ::dtrace::close $handles($sock) unset handles($sock) scripts($sock) puts "Client $addr:$port disconnected" } else { if {[string equal $line "GO"]} { ::dtrace::exec [::dtrace::compile $handles($sock) $scripts($sock)] ::dtrace::go $handles($sock) probe_desc [list callback $sock] puts $sock "CPU\tid\tprobe" dtraceLoop $sock puts "Tracing for $addr:$port started" } else { set scripts($sock) "$scripts($sock)\n$line" } } } proc callback {probe cpu id sock} { puts $sock "$cpu\t$id\t$probe" } proc dtraceLoop {sock} { global handles catch {::dtrace::process $handles($sock)} after 300 dtraceLoop $sock } socket -server accept 1986 vwait forever
dtrace(1)
dtrace
Copyright © 2008 Remigiusz 'lRem' Modrzejewski