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.