-
Measuring memory usage in Rust
- The application does too many short-lived allocations (instead of re-using the buffers) the
instrumenting the calls to allocation and deallocation approach
. - If in a steady state, the application uses too much memory, the
heap parsing
would work better for pointing out which data structures need the most attention.
- The application does too many short-lived allocations (instead of re-using the buffers) the
-
Goals
- Cope with thousands or even millions of trace events per second
- Ideally, zero overhead when not used
- Support for runtime attaching or similar
-
Good to know
- Prefer to use existing tracing frameworks
- perf with sdt / uprobe
- LLVM - Xray
-
Steps
- Inject custom code into the application
- Intercept call to heap allocation, deallocation function
- Backtrace deallocation and allocation
- Tracing and profiling should be fast, Post process should be delayed.
-
Target
functions
// libc functions
malloc, free
realtoc, calloc
posix_memalign, aligned_alloc, vat loc
// libc++ functions
operator new, operator new[]]
operator delete, operator delete[]
Each with a couple of overloads, e.g. std::atign_val_t
-
Approach
- use the
dynamic linker
to inject custom library code LD_PRELAOD=$(readlink -f path/to/lib.so) app
c++
does not define how the linker works, it works on the linux level- replacing library
malloc
call
- use the
-
Good to know before understanding the code below
- learn about
extern
- Declare anywhere, use that declared part
- learn about
dlsym
- Static cast vs reinterpret_cast
reinterpret_cast
is dangerousclass object -> func(param one)
gets converted toclass::func(*this, param)
reinterpret_cast
can perform dangerous conversions because it can typecast any pointer to any other pointerreinterpret_cast
is used when you want to work with bits- the result of a
reinterpret_cast
cannot safely be used for anything other than being cast back to its original type - if we use this type of cast then it becomes a
non-portable
product
- learn about
#include <dlfcn.h> // dlsym
extern "C" {
void* malloc(sizt_t size) {
static void* original_malloc(RTLD_NEXT ,"malloc") ;
assert(original_malloc);
auto *original_malloc_fn = reinterpret_cast<decltype(&::malloc)> (original_malloc);
void •ret = original_malloc_fn(size);
fprtntf(stderr, "mattoc intercepted: gozu oop\n",
size, ret);
return ret;
}
}