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}