partial_callgrind/lib.rs
1//! Easy to use client requests to start/stop callgrind at specific location of your code for precise profiling (100% Rust).
2//!
3//! For now only x86_64 is supported.
4//!
5//! # Examples
6//!
7//! Skip `Vec` initialization code and profile only sort.
8//! Compile in release mode and then use `valgrind --tool=callgrind --collect-atstart=no --instr-atstart=no {exec}`.
9//!
10//! ```
11//! use partial_callgrind::{start, stop};
12//! use rand::Rng;
13//!
14//! fn main() {
15//! let mut rng = rand::thread_rng();
16//!
17//! let mut data: Vec<u8> = (0..10_000).into_iter().map(|_| rng.gen::<u8>()).collect();
18//! start();
19//! data.sort();
20//! stop();
21//! }
22//! ```
23use std::arch::asm;
24
25const MAGIC_NUMBER: u64 = 1129578496;
26
27#[doc(hidden)]
28#[inline(always)]
29unsafe fn request(default: u64, args: &[u64; 6]) -> u64 {
30 let result;
31 asm!(
32 "rol rdi, 3
33 rol rdi, 13
34 rol rdi, 61
35 rol rdi, 51
36 xchg rbx,rbx",
37 inout("rdx") default=>result,
38 in("rax") args.as_ptr()
39 );
40 result
41}
42
43#[inline(always)]
44pub fn toggle_collection() {
45 unsafe { request(0, &[MAGIC_NUMBER + 2, 0, 0, 0, 0, 0]) };
46}
47
48#[inline(always)]
49pub fn start_instrumentation() {
50 unsafe { request(0, &[MAGIC_NUMBER + 4, 0, 0, 0, 0, 0]) };
51}
52
53#[inline(always)]
54pub fn stop_instrumentation() {
55 unsafe { request(0, &[MAGIC_NUMBER + 5, 0, 0, 0, 0, 0]) };
56}
57
58/// Start instrumentation and toggle collection state.
59/// With `--collect-atstart=no` option, callgrind's collection state is disabled at the beginning.
60#[inline(always)]
61pub fn start() {
62 start_instrumentation();
63 toggle_collection();
64}
65
66/// Toggle collection state and stop instrumentation.
67#[inline(always)]
68pub fn stop() {
69 toggle_collection();
70 stop_instrumentation();
71}