1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! Memory allocation tracking utilities for benchmarks and performance analysis.
//!
//! This package provides utilities to track memory allocations during code execution,
//! enabling analysis of allocation patterns in benchmarks and performance tests.
//! The tracker reports both the number of bytes allocated and the count of allocations.
//!
//! The core functionality includes:
//! - [`Allocator`] - A Rust memory allocator wrapper that enables allocation tracking
//! - [`Session`] - Configures allocation tracking and provides access to tracking data
//! - [`Report`] - Thread-safe memory allocation statistics that can be merged and processed independently
//! - [`ProcessSpan`] - Tracks process-wide memory allocation changes over a time period
//! - [`ThreadSpan`] - Tracks thread-local memory allocation changes over a time period
//! - [`Operation`] - Calculates mean memory allocation per operation
//!
//! Additionally, when the `panic_on_next_alloc` feature is enabled:
//! - [`panic_on_next_alloc`] - Function to enable panic-on-next-allocation for debugging
//!
//! This package is not meant for use in production, serving only as a development tool.
//!
//! # Features
//!
//! - `panic_on_next_alloc`: Enables the [`panic_on_next_alloc`] function for debugging
//! unexpected allocations. This feature adds some overhead to allocations, so it is optional.
//!
//! # Simple usage
//!
//! You can track allocations like this:
//!
//! ```
//! use alloc_tracker::{Allocator, Session};
//!
//! #[global_allocator]
//! static ALLOCATOR: Allocator<std::alloc::System> = Allocator::system();
//!
//! fn main() {
//! let session = Session::new();
//!
//! // Track a single operation
//! {
//! let operation = session.operation("my_operation");
//! let _span = operation.measure_process();
//! let _data = vec![1, 2, 3, 4, 5]; // This allocates memory
//! }
//!
//! // Print results
//! session.print_to_stdout();
//!
//! // Session automatically cleans up when dropped
//! }
//! ```
//!
//! # Tracking mean allocations
//!
//! For benchmarking scenarios, where you run multiple iterations of an operation, use [`Operation`]:
//!
//! ```
//! use alloc_tracker::{Allocator, Operation, Session};
//!
//! #[global_allocator]
//! static ALLOCATOR: Allocator<std::alloc::System> = Allocator::system();
//!
//! fn main() {
//! let session = Session::new();
//!
//! // Track mean over multiple operations (batched for efficiency)
//! {
//! let mut string_op = session.operation("string_allocations");
//! let _span = string_op.measure_process().iterations(10);
//! for i in 0..10 {
//! let _data = format!("String number {}", i); // This allocates memory
//! }
//! }
//!
//! // Output statistics of all operations to console
//! session.print_to_stdout();
//! }
//! ```
//!
//! # Overhead
//!
//! In single-threaded scenarios, capturing a single measurement by calling
//! `Operation::measure_xyz()` incurs an overhead of approximately 10-15 nanoseconds
//! on an arbitrary sample machine. You are recommended to batch your measurements
//! over multiple benchmark iterations to amortize this overhead via `.iterations(N)`.
//!
//! Memory allocator activity is likewise slightly impacted by the tracking logic.
//!
//! # Session management
//!
//! Multiple [`Session`] instances can be used concurrently as they track memory allocation
//! independently. Each session maintains its own set of operations and statistics.
//!
//! While [`Session`] itself is single-threaded, reports from sessions can be converted to
//! thread-safe [`Report`] instances and sent to other threads for processing:
//!
//! ```
//! use std::thread;
//!
//! use alloc_tracker::{Allocator, Report, Session};
//!
//! #[global_allocator]
//! static ALLOCATOR: Allocator<std::alloc::System> = Allocator::system();
//!
//! # fn main() {
//! let session = Session::new();
//! {
//! let operation = session.operation("work");
//! let _span = operation.measure_process();
//! let _data = vec![1, 2, 3]; // Some allocation work
//! }
//!
//! let report = session.to_report();
//!
//! // Report can be sent to another thread
//! thread::spawn(move || {
//! report.print_to_stdout();
//! })
//! .join()
//! .unwrap();
//! # }
//! ```
//!
//! # Miri compatibility
//!
//! Miri replaces the global allocator with its own logic, so you cannot execute code that uses
//! this package under Miri.
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;