tikv_jemalloc_ctl/lib.rs
1//! `jemalloc` control and introspection.
2//!
3//! `jemalloc` offers a powerful introspection and control interface through the `mallctl` function.
4//! It can be used to tune the allocator, take heap dumps, and retrieve statistics. This crate
5//! provides a typed API over that interface.
6//!
7//! While `mallctl` takes a string to specify an operation (e.g. `stats.allocated` or
8//! `stats.arenas.15.muzzy_decay_ms`), the overhead of repeatedly parsing those strings is not
9//! ideal. Fortunately, `jemalloc` offers the ability to translate the string ahead of time into a
10//! "Management Information Base" (MIB) to speed up future lookups.
11//!
12//! This crate provides a type for each `mallctl` operation. Calling
13//! `$op::{read(), write(x), update(x)}` on the type calls `mallctl` with the
14//! string-based API. If the operation will be repeatedly performed, a MIB for
15//! the operation can be obtained using `$op.mib()`.
16#![cfg_attr(
17 feature = "stats",
18 doc = r##"
19
20# Examples
21
22Repeatedly printing allocation statistics:
23
24```no_run
25use std::thread;
26use std::time::Duration;
27use tikv_jemalloc_ctl::{stats, epoch};
28
29#[global_allocator]
30static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
31
32fn main() {
33 loop {
34 // many statistics are cached and only updated when the epoch is advanced.
35 epoch::advance().unwrap();
36
37 let allocated = stats::allocated::read().unwrap();
38 let resident = stats::resident::read().unwrap();
39 println!("{} bytes allocated/{} bytes resident", allocated, resident);
40 thread::sleep(Duration::from_secs(10));
41 }
42}
43```
44
45Doing the same with the MIB-based API:
46
47```no_run
48use std::thread;
49use std::time::Duration;
50use tikv_jemalloc_ctl::{stats, epoch};
51
52#[global_allocator]
53static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
54
55fn main() {
56 let e = epoch::mib().unwrap();
57 let allocated = stats::allocated::mib().unwrap();
58 let resident = stats::resident::mib().unwrap();
59 loop {
60 // many statistics are cached and only updated when the epoch is advanced.
61 e.advance().unwrap();
62
63 let allocated = allocated.read().unwrap();
64 let resident = resident.read().unwrap();
65 println!("{} bytes allocated/{} bytes resident", allocated, resident);
66 thread::sleep(Duration::from_secs(10));
67 }
68}
69```
70"##
71)]
72// TODO: rename the following lint on next minor bump
73#![allow(renamed_and_removed_lints)]
74#![deny(missing_docs, broken_intra_doc_links)]
75#![cfg_attr(not(feature = "use_std"), no_std)]
76
77#[cfg(test)]
78#[global_allocator]
79static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
80
81use crate::std::{fmt, mem, num, ops, ptr, result, slice, str};
82#[cfg(not(feature = "use_std"))]
83use core as std;
84#[cfg(feature = "use_std")]
85use std;
86
87#[macro_use]
88mod macros;
89
90pub mod arenas;
91pub mod config;
92mod error;
93mod keys;
94pub mod opt;
95#[cfg(feature = "profiling")]
96pub mod profiling;
97pub mod raw;
98#[cfg(feature = "stats")]
99pub mod stats;
100#[cfg(feature = "use_std")]
101pub mod stats_print;
102pub mod thread;
103
104pub use error::{Error, Result};
105pub use keys::{Access, AsName, Mib, MibStr, Name};
106
107option! {
108 version[ str: b"version\0", str: 1 ] => &'static str |
109 ops: r |
110 docs:
111 /// `jemalloc` version string.
112 ///
113 /// # Example
114 ///
115 /// ```
116 /// # #[global_allocator]
117 /// # static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
118 /// #
119 /// # fn main() {
120 /// use tikv_jemalloc_ctl::version;
121 /// println!("jemalloc version {}", version::read().unwrap());
122 /// let version_mib = version::mib().unwrap();
123 /// println!("jemalloc version {}", version_mib.read().unwrap());
124 /// # }
125 /// ```
126 mib_docs: /// See [`version`].
127}
128
129option! {
130 background_thread[ str: b"background_thread\0", non_str: 1 ] => bool |
131 ops: r,w,u |
132 docs:
133 /// State of internal background worker threads.
134 ///
135 /// When enabled, background threads are created on demand (the number of
136 /// background threads will be no more than the number of CPUs or active
137 /// arenas). Threads run periodically and handle purging asynchronously.
138 ///
139 /// ```
140 /// # #[global_allocator]
141 /// # static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
142 /// #
143 /// # fn main() {
144 /// # #[cfg(not(target_os = "macos"))] {
145 /// #
146 /// use tikv_jemalloc_ctl::background_thread;
147 /// let bg = background_thread::mib().unwrap();
148 /// let s = bg.read().unwrap();
149 /// println!("background_threads enabled: {}", s);
150 /// let p = background_thread::update(!s).unwrap();
151 /// println!("background_threads enabled: {} => {}", p, bg.read().unwrap());
152 /// assert_eq!(p, s);
153 /// background_thread::write(s).unwrap();
154 /// println!("background_threads enabled: {}", bg.read().unwrap());
155 /// assert_eq!(p, s);
156 /// #
157 /// # } // #[cfg(..)]
158 /// # }
159 /// ```
160 mib_docs: /// See [`background_thread`].
161}
162
163option! {
164 max_background_threads[ str: b"max_background_threads\0", non_str: 1 ] => libc::size_t |
165 ops: r, w, u |
166 docs:
167 /// Maximum number of background threads that will be created.
168 ///
169 /// ```
170 /// # #[global_allocator]
171 /// # static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
172 /// #
173 /// # fn main() {
174 /// # #[cfg(not(target_os = "macos"))] {
175 /// #
176 /// use tikv_jemalloc_ctl::max_background_threads;
177 /// let m = max_background_threads::mib().unwrap();
178 /// println!("max_background_threads: {}", m.read().unwrap());
179 /// m.write(2).unwrap();
180 /// assert_eq!(m.read().unwrap(), 2);
181 /// #
182 /// # } // #[cfg(..)]
183 /// # }
184 /// ```
185 mib_docs: /// See [`max_background_threads`].
186}
187
188option! {
189 epoch[ str: b"epoch\0", non_str: 1 ] => u64 |
190 ops: r, w, u |
191 docs:
192 /// `jemalloc` epoch.
193 ///
194 /// Many of the statistics tracked by `jemalloc` are cached. The epoch
195 /// controls when they are refreshed.
196 ///
197 /// # Example
198 ///
199 /// Advancing the epoch:
200 ///
201 /// ```
202 /// # #[global_allocator]
203 /// # static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
204 /// #
205 /// # fn main() {
206 /// #
207 /// use tikv_jemalloc_ctl::epoch;
208 /// let e = epoch::mib().unwrap();
209 /// let a = e.advance().unwrap();
210 /// let b = e.advance().unwrap();
211 /// assert_eq!(a + 1, b);
212 ///
213 /// let o = e.update(0).unwrap();
214 /// assert_eq!(o, e.read().unwrap());
215 /// # }
216 mib_docs: /// See [`epoch`].
217}
218
219impl epoch {
220 /// Advances the epoch returning its old value - see [`epoch`].
221 pub fn advance() -> crate::error::Result<u64> {
222 Self::update(1)
223 }
224}
225
226impl epoch_mib {
227 /// Advances the epoch returning its old value - see [`epoch`].
228 pub fn advance(self) -> crate::error::Result<u64> {
229 self.0.update(1)
230 }
231}