Expand description
🔎 loupe
is a set of tools to analyse and to profile Rust
code. For the moment, it only provides tools about memory
usage. It’s mostly driven by
Wasmer’s needs, but feel
free to propose new features!
loupe
is a French word to express magnifying glass, and can be
pronounced exactly like loop.
§Memory Usage
loupe
provides the MemoryUsage
trait. It allows to know the
size of a value in bytes, recursively. So it traverses most of
the types (some are missing, feel free to contribute!), and its
fields or variants as deep as possible. Hopefully, it tracks
already visited values so that it doesn’t enter an infinite
loupe loop. The trait looks like this:
pub trait MemoryUsage {
fn size_of_val(&self, tracker: &mut dyn MemoryUsageTracker) -> usize;
}
loupe
provides a size_of_val
function that is a close sibling
of
std::mem::size_of_val
. It
can be used the same way.
loupe
exports its best companion: handful procedural macros from
the loupe-derive
crate, to
automatically implement the MemoryUsage
trait if possible, on
struct
s and enum
s.
Thus, one only needs to write:
use loupe::MemoryUsage;
use std::mem;
#[derive(MemoryUsage)]
struct S {
x: Vec<i32>,
y: Vec<i32>,
}
fn main() {
let s = S {
x: vec![1, 2, 3],
y: vec![1, 2, 3],
};
assert_eq!(48, mem::size_of_val(&s));
assert_eq!(72, loupe::size_of_val(&s));
}
In the example above, we see that each elements of Vec<i32>
has
been counted in the size of the value s
. In
Wasmer, it is possible to
get the size of an Instance
, which traverses Module
, Store
,
Engine
, Compiler
etc. It’s an entire tree of values that is
traversed and the size of each value is summed.
§Opinionated implementations
Even if MemoryUsage
is already implemented for common types,
some types are missing. We happily welcome more implementations!
However, implementations of MemoryUsage
:
- must never alter the values,
- must never panic of fail,
- must be deterministic as much as possible (ideally, everytime).
In the same spirit, our implementation of MemoryUsage
for
*const T
or *mut T
(and other pointer types, like NonNull
,
UnsafeCell
etc.) just returns the size of the pointer, but it
doesn’t dereference the pointer as it’s unsafe. It doesn’t mean
one must not do that: It’s totally possible if it’s sure that the
pointer can be safely dereferenced.
Remember that a user can implement MemoryUsage
by hand; no
need to try to have a default implementation for all the standard
types.
Finally, our implementations are certainly not perfect! Feel free to challenge it and come to discuss!
Macros§
- Alias to
assert_eq!(loupe::MemoryUsage::size_of_val(&$value), $expected)
.
Constants§
- Size of a pointer for the compilation target.
Traits§
- Traverse a value and collect its memory usage.
- Represent a bucket that can track memory addresses that have already been visited by
MemoryUsage
.
Functions§
- Returns the size of the pointer-to value in bytes. The size is calculated with
MemoryUsage::size_of_val
.
Derive Macros§
- Procedural macro to implement the
loupe::MemoryUsage
trait automatically for structs and enums.