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