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.

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

Execute arbitrary Valgrind Monitor command
Returns the RunMode app running in