Crate crabgrind

source ·
Expand description

Valgrind Client Request interface for Rust

crabgrind wraps various Valgrind macros in C functions, compiles and links against the resulting binary, and exposes an unsafe interface to allow Rust programs running under Valgrind to interact with the tools and environment.

Valgrind 3 API coverage

Quickstart

crabgrind imports macros from Valgrind’s header files, therefore you must have Valgrind installed to build the project.

Add the following to your Cargo.toml file:

[dependencies]
crabgrind = "^0.1"

Examples

Print some message to the Valgrind log

use crabgrind as cg;

if matches!(cg::run_mode(), cg::RunMode::Native) {
    println!("run me under Valgrind");
} else {
    cg::println!("Hey, Valgrind!");
}

Exclude expensive (de)initialization code from the measurements

One way to do this would be to turn off stats collection at stratup with the --collect-atstart=no callgrind command-line attribute, and enable/disable it from the code with callgrind::toggle_collect

use crabgrind as cg;

// ... some expensive initialization

cg::callgrind::toggle_collect();
// code of interest
cg::callgrind::toggle_collect();

// ... some deinitialization

Run a closure on the real CPU while running under Valgrind

We can run on the real CPU instead of the virtual one using valgrind::non_simd_call, refer to valgrind.h for details on limitations and various ways to crash.

use crabgrind as cg;

let mut state = 0;
cg::valgrind::non_simd_call(|tid| {
    // uncomment following line to see "the 'impossible' happened"
    // println!("tid: {tid}");
    state = tid;
});

println!("tid: {state}");

Save current memory usage snapshot to a file

We’ll use Massif tool and the monitor command interface to run the corresponding Massif command.

use crabgrind as cg;

let heap = String::from("alloca");

if cg::monitor_command("snapshot mem.snapshot").is_ok(){
    println!("snapshot is saved to \"mem.snapshot\"");
}

Overhead

from Valgrind docs

The code added to your binary has negligible performance impact: on x86, amd64, ppc32, ppc64 and ARM, the overhead is 6 simple integer instructions and is probably undetectable except in tight loops.

… the code does nothing when not run on Valgrind, so you are not forced to run your program under Valgrind just because you use the macros in this file.

however,

  • wrapping each macros in a function implies function call overhead regardless of the run mode
  • functions that returns std::result::Result involve branching
  • functions that takes strings as a parameters internally converts them to std::ffi::CString

If you wish to compile out all (crab)Valgrind from the binary, you can wrap crabgrind calls with the feature-gate.

Tests

Tests must be run under Valgrind, as of now cargo-valgrind fits nicely, it allows to compile and run tests under Valgrind in one command

cargo valgrind test

Modules

Macros

Prints to the Valgrind’s log.
Prints to the Valgrind’s log, with the current stacktrace attached.
Prints to the Valgrind’s log, with a newline.

Enums

Current run mode

Functions

Change the value of a dynamic command line option.
Returns the number of errors found so far by Valgrind
Disable error reporting for this thread
Re-enable error reporting for this thread
Execute arbitrary Valgrind Monitor command
Returns the RunMode app running in