Crate usdt[−][src]
Expose USDT probe points from Rust programs.
Overview
This crate provides methods for compiling definitions of DTrace probes into Rust code, allowing rich, low-overhead instrumentation of Rust programs.
Users define a provider, with one or more probe functions, in the D language. For example:
provider test {
probe start(uint8_t);
probe stop(char*, uint8_t);
};
Providers and probes may be named in any way, as long as they form valid Rust identifiers. The
names are intended to help understand the behavior of a program, so they should be semantically
meaningful. Probes accept zero or more arguments, data that is associated with the probe event
itself (timestamps, file descriptors, filesystem paths, etc.). The arguments may be specified
as any of the exact bit-width integer types (e.g., int16_t
) or strings (char *
s). See
Data types for a full list of supported types.
Assuming the above is in a file called "test.d"
, this may be compiled into Rust code with:
#![feature(asm)] usdt::dtrace_provider!("test.d");
This procedural macro will generate a Rust macro for each probe defined in the provider. Note
that including the asm
feature is required; see the notes for a discussion. The
feature
directive and the invocation of dtrace_provider
should both be at the crate
root, i.e., src/lib.rs
or src/main.rs
.
One may then call the start
probe via:
let x: u8 = 0; test_start!(|| x);
Note that test_start!
is called with a closure which returns the arguments, rather than the
actual arguments themselves. See below for details. Additionally, as the
probes are exposed as macros, they should be included in the crate root, before any other
module or item which references them.
After declaring probes and converting them into Rust code, they must be registered with the
DTrace kernel module. Developers should call the function register_probes
as soon as
possible in the execution of their program to ensure that probes are available. At this point,
the probes should be visible from the dtrace(1)
command-line tool, and can be enabled or
acted upon like any other probe. See registration for a discussion of probe
registration, especially in the context of library crates.
Examples
See the probe_test_macro and probe_test_build crates for detailed working examples showing how the probes may be defined, included, and used.
Probe arguments
Note that the probe macro is called with a closure which returns the actual arguments. There are two reasons for this. First, it makes clear that the probe may not be evaluated if it is not enabled; the arguments should not include function calls which are relied upon for their side-effects, for example. Secondly, it is more efficient. As the lambda is only called if the probe is actually enabled, this allows passing arguments to the probe that are potentially expensive to construct. However, this cost will only be incurred if the probe is actually enabled.
Data types
Probes support any of the integer types which have a specific bit-width, e.g., uint16_t
, as
well as strings, which should be specified as char *
. Below is the full list of supported
types.
uint8_t
uint16_t
uint32_t
uint64_t
int8_t
int16_t
int32_t
int64_t
char *
Currently, up to six (6) arguments are supported, though this limitation may be lifted in the future.
Registration
USDT probes must be registered with the DTrace kernel module. This is done via a call to the
register_probes
function, which must be called before any of the probes become available to
DTrace. Ideally, this would be done automatically; however, while there are methods by which
that could be achieved, they all pose significant concerns around safety, clarity, and/or
explicitness.
At this point, it is incumbent upon the application developer to ensure that
register_probes
is called appropriately. This will register all probes in an application,
including those defined in a library dependency. To avoid foisting an explicit dependency on
the usdt
crate on downstream applications, library writers should re-export the
register_probes
function with:
pub use usdt::register_probes;
The library should clearly document that it defines and uses USDT probes, and that this function should be called by an application.
Notes
The USDT crate relies on inline assembly to hook into DTrace. Unfortunatley this feature is
unstable, and requires explicitly opting in with #![feature(asm)]
as well as running with a
nightly Rust compiler. A nightly toolchain may be installed with:
$ rustup toolchain install nightly
and Rust code exposing USDT probes may then be built with:
$ cargo +nightly build
The asm
feature is a default of the usdt
crate.
Macros
dtrace_provider | Generate DTrace probe macros from a provider definition file. |
Structs
Builder | A simple struct used to build DTrace probes into Rust code in a build.rs script. |
Enums
Error | Errors related to building DTrace probes into Rust code |
Functions
register_probes | Register an application’s probes with DTrace. |