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
- Supported tool-specific client request interface:
- Monitor commands interface
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