Function instrumentation

Hi,

is there something similar to the -finstrument-functions flag for rust? I found something called -Zinstrument-mcount or -Zxray-instrument but these seem to only work for rust-nightly builds.

Basically what I want is function hooks that can be compiled in upon entering and leaving a function.
Thanks

If it's only for a handful of functions that you have control over, I'd create a custom attribute that generates calls to your hook and use it to annotate the functions I care about.

For example, you might create a my_hooks crate that exposes an instrument attribute macro, then annotate your code like so:

#[my_hooks::instrument]
fn open_config_file() -> Result<(), Error> { ... }

The #[my_hooks::instrument] attribute would then expand to something like this:

fn open_config_file() -> Result<(), Error> {
  fn inner() -> Result<(), Error> { ... }

  my_hooks::before();
  let result = inner();
  my_hooks::after();
  result
}

The my_hooks crate would also expose those before() and after() functions, plus a way to set some global object that receives the function hooks.


static HOOKS: Mutex<Box<dyn Hooks>> = Mutex::new(Box::new(Noop));

pub trait Hooks: Send + Sync {
  fn before(&self) {}
  fn after(&self) {}
}

pub fn before() {
  HOOKS.lock().unwrap().before();
}

pub fn after() {
  HOOKS.lock().unwrap().after();
}

pub fn set_hooks(hooks: impl Hooks + 'static) {
  *HOOKS.lock().unwrap() = Box::new(hooks);
}

/// A default implementation which does nothing.
struct Noop;

impl Hooks for Noop {}

You could also use a RAII guard instead of before() and after(), but that's an implementation detail.

2 Likes

Thank you, that looks quite promising already.
The only problem I have with this approach is that it requires me to modify the to-be-instrumented code. If I want to provide a profiling library that people can simply link to their code and later remove again for production code. They do not want to modify their sources. They might just want to add a flag (like with the -finstrument-functions flag).

If you want to provide a library, then people will have no problems modifying their code – after all, they will have to pull in your library in the first place.

As for turning it off, use #[cfg(…)] attributes.

I don't understand what you mean by

I will make a comparison how it works in C, maybe this clarifies my intentions. (Or maybe it turns out that this is impossible in rust).

Consider a code like

int main() {
   int a = 1; int b=2;
   return a+b;
}

With the flag -finstrument-functions the compiler will compile the code as if it looks like this:

void __cyg_profile_func_enter (void *this_fn, void *call_site);
void __cyg_profile_func_exit  (void *this_fn, void *call_site);
int main() {
   __cyg_profile_func_enter(addr_of_main, intruction_pointer_location);
   int a=1; int b=2;
   int res = a+b;
   __cyg_profile_func_exit(addr_of_main, intruction_pointer_location);
   return res;
}

The function body of __cyg_profile_func_... is provided by a user specified library:

gcc -o my_exe my_code.c -lprofiling_library

So there is no code modification needed by a user. Only a compiler flag, and an additional linker instruction. This is regularly done in the scientific computing community with C and Fortran codes. They are profiled and optimized, but for the actual runs, the profiler is excluded again. Would be cumbersome to add #[cfg(...)] tags to thousands of functions.

Is something similar possible in rust? Automatically including hook-functions via a compiler flag and an entry of a profiling crate in the Cargo file?

Thank you for your answers

Rust supports profile-guided optimisation, which it sounds like you are effectively wanting, except it manages all the profile collection and subsequent optimisation for you.

Otherwise, there is also Instrumentation-based Code Coverage, which is similar except for code coverage.

Both approaches use LLVM's profiling machinery, so you should be able to inspect the profiling data with llvm-profdata and friends.

That said, most people will use established profiling tools like perf and flamegraph when improving performance. I've never heard of someone linking in their own profiling library.

1 Like

Thank you, I will look into those.

The VAMPIR profiler is quite famous, also vftrace is used occasionally, as well as a few other ones.