allocative/lib.rs
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under both the MIT license found in the
5 * LICENSE-MIT file in the root directory of this source tree and the Apache
6 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
7 * of this source tree.
8 */
9
10//! # Allocative
11//!
12//! Crate implements lightweight memory profiler which allows
13//! object traversal and size introspection.
14//!
15//! An object implementing [`Allocative`] trait is introspectable, and this crate
16//! provides two utilities to work with such objects:
17//! * [`FlameGraphBuilder`] to build a flame graph of object tree
18//! * [`size_of_unique_allocated_data`] provides estimation
19//! of how much allocated memory the value holds
20//!
21//! ## Allocative overhead
22//!
23//! When allocative is used, binary size is slightly increased due to implementations
24//! of [`Allocative`] trait, but it has no runtime/memory overhead when it is not used.
25//!
26//! ## How it is different from other call-stack malloc profilers like jemalloc heap profiler
27//!
28//! Allocative is not a substitute for call stack malloc profiler,
29//! it provides a different view on memory usage.
30//!
31//! Here are some differences between allocative and call-stack malloc profiler:
32//!
33//! * Allocative requires implementation of [`Allocative`] trait for each type
34//! which needs to be measured, and some setup in the program to enable it
35//! * Allocative flamegraph shows object by object tree, not by call stack
36//! * Allocative shows gaps in allocated memory,
37//! e.g. spare capacity of collections or too large padding in structs or enums
38//! * Allocative allows profiling non-malloc allocations (for example, allocations within [bumpalo])
39//! * Allocative allows profiling of memory for subset of the process data
40//! (for example, measure the size of RPC response before serialization)
41//!
42//! [bumpalo]: https://github.com/fitzgen/bumpalo
43
44#![cfg_attr(rust_nightly, feature(const_type_name))]
45#![cfg_attr(rust_nightly, feature(never_type))]
46#![deny(rustdoc::broken_intra_doc_links)]
47#![allow(clippy::empty_enum)]
48
49mod allocative_trait;
50mod flamegraph;
51mod global_root;
52pub(crate) mod golden;
53mod impls;
54mod key;
55mod rc_str;
56mod size_of;
57mod test_derive;
58mod visitor;
59
60pub use allocative_derive::root;
61pub use allocative_derive::Allocative;
62
63pub use crate::allocative_trait::Allocative;
64pub use crate::flamegraph::FlameGraph;
65pub use crate::flamegraph::FlameGraphBuilder;
66pub use crate::global_root::register_root;
67pub use crate::key::Key;
68pub use crate::size_of::size_of_unique;
69pub use crate::size_of::size_of_unique_allocated_data;
70pub use crate::visitor::Visitor;
71
72#[doc(hidden)]
73pub mod __macro_refs {
74 pub use ctor;
75}
76
77/// Create a `const` of type `Key` with the provided `ident` as the value and
78/// return that value. This allows the keys to be placed conveniently inline
79/// without any performance hit because unlike calling `Key::new` this is
80/// guaranteed to be evaluated at compile time.
81///
82/// The main use case is manual implementations of [`Allocative`], like so:
83///
84/// ```
85/// use allocative::ident_key;
86/// use allocative::Allocative;
87/// use allocative::Visitor;
88///
89/// struct MyStruct {
90/// foo: usize,
91/// bar: Vec<()>,
92/// }
93///
94/// impl Allocative for MyStruct {
95/// fn visit<'a, 'b: 'a>(&self, visitor: &'a mut Visitor<'b>) {
96/// let mut visitor = visitor.enter_self(self);
97/// visitor.visit_field(ident_key!(foo), &self.foo);
98/// visitor.visit_field(ident_key!(bar), &self.bar);
99/// visitor.exit();
100/// }
101/// }
102/// ```
103#[macro_export]
104macro_rules! ident_key {
105 ($name:ident) => {{
106 const KEY: $crate::Key = $crate::Key::new(stringify!(name));
107 KEY
108 }};
109}