separate safe/unsafe ctl apis, test everything
This commit is contained in:
parent
7fb8e425e5
commit
1abc6d7ef8
|
@ -24,6 +24,7 @@ maintenance = { status = "actively-developed" }
|
||||||
[dependencies]
|
[dependencies]
|
||||||
jemalloc-sys = { path = "../jemalloc-sys", version = "0.3.0" }
|
jemalloc-sys = { path = "../jemalloc-sys", version = "0.3.0" }
|
||||||
libc = { version = "0.2", default-features = false }
|
libc = { version = "0.2", default-features = false }
|
||||||
|
paste = { version = "0.1" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
jemallocator = { path = "..", version = "0.3.0" }
|
jemallocator = { path = "..", version = "0.3.0" }
|
||||||
|
|
|
@ -1,64 +1,27 @@
|
||||||
//! Arena operations.
|
//! Arena operations.
|
||||||
|
|
||||||
use error::Result;
|
option! {
|
||||||
use keys::{Access, AsName, Mib};
|
narenas[ str: b"arenas.narenas\0", non_str: 2 ] => libc::c_uint |
|
||||||
use libc::c_uint;
|
ops: r |
|
||||||
|
docs:
|
||||||
const NARENAS: &[u8] = b"arenas.narenas\0";
|
/// Current limit on the number of arenas.
|
||||||
|
///
|
||||||
/// Returns the current limit on the number of arenas.
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// ```
|
||||||
///
|
/// # extern crate jemallocator;
|
||||||
/// ```
|
/// # extern crate jemalloc_ctl;
|
||||||
/// extern crate jemallocator;
|
/// #
|
||||||
/// extern crate jemalloc_ctl;
|
/// # #[global_allocator]
|
||||||
///
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
/// #[global_allocator]
|
/// #
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// # fn main() {
|
||||||
///
|
/// use jemalloc_ctl::arenas;
|
||||||
/// fn main() {
|
/// println!("number of arenas: {}", arenas::narenas::read().unwrap());
|
||||||
/// println!(
|
///
|
||||||
/// "number of arenas: {}",
|
/// let arenas_mib = arenas::narenas::mib().unwrap();
|
||||||
/// jemalloc_ctl::arenas::narenas().unwrap()
|
/// println!("number of arenas: {}", arenas_mib.read().unwrap());
|
||||||
/// );
|
/// # }
|
||||||
/// }
|
/// ```
|
||||||
/// ```
|
mib_docs: /// See [`narenas`].
|
||||||
pub fn narenas() -> Result<c_uint> {
|
|
||||||
NARENAS.name().read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type providing access to the current limit on the number of arenas.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// use jemalloc_ctl::arenas::NArenas;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let narenas = NArenas::new().unwrap();
|
|
||||||
///
|
|
||||||
/// println!("number of arenas: {}", narenas.get().unwrap());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct NArenas(Mib<[usize; 2]>);
|
|
||||||
|
|
||||||
impl NArenas {
|
|
||||||
/// Returns a new `NArenas`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = NARENAS.name().mib()?;
|
|
||||||
Ok(NArenas(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the maximum number of arenas.
|
|
||||||
pub fn get(self) -> Result<c_uint> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,181 +0,0 @@
|
||||||
//! Background thread operations.
|
|
||||||
|
|
||||||
use error::Result;
|
|
||||||
use keys::{Access, AsName, Mib};
|
|
||||||
|
|
||||||
const BACKGROUND_THREAD: &[u8] = b"background_thread\0";
|
|
||||||
|
|
||||||
/// Returns the state of internal background worker threads.
|
|
||||||
///
|
|
||||||
/// When enabled, background threads are created on demand (the number of
|
|
||||||
/// background threads will be no more than the number of CPUs or active
|
|
||||||
/// arenas). Threads run periodically and handle purging asynchronously.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// # #[cfg(not(target_os = "macos"))]
|
|
||||||
/// println!(
|
|
||||||
/// "background_thread: {}",
|
|
||||||
/// jemalloc_ctl::background_thread().unwrap()
|
|
||||||
/// );
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn background_thread() -> Result<bool> {
|
|
||||||
BACKGROUND_THREAD.name().read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enables or disables internal background worker threads.
|
|
||||||
///
|
|
||||||
/// When enabled, background threads are created on demand (the number of
|
|
||||||
/// background threads will be no more than the number of CPUs or active
|
|
||||||
/// arenas). Threads run periodically and handle purging asynchronously.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// # #[cfg(not(target_os = "macos"))] {
|
|
||||||
/// jemalloc_ctl::set_background_thread(true).unwrap();
|
|
||||||
/// assert!(jemalloc_ctl::background_thread().unwrap());
|
|
||||||
/// # }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn set_background_thread(background_thread: bool) -> Result<()> {
|
|
||||||
BACKGROUND_THREAD.name().write(background_thread)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type providing access to the state of internal background worker threads.
|
|
||||||
///
|
|
||||||
/// When enabled, background threads are created on demand (the number of
|
|
||||||
/// background threads will be no more than the number of CPUs or active
|
|
||||||
/// arenas). Threads run periodically and handle purging asynchronously.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// # #[cfg(not(target_os = "macos"))] {
|
|
||||||
/// let mut background_thread
|
|
||||||
/// = jemalloc_ctl::BackgroundThread::new().unwrap();
|
|
||||||
/// background_thread.set(true).unwrap();
|
|
||||||
/// assert!(background_thread.get().unwrap());
|
|
||||||
/// # }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct BackgroundThread(Mib<[usize; 1]>);
|
|
||||||
|
|
||||||
impl BackgroundThread {
|
|
||||||
/// Returns a new `BackgroundThread`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = BACKGROUND_THREAD.name().mib()?;
|
|
||||||
Ok(BackgroundThread(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the current background thread state.
|
|
||||||
pub fn get(self) -> Result<bool> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the background thread state.
|
|
||||||
pub fn set(self, background_thread: bool) -> Result<()> {
|
|
||||||
self.0.write(background_thread)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAX_BACKGROUND_THREADS: &[u8] = b"max_background_threads\0";
|
|
||||||
|
|
||||||
/// Returns the maximum number of background threads that will be created.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// # #[cfg(not(target_os = "macos"))]
|
|
||||||
/// println!(
|
|
||||||
/// "max_background_threads: {}",
|
|
||||||
/// jemalloc_ctl::max_background_threads().unwrap()
|
|
||||||
/// );
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn max_background_threads() -> Result<usize> {
|
|
||||||
MAX_BACKGROUND_THREADS.name().read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the maximum number of background threads that will be created.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// # #[cfg(not(target_os = "macos"))] {
|
|
||||||
/// jemalloc_ctl::set_max_background_threads(1).unwrap();
|
|
||||||
/// assert_eq!(jemalloc_ctl::max_background_threads().unwrap(), 1);
|
|
||||||
/// # }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn set_max_background_threads(max_background_threads: usize) -> Result<()> {
|
|
||||||
MAX_BACKGROUND_THREADS.name().write(max_background_threads)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type providing access to the maximum number of background threads that
|
|
||||||
/// will be created.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// # #[cfg(not(target_os = "macos"))] {
|
|
||||||
/// let mut max_background_threads
|
|
||||||
/// = jemalloc_ctl::MaxBackgroundThreads::new().unwrap();
|
|
||||||
/// max_background_threads.set(1).unwrap();
|
|
||||||
/// assert_eq!(max_background_threads.get().unwrap(), 1);
|
|
||||||
/// # }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct MaxBackgroundThreads(Mib<[usize; 1]>);
|
|
||||||
|
|
||||||
impl MaxBackgroundThreads {
|
|
||||||
/// Returns a new `MaxBackgroundThreads`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = MAX_BACKGROUND_THREADS.name().mib()?;
|
|
||||||
Ok(MaxBackgroundThreads(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the current background thread limit.
|
|
||||||
pub fn get(self) -> Result<usize> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the background thread limit.
|
|
||||||
pub fn set(self, max_background_threads: usize) -> Result<()> {
|
|
||||||
self.0.write(max_background_threads)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,69 +1,28 @@
|
||||||
//! Information about the jemalloc compile-time configuration
|
//! `jemalloc`'s build-time configuration.
|
||||||
use error::Result;
|
|
||||||
use keys::{Access, AsName, MibStr};
|
|
||||||
|
|
||||||
const MALLOC_CONF: &[u8] = b"config.malloc_conf\0";
|
option! {
|
||||||
|
malloc_conf[ str: b"config.malloc_conf\0", str: 2 ] => &'static str |
|
||||||
/// Returns the embeddec configure-time-specified run-time options config.
|
ops: r |
|
||||||
///
|
docs:
|
||||||
/// The string will be empty unless `--with-malloc-conf` was specified during
|
/// Default run-time options specified during `jemalloc`'s build configuration.
|
||||||
/// build configuration.
|
///
|
||||||
///
|
/// The string will be empty unless `--with-malloc-conf` was specified
|
||||||
/// # Examples
|
/// during build configuration.
|
||||||
///
|
///
|
||||||
/// ```
|
/// # Examples
|
||||||
/// extern crate jemallocator;
|
///
|
||||||
/// extern crate jemalloc_ctl;
|
/// ```
|
||||||
///
|
/// # extern crate jemallocator;
|
||||||
/// #[global_allocator]
|
/// # extern crate jemalloc_ctl;
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// #
|
||||||
///
|
/// # #[global_allocator]
|
||||||
/// fn main() {
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
/// println!(
|
/// #
|
||||||
/// "default malloc conf: {}",
|
/// # fn main() {
|
||||||
/// jemalloc_ctl::config::malloc_conf().unwrap()
|
/// use jemalloc_ctl::config;
|
||||||
/// );
|
/// let malloc_conf = config::malloc_conf::mib().unwrap();
|
||||||
/// }
|
/// println!("default malloc conf: {}", malloc_conf.read().unwrap());
|
||||||
/// ```
|
/// # }
|
||||||
pub fn malloc_conf() -> Result<&'static str> {
|
/// ```
|
||||||
MALLOC_CONF.name().read()
|
mib_docs: /// See [`malloc_conf`].
|
||||||
}
|
|
||||||
|
|
||||||
/// A type providing access to the embedded configure-time-specified run-time
|
|
||||||
/// options config.
|
|
||||||
///
|
|
||||||
/// The string will be empty unless `--with-malloc-conf` was specified during
|
|
||||||
/// build configuration.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// use jemalloc_ctl::config::MallocConf;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let malloc_conf = MallocConf::new().unwrap();
|
|
||||||
///
|
|
||||||
/// println!("default malloc conf: {}", malloc_conf.get().unwrap());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct MallocConf(MibStr<[usize; 2]>);
|
|
||||||
|
|
||||||
impl MallocConf {
|
|
||||||
/// Returns a new `MallocConf`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = MALLOC_CONF.name().mib_str()?;
|
|
||||||
Ok(MallocConf(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the embedded configure-time-specified run-time options config.
|
|
||||||
pub fn get(self) -> Result<&'static str> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
//! Epoch access.
|
|
||||||
|
|
||||||
use error::Result;
|
|
||||||
use keys::{Access, AsName, Mib};
|
|
||||||
|
|
||||||
const EPOCH: &[u8] = b"epoch\0";
|
|
||||||
|
|
||||||
/// Advances the jemalloc epoch, returning it.
|
|
||||||
///
|
|
||||||
/// Many of the statistics tracked by jemalloc are cached. The epoch controls
|
|
||||||
/// when they are refreshed.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// Advancing the epoch:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let a = jemalloc_ctl::epoch().unwrap();
|
|
||||||
/// let b = jemalloc_ctl::epoch().unwrap();
|
|
||||||
/// assert_eq!(a + 1, b);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn epoch() -> Result<u64> {
|
|
||||||
EPOCH.name().read_write(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type providing access to the jemalloc epoch.
|
|
||||||
///
|
|
||||||
/// Many of the statistics tracked by jemalloc are cached. The epoch controls
|
|
||||||
/// when they are refreshed.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// Advancing the epoch:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// use jemalloc_ctl::Epoch;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let epoch = Epoch::new().unwrap();
|
|
||||||
///
|
|
||||||
/// let a = epoch.advance().unwrap();
|
|
||||||
/// let b = epoch.advance().unwrap();
|
|
||||||
/// assert_eq!(a + 1, b);
|
|
||||||
/// }
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct Epoch(Mib<[usize; 1]>);
|
|
||||||
|
|
||||||
impl Epoch {
|
|
||||||
/// Returns a new `Epoch`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = EPOCH.name().mib()?;
|
|
||||||
Ok(Epoch(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Advances the epoch, returning it.
|
|
||||||
///
|
|
||||||
/// The epoch advances by 1 every time it is advanced, so the value can be
|
|
||||||
/// used to determine if another thread triggered a referesh.
|
|
||||||
pub fn advance(self) -> Result<u64> {
|
|
||||||
self.0.read_write(1)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,7 +19,7 @@ impl NonZeroT for i64 {
|
||||||
|
|
||||||
pub type NonZeroCInt = <c_int as NonZeroT>::T;
|
pub type NonZeroCInt = <c_int as NonZeroT>::T;
|
||||||
|
|
||||||
/// Error of the `jemalloc_sys::mallct`-family of functions.
|
/// Errors of the `jemalloc_sys::mallct`-family of functions.
|
||||||
///
|
///
|
||||||
/// The `jemalloc-sys` crate: `mallctl`, `mallctlnametomib`, and `mallctlbymib``
|
/// The `jemalloc-sys` crate: `mallctl`, `mallctlnametomib`, and `mallctlbymib``
|
||||||
/// functions return `0` on success; otherwise they return an error value.
|
/// functions return `0` on success; otherwise they return an error value.
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! Key types to index the _MALLCTL NAMESPACE_.
|
//! Key types to index the _MALLCTL NAMESPACE_.
|
||||||
//!
|
//!
|
||||||
//! The [`Name`] and [`Mib`] types are provided as safe indices into the
|
//! The [`Name`] and [`Mib`]/[`MibStr`] types are provided as safe indices into
|
||||||
//! _MALLCTL NAMESPACE_. These are constructed from slices via the [`AsName`]
|
//! the _MALLCTL NAMESPACE_. These are constructed from null-terminated strings
|
||||||
//! and [`IntoMib`] traits. The [`Access`] trait provides provides safe access
|
//! via the [`AsName`] trait. The [`Access`] trait provides provides safe access
|
||||||
//! into the `_MALLCTL NAMESPACE_`.
|
//! into the `_MALLCTL NAMESPACE_`.
|
||||||
//!
|
//!
|
||||||
//! # Example
|
//! # Example
|
||||||
|
@ -57,7 +57,13 @@ impl AsName for [u8] {
|
||||||
"cannot create Name from non-null-terminated byte-string \"{}\"",
|
"cannot create Name from non-null-terminated byte-string \"{}\"",
|
||||||
str::from_utf8(self).unwrap()
|
str::from_utf8(self).unwrap()
|
||||||
);
|
);
|
||||||
unsafe { &*(self as *const [u8] as *const Name) }
|
unsafe { &*(self as *const Self as *const Name) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsName for str {
|
||||||
|
fn name(&self) -> &Name {
|
||||||
|
self.as_bytes().name()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +114,11 @@ impl Name {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the name as null-terminated byte-string.
|
||||||
|
pub fn as_bytes(&self) -> &'static [u8] {
|
||||||
|
unsafe { &*(self as *const Self as *const [u8]) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Name {
|
impl fmt::Debug for Name {
|
||||||
|
@ -124,16 +135,28 @@ impl fmt::Display for Name {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Management Information Base.
|
/// Management Information Base of a non-string value.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Copy, Clone, PartialEq, Debug, Default)]
|
#[derive(Copy, Clone, PartialEq, Debug, Default)]
|
||||||
pub struct Mib<T: MibArg>(T);
|
pub struct Mib<T: MibArg>(T);
|
||||||
|
|
||||||
/// Management Information Base refering to a string value.
|
/// Management Information Base of a string value.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Copy, Clone, PartialEq, Debug, Default)]
|
#[derive(Copy, Clone, PartialEq, Debug, Default)]
|
||||||
pub struct MibStr<T: MibArg>(T);
|
pub struct MibStr<T: MibArg>(T);
|
||||||
|
|
||||||
|
impl<T: MibArg> AsRef<[usize]> for Mib<T> {
|
||||||
|
fn as_ref(&self) -> &[usize] {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: MibArg> AsMut<[usize]> for Mib<T> {
|
||||||
|
fn as_mut(&mut self) -> &mut [usize] {
|
||||||
|
self.0.as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: MibArg> ops::Index<usize> for Mib<T> {
|
impl<T: MibArg> ops::Index<usize> for Mib<T> {
|
||||||
type Output = usize;
|
type Output = usize;
|
||||||
fn index(&self, idx: usize) -> &Self::Output {
|
fn index(&self, idx: usize) -> &Self::Output {
|
||||||
|
@ -167,31 +190,31 @@ pub trait Access<T> {
|
||||||
/// Write `value` at the key `self`.
|
/// Write `value` at the key `self`.
|
||||||
fn write(&self, value: T) -> Result<()>;
|
fn write(&self, value: T) -> Result<()>;
|
||||||
/// Write `value` at the key `self` returning its previous value.
|
/// Write `value` at the key `self` returning its previous value.
|
||||||
fn read_write(&self, value: T) -> Result<T>;
|
fn update(&self, value: T) -> Result<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_access {
|
macro_rules! impl_access {
|
||||||
($id:ty) => {
|
($id:ty) => {
|
||||||
impl<T: MibArg> Access<$id> for Mib<T> {
|
impl<T: MibArg> Access<$id> for Mib<T> {
|
||||||
fn read(&self) -> Result<$id> {
|
fn read(&self) -> Result<$id> {
|
||||||
unsafe { raw::get_mib(self.0.as_ref()) }
|
unsafe { raw::read_mib(self.0.as_ref()) }
|
||||||
}
|
}
|
||||||
fn write(&self, value: $id) -> Result<()> {
|
fn write(&self, value: $id) -> Result<()> {
|
||||||
unsafe { raw::set_mib(self.0.as_ref(), value) }
|
unsafe { raw::write_mib(self.0.as_ref(), value) }
|
||||||
}
|
}
|
||||||
fn read_write(&self, value: $id) -> Result<$id> {
|
fn update(&self, value: $id) -> Result<$id> {
|
||||||
unsafe { raw::get_set_mib(self.0.as_ref(), value) }
|
unsafe { raw::update_mib(self.0.as_ref(), value) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Access<$id> for Name {
|
impl Access<$id> for Name {
|
||||||
fn read(&self) -> Result<$id> {
|
fn read(&self) -> Result<$id> {
|
||||||
unsafe { raw::get(&self.0) }
|
unsafe { raw::read(&self.0) }
|
||||||
}
|
}
|
||||||
fn write(&self, value: $id) -> Result<()> {
|
fn write(&self, value: $id) -> Result<()> {
|
||||||
unsafe { raw::set(&self.0, value) }
|
unsafe { raw::write(&self.0, value) }
|
||||||
}
|
}
|
||||||
fn read_write(&self, value: $id) -> Result<$id> {
|
fn update(&self, value: $id) -> Result<$id> {
|
||||||
unsafe { raw::get_set(&self.0, value) }
|
unsafe { raw::update(&self.0, value) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -205,17 +228,17 @@ impl_access!(usize);
|
||||||
impl<T: MibArg> Access<bool> for Mib<T> {
|
impl<T: MibArg> Access<bool> for Mib<T> {
|
||||||
fn read(&self) -> Result<bool> {
|
fn read(&self) -> Result<bool> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let v: u8 = raw::get_mib(self.0.as_ref())?;
|
let v: u8 = raw::read_mib(self.0.as_ref())?;
|
||||||
assert!(v == 0 || v == 1);
|
assert!(v == 0 || v == 1);
|
||||||
Ok(v == 1)
|
Ok(v == 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn write(&self, value: bool) -> Result<()> {
|
fn write(&self, value: bool) -> Result<()> {
|
||||||
unsafe { raw::set_mib(self.0.as_ref(), value) }
|
unsafe { raw::write_mib(self.0.as_ref(), value) }
|
||||||
}
|
}
|
||||||
fn read_write(&self, value: bool) -> Result<bool> {
|
fn update(&self, value: bool) -> Result<bool> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let v: u8 = raw::get_set_mib(self.0.as_ref(), value as u8)?;
|
let v: u8 = raw::update_mib(self.0.as_ref(), value as u8)?;
|
||||||
Ok(v == 1)
|
Ok(v == 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,17 +247,17 @@ impl<T: MibArg> Access<bool> for Mib<T> {
|
||||||
impl Access<bool> for Name {
|
impl Access<bool> for Name {
|
||||||
fn read(&self) -> Result<bool> {
|
fn read(&self) -> Result<bool> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let v: u8 = raw::get(&self.0)?;
|
let v: u8 = raw::read(&self.0)?;
|
||||||
assert!(v == 0 || v == 1);
|
assert!(v == 0 || v == 1);
|
||||||
Ok(v == 1)
|
Ok(v == 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn write(&self, value: bool) -> Result<()> {
|
fn write(&self, value: bool) -> Result<()> {
|
||||||
unsafe { raw::set(&self.0, value) }
|
unsafe { raw::write(&self.0, value) }
|
||||||
}
|
}
|
||||||
fn read_write(&self, value: bool) -> Result<bool> {
|
fn update(&self, value: bool) -> Result<bool> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let v: u8 = raw::get_set(&self.0, value as u8)?;
|
let v: u8 = raw::update(&self.0, value as u8)?;
|
||||||
Ok(v == 1)
|
Ok(v == 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,15 +267,15 @@ impl<T: MibArg> Access<&'static [u8]> for MibStr<T> {
|
||||||
fn read(&self) -> Result<&'static [u8]> {
|
fn read(&self) -> Result<&'static [u8]> {
|
||||||
// this is safe because the only safe way to construct a `MibStr` is by
|
// this is safe because the only safe way to construct a `MibStr` is by
|
||||||
// validating that the key refers to a byte-string value
|
// validating that the key refers to a byte-string value
|
||||||
unsafe { raw::get_str_mib(self.0.as_ref()) }
|
unsafe { raw::read_str_mib(self.0.as_ref()) }
|
||||||
}
|
}
|
||||||
fn write(&self, value: &'static [u8]) -> Result<()> {
|
fn write(&self, value: &'static [u8]) -> Result<()> {
|
||||||
raw::set_str_mib(self.0.as_ref(), value)
|
raw::write_str_mib(self.0.as_ref(), value)
|
||||||
}
|
}
|
||||||
fn read_write(&self, value: &'static [u8]) -> Result<&'static [u8]> {
|
fn update(&self, value: &'static [u8]) -> Result<&'static [u8]> {
|
||||||
// this is safe because the only safe way to construct a `MibStr` is by
|
// this is safe because the only safe way to construct a `MibStr` is by
|
||||||
// validating that the key refers to a byte-string value
|
// validating that the key refers to a byte-string value
|
||||||
unsafe { raw::get_set_str_mib(self.0.as_ref(), value) }
|
unsafe { raw::update_str_mib(self.0.as_ref(), value) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,7 +287,7 @@ impl Access<&'static [u8]> for Name {
|
||||||
self
|
self
|
||||||
);
|
);
|
||||||
// this is safe because the key refers to a byte string:
|
// this is safe because the key refers to a byte string:
|
||||||
unsafe { raw::get_str(&self.0) }
|
unsafe { raw::read_str(&self.0) }
|
||||||
}
|
}
|
||||||
fn write(&self, value: &'static [u8]) -> Result<()> {
|
fn write(&self, value: &'static [u8]) -> Result<()> {
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -272,16 +295,16 @@ impl Access<&'static [u8]> for Name {
|
||||||
"the name \"{:?}\" does not refer to a byte string",
|
"the name \"{:?}\" does not refer to a byte string",
|
||||||
self
|
self
|
||||||
);
|
);
|
||||||
raw::set_str(&self.0, value)
|
raw::write_str(&self.0, value)
|
||||||
}
|
}
|
||||||
fn read_write(&self, value: &'static [u8]) -> Result<&'static [u8]> {
|
fn update(&self, value: &'static [u8]) -> Result<&'static [u8]> {
|
||||||
assert!(
|
assert!(
|
||||||
self.value_type_str(),
|
self.value_type_str(),
|
||||||
"the name \"{:?}\" does not refer to a byte string",
|
"the name \"{:?}\" does not refer to a byte string",
|
||||||
self
|
self
|
||||||
);
|
);
|
||||||
// this is safe because the key refers to a byte string:
|
// this is safe because the key refers to a byte string:
|
||||||
unsafe { raw::get_set_str(&self.0, value) }
|
unsafe { raw::update_str(&self.0, value) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,16 +312,16 @@ impl<T: MibArg> Access<&'static str> for MibStr<T> {
|
||||||
fn read(&self) -> Result<&'static str> {
|
fn read(&self) -> Result<&'static str> {
|
||||||
// this is safe because the only safe way to construct a `MibStr` is by
|
// this is safe because the only safe way to construct a `MibStr` is by
|
||||||
// validating that the key refers to a byte-string value
|
// validating that the key refers to a byte-string value
|
||||||
let s = unsafe { raw::get_str_mib(self.0.as_ref())? };
|
let s = unsafe { raw::read_str_mib(self.0.as_ref())? };
|
||||||
Ok(str::from_utf8(s).unwrap())
|
Ok(str::from_utf8(s).unwrap())
|
||||||
}
|
}
|
||||||
fn write(&self, value: &'static str) -> Result<()> {
|
fn write(&self, value: &'static str) -> Result<()> {
|
||||||
raw::set_str_mib(self.0.as_ref(), value.as_bytes())
|
raw::write_str_mib(self.0.as_ref(), value.as_bytes())
|
||||||
}
|
}
|
||||||
fn read_write(&self, value: &'static str) -> Result<&'static str> {
|
fn update(&self, value: &'static str) -> Result<&'static str> {
|
||||||
// this is safe because the only safe way to construct a `MibStr` is by
|
// this is safe because the only safe way to construct a `MibStr` is by
|
||||||
// validating that the key refers to a byte-string value
|
// validating that the key refers to a byte-string value
|
||||||
let s = unsafe { raw::get_set_str_mib(self.0.as_ref(), value.as_bytes())? };
|
let s = unsafe { raw::update_str_mib(self.0.as_ref(), value.as_bytes())? };
|
||||||
Ok(str::from_utf8(s).unwrap())
|
Ok(str::from_utf8(s).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,7 +334,7 @@ impl Access<&'static str> for Name {
|
||||||
self
|
self
|
||||||
);
|
);
|
||||||
// this is safe because the key refers to a byte string:
|
// this is safe because the key refers to a byte string:
|
||||||
let s = unsafe { raw::get_str(&self.0)? };
|
let s = unsafe { raw::read_str(&self.0)? };
|
||||||
Ok(str::from_utf8(s).unwrap())
|
Ok(str::from_utf8(s).unwrap())
|
||||||
}
|
}
|
||||||
fn write(&self, value: &'static str) -> Result<()> {
|
fn write(&self, value: &'static str) -> Result<()> {
|
||||||
|
@ -320,16 +343,16 @@ impl Access<&'static str> for Name {
|
||||||
"the name \"{:?}\" does not refer to a byte string",
|
"the name \"{:?}\" does not refer to a byte string",
|
||||||
self
|
self
|
||||||
);
|
);
|
||||||
raw::set_str(&self.0, value.as_bytes())
|
raw::write_str(&self.0, value.as_bytes())
|
||||||
}
|
}
|
||||||
fn read_write(&self, value: &'static str) -> Result<&'static str> {
|
fn update(&self, value: &'static str) -> Result<&'static str> {
|
||||||
assert!(
|
assert!(
|
||||||
self.value_type_str(),
|
self.value_type_str(),
|
||||||
"the name \"{:?}\" does not refer to a byte string",
|
"the name \"{:?}\" does not refer to a byte string",
|
||||||
self
|
self
|
||||||
);
|
);
|
||||||
// this is safe because the key refers to a byte string:
|
// this is safe because the key refers to a byte string:
|
||||||
let s = unsafe { raw::get_set_str(&self.0, value.as_bytes())? };
|
let s = unsafe { raw::update_str(&self.0, value.as_bytes())? };
|
||||||
Ok(str::from_utf8(s).unwrap())
|
Ok(str::from_utf8(s).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
//! ideal. Fortunately, `jemalloc` offers the ability to translate the string ahead of time into a
|
//! ideal. Fortunately, `jemalloc` offers the ability to translate the string ahead of time into a
|
||||||
//! "Management Information Base" (MIB) to speed up future lookups.
|
//! "Management Information Base" (MIB) to speed up future lookups.
|
||||||
//!
|
//!
|
||||||
//! This crate provides both a function and a type for each `mallctl` operation. While the
|
//! This crate provides a type for each `mallctl` operation. Calling
|
||||||
//! function is more convenient, the type will be more efficient if the operation will be repeatedly
|
//! `$op::{read(), write(x), update(x)}` on the type calls `mallctl` with the
|
||||||
//! performed. Its constructor performs the MIB lookup, so the struct should be saved if the same
|
//! string-based API. If the operation will be repeatedly performed, a MIB for
|
||||||
//! operation is going to be repeatedly performed.
|
//! the operation can be obtained using `$op.mib()`.
|
||||||
//!
|
//!
|
||||||
//! # Examples
|
//! # Examples
|
||||||
//!
|
//!
|
||||||
|
@ -24,6 +24,7 @@
|
||||||
//!
|
//!
|
||||||
//! use std::thread;
|
//! use std::thread;
|
||||||
//! use std::time::Duration;
|
//! use std::time::Duration;
|
||||||
|
//! use jemalloc_ctl::{stats, epoch};
|
||||||
//!
|
//!
|
||||||
//! #[global_allocator]
|
//! #[global_allocator]
|
||||||
//! static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
//! static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
|
@ -31,10 +32,10 @@
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! loop {
|
//! loop {
|
||||||
//! // many statistics are cached and only updated when the epoch is advanced.
|
//! // many statistics are cached and only updated when the epoch is advanced.
|
||||||
//! jemalloc_ctl::epoch().unwrap();
|
//! epoch::advance().unwrap();
|
||||||
//!
|
//!
|
||||||
//! let allocated = jemalloc_ctl::stats::allocated().unwrap();
|
//! let allocated = stats::allocated::read().unwrap();
|
||||||
//! let resident = jemalloc_ctl::stats::resident().unwrap();
|
//! let resident = stats::resident::read().unwrap();
|
||||||
//! println!("{} bytes allocated/{} bytes resident", allocated, resident);
|
//! println!("{} bytes allocated/{} bytes resident", allocated, resident);
|
||||||
//! thread::sleep(Duration::from_secs(10));
|
//! thread::sleep(Duration::from_secs(10));
|
||||||
//! }
|
//! }
|
||||||
|
@ -49,20 +50,21 @@
|
||||||
//!
|
//!
|
||||||
//! use std::thread;
|
//! use std::thread;
|
||||||
//! use std::time::Duration;
|
//! use std::time::Duration;
|
||||||
|
//! use jemalloc_ctl::{stats, epoch};
|
||||||
//!
|
//!
|
||||||
//! #[global_allocator]
|
//! #[global_allocator]
|
||||||
//! static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
//! static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! let epoch = jemalloc_ctl::Epoch::new().unwrap();
|
//! let e = epoch::mib().unwrap();
|
||||||
//! let allocated = jemalloc_ctl::stats::Allocated::new().unwrap();
|
//! let allocated = stats::allocated::mib().unwrap();
|
||||||
//! let resident = jemalloc_ctl::stats::Resident::new().unwrap();
|
//! let resident = stats::resident::mib().unwrap();
|
||||||
//! loop {
|
//! loop {
|
||||||
//! // many statistics are cached and only updated when the epoch is advanced.
|
//! // many statistics are cached and only updated when the epoch is advanced.
|
||||||
//! epoch.advance().unwrap();
|
//! e.advance().unwrap();
|
||||||
//!
|
//!
|
||||||
//! let allocated = allocated.get().unwrap();
|
//! let allocated = allocated.read().unwrap();
|
||||||
//! let resident = resident.get().unwrap();
|
//! let resident = resident.read().unwrap();
|
||||||
//! println!("{} bytes allocated/{} bytes resident", allocated, resident);
|
//! println!("{} bytes allocated/{} bytes resident", allocated, resident);
|
||||||
//! thread::sleep(Duration::from_secs(10));
|
//! thread::sleep(Duration::from_secs(10));
|
||||||
//! }
|
//! }
|
||||||
|
@ -75,6 +77,7 @@
|
||||||
|
|
||||||
extern crate jemalloc_sys;
|
extern crate jemalloc_sys;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
extern crate paste;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate jemallocator;
|
extern crate jemallocator;
|
||||||
|
@ -87,10 +90,11 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
use core as std;
|
use core as std;
|
||||||
use std::{fmt, mem, num, ops, ptr, result, slice, str};
|
use std::{fmt, mem, num, ops, ptr, result, slice, str};
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
|
||||||
pub mod arenas;
|
pub mod arenas;
|
||||||
mod background_threads;
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
mod epoch;
|
|
||||||
mod error;
|
mod error;
|
||||||
mod keys;
|
mod keys;
|
||||||
pub mod opt;
|
pub mod opt;
|
||||||
|
@ -99,10 +103,143 @@ pub mod stats;
|
||||||
#[cfg(feature = "use_std")]
|
#[cfg(feature = "use_std")]
|
||||||
pub mod stats_print;
|
pub mod stats_print;
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
mod version;
|
|
||||||
|
|
||||||
pub use background_threads::*;
|
|
||||||
pub use epoch::*;
|
|
||||||
pub use error::{Error, Result};
|
pub use error::{Error, Result};
|
||||||
pub use keys::{Access, AsName, Mib, MibStr, Name};
|
pub use keys::{Access, AsName, Mib, MibStr, Name};
|
||||||
pub use version::*;
|
|
||||||
|
option! {
|
||||||
|
version[ str: b"version\0", str: 1 ] => &'static str |
|
||||||
|
ops: r |
|
||||||
|
docs:
|
||||||
|
/// `jemalloc` version string.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # extern crate jemallocator;
|
||||||
|
/// # extern crate jemalloc_ctl;
|
||||||
|
/// #
|
||||||
|
/// # #[global_allocator]
|
||||||
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use jemalloc_ctl::version;
|
||||||
|
/// println!("jemalloc version {}", version::read().unwrap());
|
||||||
|
/// let version_mib = version::mib().unwrap();
|
||||||
|
/// println!("jemalloc version {}", version_mib.read().unwrap());
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
mib_docs: /// See [`version`].
|
||||||
|
}
|
||||||
|
|
||||||
|
option! {
|
||||||
|
background_thread[ str: b"background_thread\0", non_str: 1 ] => bool |
|
||||||
|
ops: r,w,u |
|
||||||
|
docs:
|
||||||
|
/// State of internal background worker threads.
|
||||||
|
///
|
||||||
|
/// When enabled, background threads are created on demand (the number of
|
||||||
|
/// background threads will be no more than the number of CPUs or active
|
||||||
|
/// arenas). Threads run periodically and handle purging asynchronously.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # extern crate jemallocator;
|
||||||
|
/// # extern crate jemalloc_ctl;
|
||||||
|
/// #
|
||||||
|
/// # #[global_allocator]
|
||||||
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// # #[cfg(not(target_os = "macos"))] {
|
||||||
|
/// #
|
||||||
|
/// use jemalloc_ctl::background_thread;
|
||||||
|
/// let s = background_thread::read().unwrap();
|
||||||
|
/// println!("background_threads enabled: {}", s);
|
||||||
|
/// let p = background_thread::update(!s).unwrap();
|
||||||
|
/// assert_eq!(p, s);
|
||||||
|
/// let s = background_thread::read().unwrap();
|
||||||
|
/// assert_ne!(p, s);
|
||||||
|
/// background_thread::write(!s).unwrap();
|
||||||
|
/// assert_eq!(p, s);
|
||||||
|
/// #
|
||||||
|
/// # } // #[cfg(..)]
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
mib_docs: /// See [`background_thread`].
|
||||||
|
}
|
||||||
|
|
||||||
|
option! {
|
||||||
|
max_background_threads[ str: b"max_background_threads\0", non_str: 1 ] => libc::size_t |
|
||||||
|
ops: r, w, u |
|
||||||
|
docs:
|
||||||
|
/// Maximum number of background threads that will be created.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # extern crate jemallocator;
|
||||||
|
/// # extern crate jemalloc_ctl;
|
||||||
|
/// #
|
||||||
|
/// # #[global_allocator]
|
||||||
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// # #[cfg(not(target_os = "macos"))] {
|
||||||
|
/// #
|
||||||
|
/// use jemalloc_ctl::max_background_threads;
|
||||||
|
/// let n = max_background_threads::read().unwrap();
|
||||||
|
/// println!("max_background_threads: {}", n);
|
||||||
|
/// max_background_threads::write(n + 1).unwrap();
|
||||||
|
/// assert_eq!(max_background_threads::read().unwrap(), n + 1);
|
||||||
|
/// #
|
||||||
|
/// # } // #[cfg(..)]
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
mib_docs: /// See [`max_background_threads`].
|
||||||
|
}
|
||||||
|
|
||||||
|
option! {
|
||||||
|
epoch[ str: b"epoch\0", non_str: 1 ] => u64 |
|
||||||
|
ops: r, w, u |
|
||||||
|
docs:
|
||||||
|
/// `jemalloc` epoch.
|
||||||
|
///
|
||||||
|
/// Many of the statistics tracked by `jemalloc` are cached. The epoch
|
||||||
|
/// controls when they are refreshed.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// Advancing the epoch:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # extern crate jemallocator;
|
||||||
|
/// # extern crate jemalloc_ctl;
|
||||||
|
/// #
|
||||||
|
/// # #[global_allocator]
|
||||||
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// #
|
||||||
|
/// use jemalloc_ctl::epoch;
|
||||||
|
/// let e = epoch::mib().unwrap();
|
||||||
|
/// let a = e.advance().unwrap();
|
||||||
|
/// let b = e.advance().unwrap();
|
||||||
|
/// assert_eq!(a + 1, b);
|
||||||
|
///
|
||||||
|
/// let o = e.update(0).unwrap();
|
||||||
|
/// assert_eq!(o, e.read().unwrap());
|
||||||
|
/// # }
|
||||||
|
mib_docs: /// See [`epoch`].
|
||||||
|
}
|
||||||
|
|
||||||
|
impl epoch {
|
||||||
|
/// Advances the epoch returning its old value - see [`epoch`].
|
||||||
|
pub fn advance() -> ::error::Result<u64> {
|
||||||
|
Self::update(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl epoch_mib {
|
||||||
|
/// Advances the epoch returning its old value - see [`epoch`].
|
||||||
|
pub fn advance(self) -> ::error::Result<u64> {
|
||||||
|
self.0.update(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,210 @@
|
||||||
|
//! Utility macros
|
||||||
|
|
||||||
|
macro_rules! types {
|
||||||
|
($id:ident[ str: $byte_string:expr, $mib:ty, $name_to_mib:ident ] |
|
||||||
|
docs: $(#[$doc:meta])*
|
||||||
|
mib_docs: $(#[$doc_mib:meta])*
|
||||||
|
) => {
|
||||||
|
paste::item! {
|
||||||
|
$(#[$doc])*
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct $id;
|
||||||
|
|
||||||
|
impl $id {
|
||||||
|
const NAME: &'static ::keys::Name = {
|
||||||
|
union U<'a> {
|
||||||
|
bytes: &'a [u8],
|
||||||
|
name: &'a ::keys::Name
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { U { bytes: $byte_string }.name }
|
||||||
|
};
|
||||||
|
/// Returns Management Information Base (MIB)
|
||||||
|
///
|
||||||
|
/// This value can be used to access the key without doing string lookup.
|
||||||
|
pub fn mib() -> ::error::Result<[<$id _mib>]> {
|
||||||
|
Ok([<$id _mib>](Self::NAME.$name_to_mib()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Key [`Name`].
|
||||||
|
pub fn name() -> &'static ::keys::Name {
|
||||||
|
Self::NAME
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(#[$doc_mib])*
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct [<$id _mib>](pub ::keys::$mib);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read
|
||||||
|
macro_rules! r {
|
||||||
|
($id:ident => $ret_ty:ty) => {
|
||||||
|
paste::item! {
|
||||||
|
impl $id {
|
||||||
|
/// Reads value using string API.
|
||||||
|
pub fn read() -> ::error::Result<$ret_ty> {
|
||||||
|
use ::keys::Access;
|
||||||
|
Self::NAME.read()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl [<$id _mib>] {
|
||||||
|
/// Reads value using MIB API.
|
||||||
|
pub fn read(self) -> ::error::Result<$ret_ty> {
|
||||||
|
use ::keys::Access;
|
||||||
|
self.0.read()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn [<$id _read_test>]() {
|
||||||
|
match stringify!($id) {
|
||||||
|
"background_thread" |
|
||||||
|
"max_background_threads"
|
||||||
|
if cfg!(target_os = "macos") => return,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = $id::read().unwrap();
|
||||||
|
|
||||||
|
let mib = $id::mib().unwrap();
|
||||||
|
let _ = mib.read().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write
|
||||||
|
macro_rules! w {
|
||||||
|
($id:ident => $ret_ty:ty) => {
|
||||||
|
paste::item! {
|
||||||
|
impl $id {
|
||||||
|
/// Writes `value` using string API.
|
||||||
|
pub fn write(value: $ret_ty) -> ::error::Result<()> {
|
||||||
|
use ::keys::Access;
|
||||||
|
Self::NAME.write(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl [<$id _mib>] {
|
||||||
|
/// Writes `value` using MIB API.
|
||||||
|
pub fn write(self, value: $ret_ty) -> ::error::Result<()> {
|
||||||
|
use ::keys::Access;
|
||||||
|
self.0.write(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn [<$id _write_test>]() {
|
||||||
|
match stringify!($id) {
|
||||||
|
"background_thread" |
|
||||||
|
"max_background_threads"
|
||||||
|
if cfg!(target_os = "macos") => return,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = $id::write($ret_ty::default()).unwrap();
|
||||||
|
|
||||||
|
let mib = $id::mib().unwrap();
|
||||||
|
let _ = mib.write($ret_ty::default()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update
|
||||||
|
macro_rules! u {
|
||||||
|
($id:ident => $ret_ty:ty) => {
|
||||||
|
paste::item! {
|
||||||
|
impl $id {
|
||||||
|
/// Updates key to `value` returning its old value using string API.
|
||||||
|
pub fn update(value: $ret_ty) -> ::error::Result<$ret_ty> {
|
||||||
|
use ::keys::Access;
|
||||||
|
Self::NAME.update(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl [<$id _mib>] {
|
||||||
|
/// Updates key to `value` returning its old value using MIB API.
|
||||||
|
pub fn update(self, value: $ret_ty) -> ::error::Result<$ret_ty> {
|
||||||
|
use ::keys::Access;
|
||||||
|
self.0.update(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn [<$id _update_test>]() {
|
||||||
|
match stringify!($id) {
|
||||||
|
"background_thread" |
|
||||||
|
"max_background_threads"
|
||||||
|
if cfg!(target_os = "macos") => return,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = $id::update($ret_ty::default()).unwrap();
|
||||||
|
|
||||||
|
let mib = $id::mib().unwrap();
|
||||||
|
let _ = mib.update($ret_ty::default()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new option
|
||||||
|
macro_rules! option {
|
||||||
|
($id:ident[ str: $byte_string:expr, $mib:ty, $name_to_mib:ident ] => $ret_ty:ty |
|
||||||
|
ops: $($ops:ident),* |
|
||||||
|
docs:
|
||||||
|
$(#[$doc:meta])*
|
||||||
|
mib_docs:
|
||||||
|
$(#[$doc_mib:meta])*
|
||||||
|
) => {
|
||||||
|
types! {
|
||||||
|
$id[ str: $byte_string, $mib, $name_to_mib ] |
|
||||||
|
docs: $(#[$doc])*
|
||||||
|
mib_docs: $(#[$doc_mib])*
|
||||||
|
}
|
||||||
|
$(
|
||||||
|
$ops!($id => $ret_ty);
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
// Non-string option:
|
||||||
|
($id:ident[ str: $byte_string:expr, non_str: $mib_len:expr ] => $ret_ty:ty |
|
||||||
|
ops: $($ops:ident),* |
|
||||||
|
docs:
|
||||||
|
$(#[$doc:meta])*
|
||||||
|
mib_docs:
|
||||||
|
$(#[$doc_mib:meta])*
|
||||||
|
) => {
|
||||||
|
option! {
|
||||||
|
$id[ str: $byte_string, Mib<[usize; $mib_len]>, mib ] => $ret_ty |
|
||||||
|
ops: $($ops),* |
|
||||||
|
docs: $(#[$doc])*
|
||||||
|
mib_docs: $(#[$doc_mib])*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// String option:
|
||||||
|
($id:ident[ str: $byte_string:expr, str: $mib_len:expr ] => $ret_ty:ty |
|
||||||
|
ops: $($ops:ident),* |
|
||||||
|
docs:
|
||||||
|
$(#[$doc:meta])*
|
||||||
|
mib_docs:
|
||||||
|
$(#[$doc_mib:meta])*
|
||||||
|
) => {
|
||||||
|
option! {
|
||||||
|
$id[ str: $byte_string, MibStr<[usize; $mib_len]>, mib_str ] => $ret_ty |
|
||||||
|
ops: $($ops),* |
|
||||||
|
docs: $(#[$doc])*
|
||||||
|
mib_docs: $(#[$doc_mib])*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,523 +1,241 @@
|
||||||
//! Information about the run-time `jemalloc` configuration.
|
//! `jemalloc`'s run-time configuration.
|
||||||
//!
|
//!
|
||||||
//! These settings are controlled by the `MALLOC_CONF` environment variable.
|
//! These settings are controlled by the `MALLOC_CONF` environment variable.
|
||||||
use error::Result;
|
|
||||||
use keys::{Access, AsName, Mib, MibStr};
|
|
||||||
use libc::c_uint;
|
|
||||||
|
|
||||||
const ABORT: &[u8] = b"opt.abort\0";
|
option! {
|
||||||
|
abort[ str: b"opt.abort\0", non_str: 2 ] => bool |
|
||||||
/// Determines if `jemalloc` will call `abort(3)` on most warnings.
|
ops: r |
|
||||||
///
|
docs:
|
||||||
/// This is disabled by default unless `--enable-debug` was specified during build configuration.
|
/// Whether `jemalloc` calls `abort(3)` on most warnings.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// This is disabled by default unless `--enable-debug` was specified during
|
||||||
///
|
/// build configuration.
|
||||||
/// ```
|
///
|
||||||
/// extern crate jemallocator;
|
/// # Examples
|
||||||
/// extern crate jemalloc_ctl;
|
///
|
||||||
///
|
/// ```
|
||||||
/// #[global_allocator]
|
/// # extern crate jemallocator;
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// # extern crate jemalloc_ctl;
|
||||||
///
|
/// #
|
||||||
/// fn main() {
|
/// # #[global_allocator]
|
||||||
/// println!("abort on warning: {}", jemalloc_ctl::opt::abort().unwrap());
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
/// }
|
/// #
|
||||||
/// ```
|
/// # fn main() {
|
||||||
pub fn abort() -> Result<bool> {
|
/// use jemalloc_ctl::opt;
|
||||||
ABORT.name().read()
|
/// let abort = opt::abort::mib().unwrap();
|
||||||
|
/// println!("abort on warning: {}", abort.read().unwrap());
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
mib_docs: /// See [`abort`].
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type determining if `jemalloc` will call `abort(3)` on most warnings.
|
option! {
|
||||||
///
|
dss[ str: b"opt.dss\0", str: 2 ] => &'static str |
|
||||||
/// This is disabled by default unless `--enable-debug` was specified during build configuration.
|
ops: r |
|
||||||
///
|
docs:
|
||||||
/// # Examples
|
/// The `dss` (`sbrk(2)`) allocation precedence as related to `mmap(2)`
|
||||||
///
|
/// allocation.
|
||||||
/// ```
|
///
|
||||||
/// extern crate jemallocator;
|
/// The following settings are supported if `sbrk(2)` is supported by the
|
||||||
/// extern crate jemalloc_ctl;
|
/// operating system: "disabled", "primary", and "secondary"; otherwise only
|
||||||
///
|
/// "disabled" is supported. The default is "secondary" if `sbrk(2)` is
|
||||||
/// use jemalloc_ctl::opt::Abort;
|
/// supported by the operating system; "disabled" otherwise.
|
||||||
///
|
///
|
||||||
/// #[global_allocator]
|
/// # Examples
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
///
|
||||||
///
|
/// ```
|
||||||
/// fn main() {
|
/// # extern crate jemallocator;
|
||||||
/// let abort = Abort::new().unwrap();
|
/// # extern crate jemalloc_ctl;
|
||||||
///
|
/// #
|
||||||
/// println!("abort on warning: {}", abort.get().unwrap());
|
/// # #[global_allocator]
|
||||||
/// }
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
/// ```
|
/// #
|
||||||
#[derive(Copy, Clone)]
|
/// # fn main() {
|
||||||
pub struct Abort(Mib<[usize; 2]>);
|
/// use jemalloc_ctl::opt;
|
||||||
|
/// let dss = opt::dss::read().unwrap();
|
||||||
impl Abort {
|
/// println!("dss priority: {}", dss);
|
||||||
/// Returns a new `Abort`.
|
/// # }
|
||||||
pub fn new() -> Result<Self> {
|
/// ```
|
||||||
let mib = ABORT.name().mib()?;
|
mib_docs: /// See [`dss`].
|
||||||
Ok(Abort(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the abort-on-warning behavior.
|
|
||||||
pub fn get(self) -> Result<bool> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DSS: &[u8] = b"opt.dss\0";
|
option! {
|
||||||
|
narenas[ str: b"opt.narenas\0", non_str: 2 ] => libc::c_uint |
|
||||||
/// Returns the dss (`sbrk(2)`) allocation precedence as related to `mmap(2)` allocation.
|
ops: r |
|
||||||
///
|
docs:
|
||||||
/// The following settings are supported if `sbrk(2)` is supported by the operating system:
|
/// Maximum number of arenas to use for automatic multiplexing of threads
|
||||||
/// "disabled", "primary", and "secondary"; otherwise only "disabled" is supported. The default is
|
/// and arenas.
|
||||||
/// "secondary" if `sbrk(2)` is supported by the operating system; "disabled" otherwise.
|
///
|
||||||
///
|
/// The default is four times the number of CPUs, or one if there is a
|
||||||
/// # Examples
|
/// single CPU.
|
||||||
///
|
///
|
||||||
/// ```
|
/// # Examples
|
||||||
/// extern crate jemallocator;
|
///
|
||||||
/// extern crate jemalloc_ctl;
|
/// ```
|
||||||
///
|
/// # extern crate jemallocator;
|
||||||
/// #[global_allocator]
|
/// # extern crate jemalloc_ctl;
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// #
|
||||||
///
|
/// # #[global_allocator]
|
||||||
/// fn main() {
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
/// println!("dss priority: {}", jemalloc_ctl::opt::dss().unwrap());
|
/// #
|
||||||
/// }
|
/// # fn main() {
|
||||||
/// ```
|
/// use jemalloc_ctl::opt;
|
||||||
pub fn dss() -> Result<&'static str> {
|
/// let narenas = opt::narenas::read().unwrap();
|
||||||
DSS.name().read()
|
/// println!("number of arenas: {}", narenas);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
mib_docs: /// See [`narenas`].
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type providing access to the dss (`sbrk(2)`) allocation precedence as related to `mmap(2)`
|
option! {
|
||||||
/// allocation.
|
junk[ str: b"opt.junk\0", str: 2 ] => &'static str |
|
||||||
///
|
ops: r |
|
||||||
/// The following settings are supported if `sbrk(2)` is supported by the operating system:
|
docs:
|
||||||
/// "disabled", "primary", and "secondary"; otherwise only "disabled" is supported. The default is
|
/// `jemalloc`'s junk filling mode.
|
||||||
/// "secondary" if `sbrk(2)` is supported by the operating system; "disabled" otherwise.
|
///
|
||||||
///
|
/// Requires `--enable-fill` to have been specified during build
|
||||||
/// # Examples
|
/// configuration.
|
||||||
///
|
///
|
||||||
/// ```
|
/// If set to "alloc", each byte of uninitialized allocated memory will be
|
||||||
/// extern crate jemallocator;
|
/// set to `0x5a`. If set to "free", each byte of deallocated memory will be set
|
||||||
/// extern crate jemalloc_ctl;
|
/// to `0x5a`. If set to "true", both allocated and deallocated memory will be
|
||||||
///
|
/// initialized, and if set to "false" junk filling will be disabled. This is
|
||||||
/// use jemalloc_ctl::opt::Dss;
|
/// intended for debugging and will impact performance negatively.
|
||||||
///
|
///
|
||||||
/// #[global_allocator]
|
/// The default is "false", unless `--enable-debug` was specified during
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// build configuration, in
|
||||||
///
|
/// which case the default is "true".
|
||||||
/// fn main() {
|
///
|
||||||
/// let dss = Dss::new().unwrap();
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// println!("dss priority: {}", dss.get().unwrap());
|
/// ```
|
||||||
/// }
|
/// # extern crate jemallocator;
|
||||||
/// ```
|
/// # extern crate jemalloc_ctl;
|
||||||
#[derive(Copy, Clone)]
|
/// #
|
||||||
pub struct Dss(MibStr<[usize; 2]>);
|
/// # #[global_allocator]
|
||||||
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
impl Dss {
|
/// #
|
||||||
/// Returns a new `Dss`.
|
/// # fn main() {
|
||||||
pub fn new() -> Result<Self> {
|
/// use jemalloc_ctl::opt;
|
||||||
let mib = DSS.name().mib_str()?;
|
/// let junk = opt::junk::read().unwrap();
|
||||||
Ok(Dss(mib))
|
/// println!("junk filling: {}", junk);
|
||||||
}
|
/// # }
|
||||||
|
/// ```
|
||||||
/// Returns the dss allocation precedence.
|
mib_docs: /// See [`junk`].
|
||||||
pub fn get(self) -> Result<&'static str> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NARENAS: &[u8] = b"opt.narenas\0";
|
option! {
|
||||||
|
zero[ str: b"opt.zero\0", non_str: 2 ] => bool |
|
||||||
/// Returns the maximum number of arenas to use for automatic multiplexing of threads and arenas.
|
ops: r |
|
||||||
///
|
docs:
|
||||||
/// The default is four times the number of CPUs, or one if there is a single CPU.
|
/// `jemalloc`'s zeroing behavior.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// Requires `--enable-fill` to have been specified during build
|
||||||
///
|
/// configuration.
|
||||||
/// ```
|
///
|
||||||
/// extern crate jemallocator;
|
/// If enabled, `jemalloc` will initialize each byte of uninitialized
|
||||||
/// extern crate jemalloc_ctl;
|
/// allocated memory to 0. This is intended for debugging and will impact
|
||||||
///
|
/// performance negatively. It is disabled by default.
|
||||||
/// #[global_allocator]
|
///
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// ```
|
||||||
/// println!("number of arenas: {}", jemalloc_ctl::opt::narenas().unwrap());
|
/// # extern crate jemallocator;
|
||||||
/// }
|
/// # extern crate jemalloc_ctl;
|
||||||
/// ```
|
/// #
|
||||||
pub fn narenas() -> Result<c_uint> {
|
/// # #[global_allocator]
|
||||||
NARENAS.name().read()
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// use jemalloc_ctl::opt;
|
||||||
|
/// let zero = opt::zero::read().unwrap();
|
||||||
|
/// println!("zeroing: {}", zero);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
mib_docs: /// See [`zero`].
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type providing access to the maximum number of arenas to use for automatic multiplexing of
|
option! {
|
||||||
/// threads and arenas.
|
tcache[ str: b"opt.tcache\0", non_str: 2 ] => bool |
|
||||||
///
|
ops: r |
|
||||||
/// The default is four times the number of CPUs, or one if there is a single CPU.
|
docs:
|
||||||
///
|
/// Thread-local allocation caching behavior.
|
||||||
/// # Examples
|
///
|
||||||
///
|
/// Thread-specific caching allows many allocations to be satisfied without
|
||||||
/// ```
|
/// performing any thread synchronization, at the cost of increased memory
|
||||||
/// extern crate jemallocator;
|
/// use. This is enabled by default.
|
||||||
/// extern crate jemalloc_ctl;
|
///
|
||||||
///
|
/// # Examples
|
||||||
/// use jemalloc_ctl::opt::NArenas;
|
///
|
||||||
///
|
/// ```
|
||||||
/// #[global_allocator]
|
/// # extern crate jemallocator;
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// # extern crate jemalloc_ctl;
|
||||||
///
|
/// #
|
||||||
/// fn main() {
|
/// # #[global_allocator]
|
||||||
/// let narenas = NArenas::new().unwrap();
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
///
|
/// #
|
||||||
/// println!("number of arenas: {}", narenas.get().unwrap());
|
/// # fn main() {
|
||||||
/// }
|
/// use jemalloc_ctl::opt;
|
||||||
/// ```
|
/// let tcache = opt::tcache::read().unwrap();
|
||||||
#[derive(Copy, Clone)]
|
/// println!("thread-local caching: {}", tcache);
|
||||||
pub struct NArenas(Mib<[usize; 2]>);
|
/// # }
|
||||||
|
/// ```
|
||||||
impl NArenas {
|
mib_docs: /// See [`tcache`].
|
||||||
/// Returns a new `NArenas`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = NARENAS.name().mib()?;
|
|
||||||
Ok(NArenas(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the maximum number of arenas.
|
|
||||||
pub fn get(self) -> Result<c_uint> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const JUNK: &[u8] = b"opt.junk\0";
|
option! {
|
||||||
|
lg_tcache_max[ str: b"opt.lg_tcache_max\0", non_str: 2 ] => libc::size_t |
|
||||||
/// Returns `jemalloc`'s junk filling mode.
|
ops: r |
|
||||||
///
|
docs:
|
||||||
/// Requires `--enable-fill` to have been specified during build configuration.
|
/// Maximum size class (log base 2) to cache in the thread-specific cache
|
||||||
///
|
/// (`tcache`).
|
||||||
/// If set to "alloc", each byte of uninitialized allocated memory will be set to `0x5a`. If set to
|
///
|
||||||
/// "free", each byte of deallocated memory will be set to `0x5a`. If set to "true", both allocated
|
/// At a minimum, all small size classes are cached, and at a maximum all
|
||||||
/// and deallocated memory will be initialized, and if set to "false" junk filling will be disabled.
|
/// large size classes are cached. The default maximum is 32 KiB (2^15).
|
||||||
/// This is intended for debugging and will impact performance negatively.
|
///
|
||||||
///
|
/// # Examples
|
||||||
/// The default is "false", unless `--enable-debug` was specified during build configuration, in
|
///
|
||||||
/// which case the default is "true".
|
/// ```
|
||||||
///
|
/// # extern crate jemallocator;
|
||||||
/// # Examples
|
/// # extern crate jemalloc_ctl;
|
||||||
///
|
/// #
|
||||||
/// ```
|
/// # #[global_allocator]
|
||||||
/// extern crate jemallocator;
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
/// extern crate jemalloc_ctl;
|
/// #
|
||||||
///
|
/// # fn main() {
|
||||||
/// #[global_allocator]
|
/// use jemalloc_ctl::opt;
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// let lg_tcache_max = opt::lg_tcache_max::read().unwrap();
|
||||||
///
|
/// println!("max cached allocation size: {}", 1 << lg_tcache_max);
|
||||||
/// fn main() {
|
/// # }
|
||||||
/// println!("junk filling: {}", jemalloc_ctl::opt::junk().unwrap());
|
/// ```
|
||||||
/// }
|
mib_docs: /// See [`lg_tcache_max`].
|
||||||
/// ```
|
|
||||||
pub fn junk() -> Result<&'static str> {
|
|
||||||
JUNK.name().read()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type providing access to `jemalloc`'s junk filling mode.
|
option! {
|
||||||
///
|
background_thread[ str: b"opt.background_thread\0", non_str: 2 ] => bool |
|
||||||
/// Requires `--enable-fill` to have been specified during build configuration.
|
ops: r |
|
||||||
///
|
docs:
|
||||||
/// If set to "alloc", each byte of uninitialized allocated memory will be set to `0x5a`. If set to
|
/// `jemalloc`'s default initialization behavior for background threads.
|
||||||
/// "free", each byte of deallocated memory will be set to `0x5a`. If set to "true", both allocated
|
///
|
||||||
/// and deallocated memory will be initialized, and if set to "false" junk filling will be disabled.
|
/// `jemalloc` automatically spawns background worker threads on
|
||||||
/// This is intended for debugging and will impact performance negatively.
|
/// initialization (first `jemalloc` call) if this option is enabled. By
|
||||||
///
|
/// default this option is disabled - `malloc_conf=background_thread:true`
|
||||||
/// The default is "false", unless `--enable-debug` was specified during build configuration, in
|
/// changes its default.
|
||||||
/// which case the default is "true".
|
///
|
||||||
///
|
/// # Examples
|
||||||
/// # Examples
|
///
|
||||||
///
|
/// ```
|
||||||
/// ```
|
/// # extern crate jemallocator;
|
||||||
/// extern crate jemallocator;
|
/// # extern crate jemalloc_ctl;
|
||||||
/// extern crate jemalloc_ctl;
|
/// #
|
||||||
///
|
/// # #[global_allocator]
|
||||||
/// use jemalloc_ctl::opt::Junk;
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
///
|
/// #
|
||||||
/// #[global_allocator]
|
/// # fn main() {
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// use jemalloc_ctl::opt;
|
||||||
///
|
/// let background_thread = opt::background_thread::read().unwrap();
|
||||||
/// fn main() {
|
/// println!("background threads since initialization: {}", background_thread);
|
||||||
/// let junk = Junk::new().unwrap();
|
/// # }
|
||||||
///
|
/// ```
|
||||||
/// println!("junk filling: {}", junk.get().unwrap());
|
mib_docs: /// See [`background_thread`].
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct Junk(MibStr<[usize; 2]>);
|
|
||||||
|
|
||||||
impl Junk {
|
|
||||||
/// Returns a new `Junk`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = JUNK.name().mib_str()?;
|
|
||||||
Ok(Junk(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns jemalloc's junk filling mode.
|
|
||||||
pub fn get(self) -> Result<&'static str> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ZERO: &[u8] = b"opt.zero\0";
|
|
||||||
|
|
||||||
/// Returns jemalloc's zeroing behavior.
|
|
||||||
///
|
|
||||||
/// Requires `--enable-fill` to have been specified during build configuration.
|
|
||||||
///
|
|
||||||
/// If enabled, `jemalloc` will initialize each byte of uninitialized allocated memory to 0. This is
|
|
||||||
/// intended for debugging and will impact performance negatively. It is disabled by default.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// println!("zeroing: {}", jemalloc_ctl::opt::zero().unwrap());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn zero() -> Result<bool> {
|
|
||||||
ZERO.name().read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type providing access to jemalloc's zeroing behavior.
|
|
||||||
///
|
|
||||||
/// Requires `--enable-fill` to have been specified during build configuration.
|
|
||||||
///
|
|
||||||
/// If enabled, `jemalloc` will initialize each byte of uninitialized allocated memory to 0. This is
|
|
||||||
/// intended for debugging and will impact performance negatively. It is disabled by default.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// use jemalloc_ctl::opt::Zero;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let zero = Zero::new().unwrap();
|
|
||||||
///
|
|
||||||
/// println!("zeroing: {}", zero.get().unwrap());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct Zero(Mib<[usize; 2]>);
|
|
||||||
|
|
||||||
impl Zero {
|
|
||||||
/// Returns a new `Zero`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = ZERO.name().mib()?;
|
|
||||||
Ok(Zero(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the `jemalloc` zeroing behavior.
|
|
||||||
pub fn get(self) -> Result<bool> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const TCACHE: &[u8] = b"opt.tcache\0";
|
|
||||||
|
|
||||||
/// Determines if thread-local allocation caching is enabled.
|
|
||||||
///
|
|
||||||
/// Thread-specific caching allows many allocations to be satisfied without performing any thread
|
|
||||||
/// synchronization, at the cost of increased memory use. This is enabled by default.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// println!("thread-local caching: {}", jemalloc_ctl::opt::tcache().unwrap());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn tcache() -> Result<bool> {
|
|
||||||
TCACHE.name().read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type providing access to thread-local allocation caching behavior.
|
|
||||||
///
|
|
||||||
/// Thread-specific caching allows many allocations to be satisfied without performing any thread
|
|
||||||
/// synchronization, at the cost of increased memory use. This is enabled by default.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// use jemalloc_ctl::opt::Tcache;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let tcache = Tcache::new().unwrap();
|
|
||||||
///
|
|
||||||
/// println!("thread-local caching: {}", tcache.get().unwrap());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct Tcache(Mib<[usize; 2]>);
|
|
||||||
|
|
||||||
impl Tcache {
|
|
||||||
/// Returns a new `Tcache`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = TCACHE.name().mib()?;
|
|
||||||
Ok(Tcache(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the thread-local caching behavior.
|
|
||||||
pub fn get(self) -> Result<bool> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const LG_TCACHE_MAX: &[u8] = b"opt.lg_tcache_max\0";
|
|
||||||
|
|
||||||
/// Returns the maximum size class (log base 2) to cache in the thread-specific cache (tcache).
|
|
||||||
///
|
|
||||||
/// At a minimum, all small size classes are cached, and at a maximum all large size classes are
|
|
||||||
/// cached. The default maximum is 32 KiB (2^15).
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// println!("max cached allocation size: {}", 1 << jemalloc_ctl::opt::lg_tcache_max().unwrap());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn lg_tcache_max() -> Result<usize> {
|
|
||||||
LG_TCACHE_MAX.name().read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type providing access to the maximum size class (log base 2) to cache in the thread-specific
|
|
||||||
/// cache (tcache).
|
|
||||||
///
|
|
||||||
/// At a minimum, all small size classes are cached, and at a maximum all large size classes are
|
|
||||||
/// cached. The default maximum is 32 KiB (2^15).
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// use jemalloc_ctl::opt::LgTcacheMax;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let lg_tcache_max = LgTcacheMax::new().unwrap();
|
|
||||||
///
|
|
||||||
/// println!("max cached allocation size: {}", 1 << lg_tcache_max.get().unwrap());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct LgTcacheMax(Mib<[usize; 2]>);
|
|
||||||
|
|
||||||
impl LgTcacheMax {
|
|
||||||
/// Returns a new `LgTcacheMax`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = LG_TCACHE_MAX.name().mib()?;
|
|
||||||
Ok(LgTcacheMax(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the maximum cached size class.
|
|
||||||
pub fn get(self) -> Result<usize> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const BACKGROUND_THREAD: &[u8] = b"opt.background_thread\0";
|
|
||||||
|
|
||||||
/// Returns whether `jemalloc` is initialized with background worker threads
|
|
||||||
/// enabled.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// println!(
|
|
||||||
/// "initialized with background threads enabled: {}",
|
|
||||||
/// jemalloc_ctl::opt::background_thread().unwrap()
|
|
||||||
/// );
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn background_thread() -> Result<bool> {
|
|
||||||
BACKGROUND_THREAD.name().read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type determining if `jemalloc` will be initialized with background worker
|
|
||||||
/// threads enabled.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// use jemalloc_ctl::opt::BackgroundThread;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let background_thread = BackgroundThread::new().unwrap();
|
|
||||||
///
|
|
||||||
/// println!(
|
|
||||||
/// "initialized with background threads enabled: {}",
|
|
||||||
/// background_thread.get().unwrap()
|
|
||||||
/// );
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct BackgroundThread(Mib<[usize; 2]>);
|
|
||||||
|
|
||||||
impl BackgroundThread {
|
|
||||||
/// Returns a new `BackgroundThread`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = BACKGROUND_THREAD.name().mib()?;
|
|
||||||
Ok(BackgroundThread(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the background thread initialization behavior.
|
|
||||||
pub fn get(self) -> Result<bool> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Raw `malloctl` getter/setters
|
//! Raw `unsafe` access to the `malloctl` API.
|
||||||
|
|
||||||
use error::{cvt, Result};
|
use error::{cvt, Result};
|
||||||
use libc::c_char;
|
use libc::c_char;
|
||||||
|
@ -31,11 +31,11 @@ use {mem, ptr, slice};
|
||||||
/// use libc::{c_uint, c_char};
|
/// use libc::{c_uint, c_char};
|
||||||
/// unsafe {
|
/// unsafe {
|
||||||
/// let mut mib = [0; 4];
|
/// let mut mib = [0; 4];
|
||||||
/// let nbins: c_uint = raw::get(b"arenas.nbins\0").unwrap();
|
/// let nbins: c_uint = raw::read(b"arenas.nbins\0").unwrap();
|
||||||
/// raw::name_to_mib(b"arenas.bin.0.size\0", &mut mib).unwrap();
|
/// raw::name_to_mib(b"arenas.bin.0.size\0", &mut mib).unwrap();
|
||||||
/// for i in 0..4 {
|
/// for i in 0..4 {
|
||||||
/// mib[2] = i;
|
/// mib[2] = i;
|
||||||
/// let bin_size: usize = raw::get_mib(&mut mib).unwrap();
|
/// let bin_size: usize = raw::read_mib(&mut mib).unwrap();
|
||||||
/// println!("arena bin {} has size {}", i, bin_size);
|
/// println!("arena bin {} has size {}", i, bin_size);
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
|
@ -67,7 +67,7 @@ pub fn name_to_mib(name: &[u8], mib: &mut [usize]) -> Result<()> {
|
||||||
/// invalid `T`, for example, by passing `T=bool` for a key returning `u8`. The
|
/// invalid `T`, for example, by passing `T=bool` for a key returning `u8`. The
|
||||||
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
|
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
|
||||||
/// `u8` can.
|
/// `u8` can.
|
||||||
pub unsafe fn get_mib<T: Copy>(mib: &[usize]) -> Result<T> {
|
pub unsafe fn read_mib<T: Copy>(mib: &[usize]) -> Result<T> {
|
||||||
let mut value = MaybeUninit { init: () };
|
let mut value = MaybeUninit { init: () };
|
||||||
let mut len = mem::size_of::<T>();
|
let mut len = mem::size_of::<T>();
|
||||||
cvt(jemalloc_sys::mallctlbymib(
|
cvt(jemalloc_sys::mallctlbymib(
|
||||||
|
@ -91,7 +91,7 @@ pub unsafe fn get_mib<T: Copy>(mib: &[usize]) -> Result<T> {
|
||||||
/// invalid `T`, for example, by passing `T=bool` for a key returning `u8`. The
|
/// invalid `T`, for example, by passing `T=bool` for a key returning `u8`. The
|
||||||
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
|
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
|
||||||
/// `u8` can.
|
/// `u8` can.
|
||||||
pub unsafe fn get<T: Copy>(name: &[u8]) -> Result<T> {
|
pub unsafe fn read<T: Copy>(name: &[u8]) -> Result<T> {
|
||||||
validate_name(name);
|
validate_name(name);
|
||||||
|
|
||||||
let mut value = MaybeUninit { init: () };
|
let mut value = MaybeUninit { init: () };
|
||||||
|
@ -107,7 +107,7 @@ pub unsafe fn get<T: Copy>(name: &[u8]) -> Result<T> {
|
||||||
Ok(value.maybe_uninit)
|
Ok(value.maybe_uninit)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and sets its `value`.
|
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and writes its `value`.
|
||||||
///
|
///
|
||||||
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
|
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
|
||||||
/// to a `mib` (Management Information Base).
|
/// to a `mib` (Management Information Base).
|
||||||
|
@ -118,7 +118,7 @@ pub unsafe fn get<T: Copy>(name: &[u8]) -> Result<T> {
|
||||||
/// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The
|
/// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The
|
||||||
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
|
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
|
||||||
/// `u8` can.
|
/// `u8` can.
|
||||||
pub unsafe fn set_mib<T>(mib: &[usize], mut value: T) -> Result<()> {
|
pub unsafe fn write_mib<T>(mib: &[usize], mut value: T) -> Result<()> {
|
||||||
cvt(jemalloc_sys::mallctlbymib(
|
cvt(jemalloc_sys::mallctlbymib(
|
||||||
mib.as_ptr(),
|
mib.as_ptr(),
|
||||||
mib.len(),
|
mib.len(),
|
||||||
|
@ -130,7 +130,7 @@ pub unsafe fn set_mib<T>(mib: &[usize], mut value: T) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uses the null-terminated string `name` as the key to the _MALLCTL NAMESPACE_
|
/// Uses the null-terminated string `name` as the key to the _MALLCTL NAMESPACE_
|
||||||
/// and sets it `value`
|
/// and writes it `value`
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
@ -138,7 +138,7 @@ pub unsafe fn set_mib<T>(mib: &[usize], mut value: T) -> Result<()> {
|
||||||
/// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The
|
/// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The
|
||||||
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
|
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
|
||||||
/// `u8` can.
|
/// `u8` can.
|
||||||
pub unsafe fn set<T>(name: &[u8], mut value: T) -> Result<()> {
|
pub unsafe fn write<T>(name: &[u8], mut value: T) -> Result<()> {
|
||||||
validate_name(name);
|
validate_name(name);
|
||||||
|
|
||||||
cvt(jemalloc_sys::mallctl(
|
cvt(jemalloc_sys::mallctl(
|
||||||
|
@ -150,7 +150,7 @@ pub unsafe fn set<T>(name: &[u8], mut value: T) -> Result<()> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and sets its `value`
|
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and writes its `value`
|
||||||
/// returning its previous value.
|
/// returning its previous value.
|
||||||
///
|
///
|
||||||
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
|
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
|
||||||
|
@ -162,7 +162,7 @@ pub unsafe fn set<T>(name: &[u8], mut value: T) -> Result<()> {
|
||||||
/// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The
|
/// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The
|
||||||
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
|
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
|
||||||
/// `u8` can.
|
/// `u8` can.
|
||||||
pub unsafe fn get_set_mib<T>(mib: &[usize], mut value: T) -> Result<T> {
|
pub unsafe fn update_mib<T>(mib: &[usize], mut value: T) -> Result<T> {
|
||||||
let mut len = mem::size_of::<T>();
|
let mut len = mem::size_of::<T>();
|
||||||
cvt(jemalloc_sys::mallctlbymib(
|
cvt(jemalloc_sys::mallctlbymib(
|
||||||
mib.as_ptr(),
|
mib.as_ptr(),
|
||||||
|
@ -177,7 +177,7 @@ pub unsafe fn get_set_mib<T>(mib: &[usize], mut value: T) -> Result<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and
|
/// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and
|
||||||
/// sets its `value` returning its previous value.
|
/// writes its `value` returning its previous value.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
@ -185,7 +185,7 @@ pub unsafe fn get_set_mib<T>(mib: &[usize], mut value: T) -> Result<T> {
|
||||||
/// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The
|
/// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The
|
||||||
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
|
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
|
||||||
/// `u8` can.
|
/// `u8` can.
|
||||||
pub unsafe fn get_set<T>(name: &[u8], mut value: T) -> Result<T> {
|
pub unsafe fn update<T>(name: &[u8], mut value: T) -> Result<T> {
|
||||||
validate_name(name);
|
validate_name(name);
|
||||||
|
|
||||||
let mut len = mem::size_of::<T>();
|
let mut len = mem::size_of::<T>();
|
||||||
|
@ -225,12 +225,12 @@ pub unsafe fn get_set<T>(name: &[u8], mut value: T) -> Result<T> {
|
||||||
/// If the pointer is valid but it does not point to a null-terminated string,
|
/// If the pointer is valid but it does not point to a null-terminated string,
|
||||||
/// looking for `\0` will read garbage and might end up reading out-of-bounds,
|
/// looking for `\0` will read garbage and might end up reading out-of-bounds,
|
||||||
/// which is undefined behavior.
|
/// which is undefined behavior.
|
||||||
pub unsafe fn get_str_mib(mib: &[usize]) -> Result<&'static [u8]> {
|
pub unsafe fn read_str_mib(mib: &[usize]) -> Result<&'static [u8]> {
|
||||||
let ptr: *const c_char = get_mib(mib)?;
|
let ptr: *const c_char = read_mib(mib)?;
|
||||||
ptr2str(ptr)
|
ptr2str(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and sets its `value`.
|
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and writes its `value`.
|
||||||
///
|
///
|
||||||
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
|
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
|
||||||
/// to a `mib` (Management Information Base).
|
/// to a `mib` (Management Information Base).
|
||||||
|
@ -238,16 +238,16 @@ pub unsafe fn get_str_mib(mib: &[usize]) -> Result<&'static [u8]> {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// If `value` is not a non-empty null-terminated string.
|
/// If `value` is not a non-empty null-terminated string.
|
||||||
pub fn set_str_mib(mib: &[usize], value: &'static [u8]) -> Result<()> {
|
pub fn write_str_mib(mib: &[usize], value: &'static [u8]) -> Result<()> {
|
||||||
assert!(!value.is_empty(), "value cannot be empty");
|
assert!(!value.is_empty(), "value cannot be empty");
|
||||||
assert_eq!(*value.last().unwrap(), b'\0');
|
assert_eq!(*value.last().unwrap(), b'\0');
|
||||||
// This is safe because `value` will always point to a null-terminated
|
// This is safe because `value` will always point to a null-terminated
|
||||||
// string, which makes it safe for all key value types: pointers to
|
// string, which makes it safe for all key value types: pointers to
|
||||||
// null-terminated strings, pointers, pointer-sized integers, etc.
|
// null-terminated strings, pointers, pointer-sized integers, etc.
|
||||||
unsafe { set_mib(mib, value.as_ptr() as *const c_char) }
|
unsafe { write_mib(mib, value.as_ptr() as *const c_char) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and sets its `value`
|
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and writes its `value`
|
||||||
/// returning its previous value.
|
/// returning its previous value.
|
||||||
///
|
///
|
||||||
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
|
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
|
||||||
|
@ -273,8 +273,8 @@ pub fn set_str_mib(mib: &[usize], value: &'static [u8]) -> Result<()> {
|
||||||
/// If the pointer is valid but it does not point to a null-terminated string,
|
/// If the pointer is valid but it does not point to a null-terminated string,
|
||||||
/// looking for `\0` will read garbage and might end up reading out-of-bounds,
|
/// looking for `\0` will read garbage and might end up reading out-of-bounds,
|
||||||
/// which is undefined behavior.
|
/// which is undefined behavior.
|
||||||
pub unsafe fn get_set_str_mib(mib: &[usize], value: &'static [u8]) -> Result<&'static [u8]> {
|
pub unsafe fn update_str_mib(mib: &[usize], value: &'static [u8]) -> Result<&'static [u8]> {
|
||||||
let ptr: *const c_char = get_set_mib(mib, value.as_ptr() as *const c_char)?;
|
let ptr: *const c_char = update_mib(mib, value.as_ptr() as *const c_char)?;
|
||||||
ptr2str(ptr)
|
ptr2str(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,24 +301,24 @@ pub unsafe fn get_set_str_mib(mib: &[usize], value: &'static [u8]) -> Result<&'s
|
||||||
/// If the pointer is valid but it does not point to a null-terminated string,
|
/// If the pointer is valid but it does not point to a null-terminated string,
|
||||||
/// looking for `\0` will read garbage and might end up reading out-of-bounds,
|
/// looking for `\0` will read garbage and might end up reading out-of-bounds,
|
||||||
/// which is undefined behavior.
|
/// which is undefined behavior.
|
||||||
pub unsafe fn get_str(name: &[u8]) -> Result<&'static [u8]> {
|
pub unsafe fn read_str(name: &[u8]) -> Result<&'static [u8]> {
|
||||||
let ptr: *const c_char = get(name)?;
|
let ptr: *const c_char = read(name)?;
|
||||||
ptr2str(ptr)
|
ptr2str(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and
|
/// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and
|
||||||
/// sets its `value`.
|
/// writes its `value`.
|
||||||
pub fn set_str(name: &[u8], value: &'static [u8]) -> Result<()> {
|
pub fn write_str(name: &[u8], value: &'static [u8]) -> Result<()> {
|
||||||
assert!(!value.is_empty(), "value cannot be empty");
|
assert!(!value.is_empty(), "value cannot be empty");
|
||||||
assert_eq!(*value.last().unwrap(), b'\0');
|
assert_eq!(*value.last().unwrap(), b'\0');
|
||||||
// This is safe because `value` will always point to a null-terminated
|
// This is safe because `value` will always point to a null-terminated
|
||||||
// string, which makes it safe for all key value types: pointers to
|
// string, which makes it safe for all key value types: pointers to
|
||||||
// null-terminated strings, pointers, pointer-sized integers, etc.
|
// null-terminated strings, pointers, pointer-sized integers, etc.
|
||||||
unsafe { set(name, value.as_ptr() as *const c_char) }
|
unsafe { write(name, value.as_ptr() as *const c_char) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and
|
/// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and
|
||||||
/// sets its `value` returning its previous value.
|
/// writes its `value` returning its previous value.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
@ -340,8 +340,8 @@ pub fn set_str(name: &[u8], value: &'static [u8]) -> Result<()> {
|
||||||
/// If the pointer is valid but it does not point to a null-terminated string,
|
/// If the pointer is valid but it does not point to a null-terminated string,
|
||||||
/// looking for `\0` will read garbage and might end up reading out-of-bounds,
|
/// looking for `\0` will read garbage and might end up reading out-of-bounds,
|
||||||
/// which is undefined behavior.
|
/// which is undefined behavior.
|
||||||
pub unsafe fn get_set_str(name: &[u8], value: &'static [u8]) -> Result<&'static [u8]> {
|
pub unsafe fn update_str(name: &[u8], value: &'static [u8]) -> Result<&'static [u8]> {
|
||||||
let ptr: *const c_char = get_set(name, value.as_ptr() as *const c_char)?;
|
let ptr: *const c_char = update(name, value.as_ptr() as *const c_char)?;
|
||||||
ptr2str(ptr)
|
ptr2str(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,515 +1,228 @@
|
||||||
//! Global allocator statistics.
|
//! Global allocator statistics.
|
||||||
//!
|
//!
|
||||||
//! `jemalloc` tracks a wide variety of statistics. Many of them are cached, and only refreshed when
|
//! `jemalloc` tracks a wide variety of statistics. Many of them are cached, and
|
||||||
//! the jemalloc "epoch" is advanced. See the [`Epoch`] type for more information.
|
//! only refreshed when the `jemalloc` "epoch" is advanced. See the [`::epoch`] type
|
||||||
//!
|
//! for more information.
|
||||||
//! [`Epoch`]: ../struct.Epoch.html
|
|
||||||
|
|
||||||
use error::Result;
|
option! {
|
||||||
use keys::{Access, AsName, Mib};
|
allocated[ str: b"stats.allocated\0", non_str: 2 ] => libc::size_t |
|
||||||
|
ops: r |
|
||||||
const ALLOCATED: &[u8] = b"stats.allocated\0";
|
docs:
|
||||||
|
/// Total number of bytes allocated by the application.
|
||||||
/// Returns the total number of bytes allocated by the application.
|
///
|
||||||
///
|
/// This statistic is cached, and is only refreshed when the epoch is
|
||||||
/// This statistic is cached, and is only refreshed when the epoch is advanced. See the [`epoch`]
|
/// advanced. See the [`::epoch`] type for more information.
|
||||||
/// function for more information.
|
///
|
||||||
///
|
/// This corresponds to `stats.allocated` in jemalloc's API.
|
||||||
/// This corresponds to `stats.allocated` in jemalloc's API.
|
///
|
||||||
///
|
/// # Examples
|
||||||
/// # Examples
|
///
|
||||||
///
|
/// ```rust
|
||||||
/// ```
|
/// # extern crate jemallocator;
|
||||||
/// extern crate jemallocator;
|
/// # extern crate jemalloc_ctl;
|
||||||
/// extern crate jemalloc_ctl;
|
/// #
|
||||||
///
|
/// # #[global_allocator]
|
||||||
/// #[global_allocator]
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// #
|
||||||
///
|
/// # fn main() {
|
||||||
/// fn main() {
|
/// use jemalloc_ctl::{epoch, stats};
|
||||||
/// let a = jemalloc_ctl::stats::allocated().unwrap();
|
/// let e = epoch::mib().unwrap();
|
||||||
/// let _buf = vec![0; 1024 * 1024];
|
/// let allocated = stats::allocated::mib().unwrap();
|
||||||
/// jemalloc_ctl::epoch().unwrap();
|
///
|
||||||
/// let b = jemalloc_ctl::stats::allocated().unwrap();
|
/// let a = allocated.read().unwrap();
|
||||||
/// assert!(a < b);
|
/// let _buf = vec![0; 1024 * 1024];
|
||||||
/// }
|
/// e.advance().unwrap();
|
||||||
/// ```
|
/// let b = allocated.read().unwrap();
|
||||||
///
|
/// assert!(a < b);
|
||||||
/// [`epoch`]: ../fn.epoch().html
|
/// # }
|
||||||
pub fn allocated() -> Result<usize> {
|
/// ```
|
||||||
ALLOCATED.name().read()
|
mib_docs: /// See [`allocated`].
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type providing access to the total number of bytes allocated by the application.
|
option! {
|
||||||
///
|
active[ str: b"stats.active\0", non_str: 2 ] => libc::size_t |
|
||||||
/// This statistic is cached, and is only refreshed when the epoch is advanced. See the [`Epoch`]
|
ops: r |
|
||||||
/// type for more information.
|
docs:
|
||||||
///
|
/// Total number of bytes in active pages allocated by the application.
|
||||||
/// This corresponds to `stats.allocated` in jemalloc's API.
|
///
|
||||||
///
|
/// This is a multiple of the page size, and greater than or equal to the
|
||||||
/// # Examples
|
/// value returned by [`allocated`].
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// This statistic is cached, and is only refreshed when the epoch is
|
||||||
/// extern crate jemallocator;
|
/// advanced. See the [`::epoch`] type for more information.
|
||||||
/// extern crate jemalloc_ctl;
|
///
|
||||||
///
|
/// This corresponds to `stats.active` in jemalloc's API.
|
||||||
/// use jemalloc_ctl::Epoch;
|
///
|
||||||
/// use jemalloc_ctl::stats::Allocated;
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// #[global_allocator]
|
/// ```rust
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// # extern crate jemallocator;
|
||||||
///
|
/// # extern crate jemalloc_ctl;
|
||||||
/// fn main() {
|
/// #
|
||||||
/// let epoch = Epoch::new().unwrap();
|
/// # #[global_allocator]
|
||||||
/// let allocated = Allocated::new().unwrap();
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
///
|
/// #
|
||||||
/// let a = allocated.get().unwrap();
|
/// # fn main() {
|
||||||
/// let _buf = vec![0; 1024 * 1024];
|
/// use jemalloc_ctl::{epoch, stats};
|
||||||
/// epoch.advance().unwrap();
|
/// let e = epoch::mib().unwrap();
|
||||||
/// let b = allocated.get().unwrap();
|
/// let active = stats::active::mib().unwrap();
|
||||||
/// assert!(a < b);
|
///
|
||||||
/// }
|
/// let a = active.read().unwrap();
|
||||||
/// ```
|
/// let _buf = vec![0; 1024 * 1024];
|
||||||
///
|
/// e.advance().unwrap();
|
||||||
/// [`Epoch`]: ../struct.Epoch.html
|
/// let b = active.read().unwrap();
|
||||||
#[derive(Copy, Clone)]
|
/// assert!(a < b);
|
||||||
pub struct Allocated(Mib<[usize; 2]>);
|
/// # }
|
||||||
|
/// ```
|
||||||
impl Allocated {
|
mib_docs: /// See [`active`].
|
||||||
/// Returns a new `Allocated`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = ALLOCATED.name().mib()?;
|
|
||||||
Ok(Allocated(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of bytes allocated by the application.
|
|
||||||
pub fn get(self) -> Result<usize> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ACTIVE: &[u8] = b"stats.active\0";
|
option! {
|
||||||
|
metadata[ str: b"stats.metadata\0", non_str: 2 ] => libc::size_t |
|
||||||
/// Returns the total number of bytes in active pages allocated by the application.
|
ops: r |
|
||||||
///
|
docs:
|
||||||
/// This is a multiple of the page size, and is greater than or equal to the value returned by
|
/// Total number of bytes dedicated to `jemalloc` metadata.
|
||||||
/// [`allocated`].
|
///
|
||||||
///
|
/// This statistic is cached, and is only refreshed when the epoch is
|
||||||
/// This statistic is cached, and is only refreshed when the epoch is advanced. See the [`epoch`]
|
/// advanced. See the [`::epoch`] type for more information.
|
||||||
/// type for more information.
|
///
|
||||||
///
|
/// This corresponds to `stats.metadata` in jemalloc's API.
|
||||||
/// This corresponds to `stats.active` in jemalloc's API.
|
///
|
||||||
///
|
/// # Examples
|
||||||
/// # Examples
|
///
|
||||||
///
|
/// ```rust
|
||||||
/// ```
|
/// # extern crate jemallocator;
|
||||||
/// extern crate jemallocator;
|
/// # extern crate jemalloc_ctl;
|
||||||
/// extern crate jemalloc_ctl;
|
/// #
|
||||||
///
|
/// # #[global_allocator]
|
||||||
/// #[global_allocator]
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// #
|
||||||
///
|
/// # fn main() {
|
||||||
/// fn main() {
|
/// use jemalloc_ctl::{epoch, stats};
|
||||||
/// let a = jemalloc_ctl::stats::active().unwrap();
|
/// let e = epoch::mib().unwrap();
|
||||||
/// let _buf = vec![0; 1024 * 1024];
|
/// let metadata = stats::metadata::mib().unwrap();
|
||||||
/// jemalloc_ctl::epoch().unwrap();
|
///
|
||||||
/// let b = jemalloc_ctl::stats::active().unwrap();
|
/// e.advance().unwrap();
|
||||||
/// assert!(a < b);
|
/// let size = metadata.read().unwrap();
|
||||||
/// }
|
/// println!("{} bytes of jemalloc metadata", size);
|
||||||
/// ```
|
/// # }
|
||||||
///
|
/// ```
|
||||||
/// [`epoch`]: ../fn.epoch().html
|
mib_docs: /// See [`metadata`].
|
||||||
/// [`allocated`]: fn.allocated.hml
|
|
||||||
pub fn active() -> Result<usize> {
|
|
||||||
ACTIVE.name().read()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type providing access to the total number of bytes in active pages allocated by the
|
option! {
|
||||||
/// application.
|
resident[ str: b"stats.resident\0", non_str: 2 ] => libc::size_t |
|
||||||
///
|
ops: r |
|
||||||
/// This is a multiple of the page size, and greater than or equal to the value returned by
|
docs:
|
||||||
/// [`Allocated`].
|
/// Total number of bytes in physically resident data pages mapped by the
|
||||||
///
|
/// allocator.
|
||||||
/// This statistic is cached, and is only refreshed when the epoch is advanced. See the [`Epoch`]
|
///
|
||||||
/// type for more information.
|
/// This consists of all pages dedicated to allocator metadata, pages
|
||||||
///
|
/// backing active allocations, and unused dirty pages. It may overestimate
|
||||||
/// This corresponds to `stats.active` in jemalloc's API.
|
/// the true value because pages may not actually be physically resident if
|
||||||
///
|
/// they correspond to demand-zeroed virtual memory that has not yet been
|
||||||
/// # Examples
|
/// touched. This is a multiple of the page size, and is larger than the
|
||||||
///
|
/// value returned by [`active`].
|
||||||
/// ```rust
|
///
|
||||||
/// extern crate jemallocator;
|
/// This statistic is cached, and is only refreshed when the epoch is
|
||||||
/// extern crate jemalloc_ctl;
|
/// advanced. See the [`::epoch`] type for more information.
|
||||||
///
|
///
|
||||||
/// use jemalloc_ctl::Epoch;
|
/// This corresponds to `stats.resident` in jemalloc's API.
|
||||||
/// use jemalloc_ctl::stats::Active;
|
///
|
||||||
///
|
/// # Examples
|
||||||
/// #[global_allocator]
|
///
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// ```rust
|
||||||
///
|
/// # extern crate jemallocator;
|
||||||
/// fn main() {
|
/// # extern crate jemalloc_ctl;
|
||||||
/// let epoch = Epoch::new().unwrap();
|
/// #
|
||||||
/// let active = Active::new().unwrap();
|
/// # #[global_allocator]
|
||||||
///
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
/// let a = active.get().unwrap();
|
/// #
|
||||||
/// let _buf = vec![0; 1024 * 1024];
|
/// # fn main() {
|
||||||
/// epoch.advance().unwrap();
|
/// use jemalloc_ctl::{epoch, stats};
|
||||||
/// let b = active.get().unwrap();
|
/// let e = epoch::mib().unwrap();
|
||||||
/// assert!(a < b);
|
/// let resident = stats::resident::mib().unwrap();
|
||||||
/// }
|
///
|
||||||
/// ```
|
/// e.advance().unwrap();
|
||||||
///
|
/// let size = resident.read().unwrap();
|
||||||
/// [`Epoch`]: ../struct.Epoch.html
|
/// println!("{} bytes of total resident data", size);
|
||||||
/// [`Allocated`]: struct.Allocated.html
|
/// # }
|
||||||
#[derive(Copy, Clone)]
|
/// ```
|
||||||
pub struct Active(Mib<[usize; 2]>);
|
mib_docs: /// See [`resident`].
|
||||||
|
|
||||||
impl Active {
|
|
||||||
/// Returns a new `Allocated`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = ACTIVE.name().mib()?;
|
|
||||||
Ok(Active(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of bytes in active pages allocated by the application.
|
|
||||||
pub fn get(self) -> Result<usize> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const METADATA: &[u8] = b"stats.metadata\0";
|
option! {
|
||||||
|
mapped[ str: b"stats.mapped\0", non_str: 2 ] => libc::size_t |
|
||||||
/// Returns the total number of bytes dedicated to jemalloc metadata.
|
ops: r |
|
||||||
///
|
docs:
|
||||||
/// This statistic is cached, and is only refreshed when the epoch is advanced. See the [`epoch`]
|
/// Total number of bytes in active extents mapped by the allocator.
|
||||||
/// function for more information.
|
///
|
||||||
///
|
/// This does not include inactive extents, even those that contain unused
|
||||||
/// This corresponds to `stats.metadata` in jemalloc's API.
|
/// dirty pages, so there is no strict ordering between this and the value
|
||||||
///
|
/// returned by [`resident`]. This is a multiple of the page size, and is
|
||||||
/// # Examples
|
/// larger than the value returned by [`active`].
|
||||||
///
|
///
|
||||||
/// ```
|
/// This statistic is cached, and is only refreshed when the epoch is
|
||||||
/// extern crate jemallocator;
|
/// advanced. See the [`::epoch`] type for more information.
|
||||||
/// extern crate jemalloc_ctl;
|
///
|
||||||
///
|
/// This corresponds to `stats.mapped` in jemalloc's API.
|
||||||
/// #[global_allocator]
|
///
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// ```rust
|
||||||
/// jemalloc_ctl::epoch().unwrap();
|
/// # extern crate jemallocator;
|
||||||
/// println!("{} bytes of jemalloc metadata", jemalloc_ctl::stats::metadata().unwrap());
|
/// # extern crate jemalloc_ctl;
|
||||||
/// }
|
/// #
|
||||||
/// ```
|
/// # #[global_allocator]
|
||||||
///
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
/// [`epoch`]: ../fn.epoch.html
|
/// #
|
||||||
pub fn metadata() -> Result<usize> {
|
/// # fn main() {
|
||||||
METADATA.name().read()
|
/// use jemalloc_ctl::{epoch, stats};
|
||||||
|
/// let e = epoch::mib().unwrap();
|
||||||
|
/// let mapped = stats::mapped::mib().unwrap();
|
||||||
|
///
|
||||||
|
/// e.advance().unwrap();
|
||||||
|
/// let size = mapped.read().unwrap();
|
||||||
|
/// println!("{} bytes of total mapped data", size);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
mib_docs: /// See [`mapped`].
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type providing access to the total number of bytes dedicated to jemalloc metadata.
|
option! {
|
||||||
///
|
retained[ str: b"stats.retained\0", non_str: 2 ] => libc::size_t |
|
||||||
/// This statistic is cached, and is only refreshed when the epoch is advanced. See the [`Epoch`]
|
ops: r |
|
||||||
/// type for more information.
|
docs:
|
||||||
///
|
/// Total number of bytes in virtual memory mappings that were retained
|
||||||
/// This corresponds to `stats.metadata` in jemalloc's API.
|
/// rather than being returned to the operating system via e.g. `munmap(2)`.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// Retained virtual memory is typically untouched, decommitted, or purged,
|
||||||
///
|
/// so it has no strongly associated physical memory. Retained memory is
|
||||||
/// ```rust
|
/// excluded from mapped memory statistics, e.g. [`mapped`].
|
||||||
/// extern crate jemallocator;
|
///
|
||||||
/// extern crate jemalloc_ctl;
|
/// This statistic is cached, and is only refreshed when the epoch is
|
||||||
///
|
/// advanced. See the [`::epoch`] type for more information.
|
||||||
/// use jemalloc_ctl::Epoch;
|
///
|
||||||
/// use jemalloc_ctl::stats::Metadata;
|
/// This corresponds to `stats.retained` in jemalloc's API.
|
||||||
///
|
///
|
||||||
/// #[global_allocator]
|
/// # Examples
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
///
|
||||||
///
|
/// ```rust
|
||||||
/// fn main() {
|
/// # extern crate jemallocator;
|
||||||
/// let epoch = Epoch::new().unwrap();
|
/// # extern crate jemalloc_ctl;
|
||||||
/// let metadata = Metadata::new().unwrap();
|
/// #
|
||||||
///
|
/// # #[global_allocator]
|
||||||
/// epoch.advance().unwrap();
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
/// let size = metadata.get().unwrap();
|
/// #
|
||||||
/// println!("{} bytes of jemalloc metadata", size);
|
/// # fn main() {
|
||||||
/// }
|
/// use jemalloc_ctl::{epoch, stats};
|
||||||
/// ```
|
/// let e = epoch::mib().unwrap();
|
||||||
///
|
/// let retained = stats::retained::mib().unwrap();
|
||||||
/// [`Epoch`]: ../struct.Epoch.html
|
///
|
||||||
#[derive(Copy, Clone)]
|
/// e.advance().unwrap();
|
||||||
pub struct Metadata(Mib<[usize; 2]>);
|
/// let size = retained.read().unwrap();
|
||||||
|
/// println!("{} bytes of total retained data", size);
|
||||||
impl Metadata {
|
/// # }
|
||||||
/// Returns a new `Metadata`.
|
/// ```
|
||||||
pub fn new() -> Result<Self> {
|
mib_docs: /// See [`retained`].
|
||||||
let mib = METADATA.name().mib()?;
|
|
||||||
Ok(Metadata(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of bytes dedicated to jemalloc metadata.
|
|
||||||
pub fn get(self) -> Result<usize> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const RESIDENT: &[u8] = b"stats.resident\0";
|
|
||||||
|
|
||||||
/// Returns the total number of bytes in physically resident data pages mapped by the allocator.
|
|
||||||
///
|
|
||||||
/// This consists of all pages dedicated to allocator metadata, pages backing active allocations,
|
|
||||||
/// and unused dirty pages. It may overestimate the true value because pages may not actually be
|
|
||||||
/// physically resident if they correspond to demand-zeroed virtual memory that has not yet been
|
|
||||||
/// touched. This is a multiple of the page size, and is larger than the value returned by
|
|
||||||
/// [`active`].
|
|
||||||
///
|
|
||||||
/// This statistic is cached, and is only refreshed when the epoch is advanced. See the [`epoch`]
|
|
||||||
/// function for more information.
|
|
||||||
///
|
|
||||||
/// This corresponds to `stats.resident` in jemalloc's API.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// jemalloc_ctl::epoch().unwrap();
|
|
||||||
/// println!("{} bytes of total resident data", jemalloc_ctl::stats::resident().unwrap());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`epoch`]: ../fn.epoch.html
|
|
||||||
/// [`active`]: fn.active.html
|
|
||||||
pub fn resident() -> Result<usize> {
|
|
||||||
RESIDENT.name().read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type providing access to the total number of bytes in physically resident data pages mapped
|
|
||||||
/// by the allocator.
|
|
||||||
///
|
|
||||||
/// This consists of all pages dedicated to allocator metadata, pages backing active allocations,
|
|
||||||
/// and unused dirty pages. It may overestimate the true value because pages may not actually be
|
|
||||||
/// physically resident if they correspond to demand-zeroed virtual memory that has not yet been
|
|
||||||
/// touched. This is a multiple of the page size, and is larger than the value returned by
|
|
||||||
/// [`Active`].
|
|
||||||
///
|
|
||||||
/// This statistic is cached, and is only refreshed when the epoch is advanced. See the [`Epoch`]
|
|
||||||
/// type for more information.
|
|
||||||
///
|
|
||||||
/// This corresponds to `stats.resident` in jemalloc's API.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// use jemalloc_ctl::Epoch;
|
|
||||||
/// use jemalloc_ctl::stats::Resident;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let epoch = Epoch::new().unwrap();
|
|
||||||
/// let resident = Resident::new().unwrap();
|
|
||||||
///
|
|
||||||
/// epoch.advance().unwrap();
|
|
||||||
/// let size = resident.get().unwrap();
|
|
||||||
/// println!("{} bytes of total resident data", size);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`Epoch`]: ../struct.Epoch.html
|
|
||||||
/// [`Active`]: struct.Active.html
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct Resident(Mib<[usize; 2]>);
|
|
||||||
|
|
||||||
impl Resident {
|
|
||||||
/// Returns a new `Resident`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = RESIDENT.name().mib()?;
|
|
||||||
Ok(Resident(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of bytes in physically resident data pages mapped by the allocator.
|
|
||||||
pub fn get(self) -> Result<usize> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAPPED: &[u8] = b"stats.mapped\0";
|
|
||||||
|
|
||||||
/// Returns the total number of bytes in active extents mapped by the allocator.
|
|
||||||
///
|
|
||||||
/// This does not include inactive extents, even those taht contain unused dirty pages, so there
|
|
||||||
/// is no strict ordering between this and the value returned by [`resident`]. This is a
|
|
||||||
/// multiple of the page size, and is larger than the value returned by [`active`].
|
|
||||||
///
|
|
||||||
/// This statistic is cached, and is only refreshed when the epoch is advanced. See the [`epoch`]
|
|
||||||
/// type for more information.
|
|
||||||
///
|
|
||||||
/// This corresponds to `stats.mapped` in jemalloc's API.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// jemalloc_ctl::epoch().unwrap();
|
|
||||||
/// println!("{} bytes of total mapped data", jemalloc_ctl::stats::mapped().unwrap());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`epoch`]: ../fn.epoch.html
|
|
||||||
/// [`resident`]: fn.resident.html
|
|
||||||
/// [`active`]: fn.active.html
|
|
||||||
pub fn mapped() -> Result<usize> {
|
|
||||||
MAPPED.name().read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type providing access to the total number of bytes in active extents mapped by the allocator.
|
|
||||||
///
|
|
||||||
/// This does not include inactive extents, even those that contain unused dirty pages, so there
|
|
||||||
/// is no strict ordering between this and the value returned by [`Resident`]. This is a
|
|
||||||
/// multiple of the page size, and is larger than the value returned by [`Active`].
|
|
||||||
///
|
|
||||||
/// This statistic is cached, and is only refreshed when the epoch is advanced. See the [`Epoch`]
|
|
||||||
/// type for more information.
|
|
||||||
///
|
|
||||||
/// This corresponds to `stats.mapped` in jemalloc's API.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// use jemalloc_ctl::Epoch;
|
|
||||||
/// use jemalloc_ctl::stats::Mapped;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let epoch = Epoch::new().unwrap();
|
|
||||||
/// let mapped = Mapped::new().unwrap();
|
|
||||||
///
|
|
||||||
/// epoch.advance().unwrap();
|
|
||||||
/// let size = mapped.get().unwrap();
|
|
||||||
/// println!("{} bytes of total mapped data", size);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`Epoch`]: ../struct.Epoch.html
|
|
||||||
/// [`Resident`]: struct.Resident.html
|
|
||||||
/// [`Active`]: struct.Active.html
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct Mapped(Mib<[usize; 2]>);
|
|
||||||
|
|
||||||
impl Mapped {
|
|
||||||
/// Returns a new `Mapped`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = MAPPED.name().mib()?;
|
|
||||||
Ok(Mapped(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of bytes in active extents mapped by the allocator.
|
|
||||||
pub fn get(self) -> Result<usize> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const RETAINED: &[u8] = b"stats.retained\0";
|
|
||||||
|
|
||||||
/// Returns the total number of bytes in virtual memory mappings that were retained rather than being returned to the
|
|
||||||
/// operating system via e.g. `munmap(2)`.
|
|
||||||
///
|
|
||||||
/// Retained virtual memory is typically untouched, decommitted, or purged, so it has no strongly associated physical
|
|
||||||
/// memory. Retained memory is excluded from mapped memory statistics, e.g. [`mapped`].
|
|
||||||
///
|
|
||||||
/// This statistic is cached, and is only refreshed when the epoch is advanced. See the [`epoch`]
|
|
||||||
/// type for more information.
|
|
||||||
///
|
|
||||||
/// This corresponds to `stats.retained` in jemalloc's API.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// jemalloc_ctl::epoch().unwrap();
|
|
||||||
/// println!("{} bytes of total retained data", jemalloc_ctl::stats::retained().unwrap());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`epoch`]: ../fn.epoch.html
|
|
||||||
/// [`mapped`]: fn.mapped.html
|
|
||||||
pub fn retained() -> Result<usize> {
|
|
||||||
RETAINED.name().read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type providing access to the total number of bytes in virtual memory mappings that were retained rather than being
|
|
||||||
/// returned to the operating system via e.g. `munmap(2)`.
|
|
||||||
///
|
|
||||||
/// Retained virtual memory is typically untouched, decommitted, or purged, so it has no strongly associated physical
|
|
||||||
/// memory. Retained memory is excluded from mapped memory statistics, e.g. [`Mapped`].
|
|
||||||
///
|
|
||||||
/// This statistic is cached, and is only refreshed when the epoch is advanced. See the [`Epoch`]
|
|
||||||
/// type for more information.
|
|
||||||
///
|
|
||||||
/// This corresponds to `stats.retained` in jemalloc's API.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// use jemalloc_ctl::Epoch;
|
|
||||||
/// use jemalloc_ctl::stats::Retained;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let epoch = Epoch::new().unwrap();
|
|
||||||
/// let retained = Retained::new().unwrap();
|
|
||||||
///
|
|
||||||
/// epoch.advance().unwrap();
|
|
||||||
/// let size = retained.get().unwrap();
|
|
||||||
/// println!("{} bytes of total retained data", size);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`Epoch`]: ../struct.Epoch.html
|
|
||||||
/// [`Mapped`]: struct.Mapped.html
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct Retained(Mib<[usize; 2]>);
|
|
||||||
|
|
||||||
impl Retained {
|
|
||||||
/// Returns a new `Retained`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = RETAINED.name().mib()?;
|
|
||||||
Ok(Retained(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of bytes in virtual memory mappings that were retained.
|
|
||||||
pub fn get(self) -> Result<usize> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,188 +1,115 @@
|
||||||
//! Thread specific operations.
|
//! Thread specific operations.
|
||||||
|
|
||||||
use error::Result;
|
use error::Result;
|
||||||
use raw::{get, get_mib, name_to_mib};
|
use raw::{read, read_mib};
|
||||||
|
|
||||||
const ALLOCATEDP: &[u8] = b"thread.allocatedp\0";
|
option! {
|
||||||
|
allocatedp[ str: b"thread.allocatedp\0", non_str: 2 ] => *mut u64 |
|
||||||
/// Returns a thread-local pointer to the total number of bytes allocated by the current thread.
|
ops: |
|
||||||
///
|
docs:
|
||||||
/// Unlike [`stats::allocated`], the value returned by this type is not the number of bytes
|
/// Access to the total number of bytes allocated by the current thread.
|
||||||
/// *currently* allocated, but rather the number of bytes that have *ever* been allocated by this
|
///
|
||||||
/// thread.
|
/// Unlike [`::stats::allocated`], the value returned by this type is not the
|
||||||
///
|
/// number of bytes *currently* allocated, but rather the number of bytes
|
||||||
/// This function doesn't return the value directly, but actually a pointer to the value. This
|
/// that have *ever* been allocated by this thread.
|
||||||
/// allows for very fast repeated lookup, since there is no function call overhead. The pointer type
|
///
|
||||||
/// cannot be sent to other threads, but `allocated` can be called on different threads and will
|
/// The `read` method doesn't return the value directly, but actually a
|
||||||
/// return the appropriate pointer for each of them.
|
/// pointer to the value. This allows for very fast repeated lookup, since
|
||||||
///
|
/// there is no function call overhead. The pointer type cannot be sent to
|
||||||
/// This corresponds to `thread.allocatedp` in jemalloc's API.
|
/// other threads, but `allocated::read` can be called on different threads
|
||||||
///
|
/// and will return the appropriate pointer for each of them.
|
||||||
/// # Examples
|
///
|
||||||
///
|
/// # Example
|
||||||
/// ```
|
///
|
||||||
/// extern crate jemallocator;
|
/// ```
|
||||||
/// extern crate jemalloc_ctl;
|
/// # extern crate jemallocator;
|
||||||
///
|
/// # extern crate jemalloc_ctl;
|
||||||
/// #[global_allocator]
|
/// #
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// # #[global_allocator]
|
||||||
///
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
/// fn main() {
|
/// #
|
||||||
/// let allocated = jemalloc_ctl::thread::allocatedp().unwrap();
|
/// # fn main() {
|
||||||
///
|
/// use jemalloc_ctl::thread;
|
||||||
/// let a = allocated.get();
|
/// let allocated = thread::allocatedp::mib().unwrap();
|
||||||
/// let buf = vec![0; 1024 * 1024];
|
/// let allocated = allocated.read().unwrap();
|
||||||
/// let b = allocated.get();
|
///
|
||||||
/// drop(buf);
|
/// let a = allocated.get();
|
||||||
/// let c = allocated.get();
|
/// let buf = vec![0; 1024 * 1024];
|
||||||
///
|
/// let b = allocated.get();
|
||||||
/// assert!(a < b);
|
/// drop( buf);
|
||||||
/// assert_eq!(b, c);
|
/// let c = allocated.get();
|
||||||
/// }
|
///
|
||||||
/// ```
|
/// assert!(a < b);
|
||||||
pub fn allocatedp() -> Result<ThreadLocal<u64>> {
|
/// assert_eq!(b, c);
|
||||||
unsafe { get(ALLOCATEDP).map(ThreadLocal) }
|
/// # }
|
||||||
|
/// ```
|
||||||
|
mib_docs: /// See [`allocatedp`].
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type providing access to the total number of bytes allocated by the current thread.
|
impl allocatedp {
|
||||||
///
|
/// Reads value using string API.
|
||||||
/// Unlike [`stats::Allocated`], the value returned by this type is not the number of bytes
|
pub fn read() -> Result<ThreadLocal<u64>> {
|
||||||
/// *currently* allocated, but rather the number of bytes that have *ever* been allocated by this
|
unsafe { read(Self::name().as_bytes()).map(ThreadLocal) }
|
||||||
/// thread.
|
|
||||||
///
|
|
||||||
/// The `get` method doesn't return the value directly, but actually a pointer to the value. This
|
|
||||||
/// allows for very fast repeated lookup, since there is no function call overhead. The pointer type
|
|
||||||
/// cannot be sent to other threads, but `Allocated::get` can be called on different threads and
|
|
||||||
/// will return the appropriate pointer for each of them.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// use jemalloc_ctl::thread::AllocatedP;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let allocated = AllocatedP::new().unwrap();
|
|
||||||
/// let allocated = allocated.get().unwrap();
|
|
||||||
///
|
|
||||||
/// let a = allocated.get();
|
|
||||||
/// let buf = vec![0; 1024 * 1024];
|
|
||||||
/// let b = allocated.get();
|
|
||||||
/// drop(buf);
|
|
||||||
/// let c = allocated.get();
|
|
||||||
///
|
|
||||||
/// assert!(a < b);
|
|
||||||
/// assert_eq!(b, c);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`stats::Allocated`]: ../stats/struct.Allocated.html
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct AllocatedP([usize; 2]);
|
|
||||||
|
|
||||||
impl AllocatedP {
|
|
||||||
/// Returns a new `Allocated`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mut mib = [0; 2];
|
|
||||||
name_to_mib(ALLOCATEDP, &mut mib)?;
|
|
||||||
Ok(AllocatedP(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a thread-local pointer to the total number of bytes allocated by this thread.
|
|
||||||
pub fn get(&self) -> Result<ThreadLocal<u64>> {
|
|
||||||
unsafe { get_mib(&self.0).map(ThreadLocal) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEALLOCATEDP: &[u8] = b"thread.deallocatedp\0";
|
impl allocatedp_mib {
|
||||||
|
/// Reads value using MIB API.
|
||||||
/// Returns a pointer to the total number of bytes deallocated by the current thread.
|
pub fn read(&self) -> Result<ThreadLocal<u64>> {
|
||||||
///
|
unsafe { read_mib(self.0.as_ref()).map(ThreadLocal) }
|
||||||
/// This function doesn't return the value directly, but actually a pointer to the value. This
|
}
|
||||||
/// allows for very fast repeated lookup, since there is no function call overhead. The pointer type
|
|
||||||
/// cannot be sent to other threads, but `deallocatedp` can be called on different threads and will
|
|
||||||
/// return the appropriate pointer for each of them.
|
|
||||||
///
|
|
||||||
/// This corresponds to `thread.deallocatedp` in jemalloc's API.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let deallocated = jemalloc_ctl::thread::deallocatedp().unwrap();
|
|
||||||
///
|
|
||||||
/// let a = deallocated.get();
|
|
||||||
/// let buf = vec![0; 1024 * 1024];
|
|
||||||
/// let b = deallocated.get();
|
|
||||||
/// drop(buf);
|
|
||||||
/// let c = deallocated.get();
|
|
||||||
///
|
|
||||||
/// assert_eq!(a, b);
|
|
||||||
/// assert!(b < c);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn deallocatedp() -> Result<ThreadLocal<u64>> {
|
|
||||||
unsafe { get(DEALLOCATEDP).map(ThreadLocal) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type providing access to the total number of bytes deallocated by the current thread.
|
option! {
|
||||||
///
|
deallocatedp[ str: b"thread.deallocatedp\0", non_str: 2 ] => *mut u64 |
|
||||||
/// The `get` method doesn't return the value directly, but actually a pointer to the value. This
|
ops: |
|
||||||
/// allows for very fast repeated lookup, since there is no function call overhead. The pointer type
|
docs:
|
||||||
/// cannot be sent to other threads, but `DeallocatedP::get` can be called on different threads and
|
/// Access to the total number of bytes deallocated by the current thread.
|
||||||
/// will return the appropriate pointer for each of them.
|
///
|
||||||
///
|
/// The `read` method doesn't return the value directly, but actually a
|
||||||
/// # Example
|
/// pointer to the value. This allows for very fast repeated lookup, since
|
||||||
///
|
/// there is no function call overhead. The pointer type cannot be sent to
|
||||||
/// ```
|
/// other threads, but [`deallocatedp::read`] can be called on different
|
||||||
/// extern crate jemallocator;
|
/// threads and will return the appropriate pointer for each of them.
|
||||||
/// extern crate jemalloc_ctl;
|
///
|
||||||
///
|
/// # Example
|
||||||
/// use jemalloc_ctl::thread::DeallocatedP;
|
///
|
||||||
///
|
/// ```
|
||||||
/// #[global_allocator]
|
/// # extern crate jemallocator;
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
/// # extern crate jemalloc_ctl;
|
||||||
///
|
/// #
|
||||||
/// fn main() {
|
/// # #[global_allocator]
|
||||||
/// let deallocated = DeallocatedP::new().unwrap();
|
/// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
/// let deallocated = deallocated.get().unwrap();
|
/// #
|
||||||
///
|
/// # fn main() {
|
||||||
/// let a = deallocated.get();
|
/// use jemalloc_ctl::thread;
|
||||||
/// let buf = vec![0; 1024 * 1024];
|
/// let deallocated = thread::deallocatedp::mib().unwrap();
|
||||||
/// let b = deallocated.get();
|
/// let deallocated = deallocated.read().unwrap();
|
||||||
/// drop(buf);
|
///
|
||||||
/// let c = deallocated.get();
|
/// let a = deallocated.get();
|
||||||
///
|
/// let buf = vec![0; 1024 * 1024];
|
||||||
/// assert_eq!(a, b);
|
/// let b = deallocated.get();
|
||||||
/// assert!(b < c);
|
/// drop(buf);
|
||||||
/// }
|
/// let c = deallocated.get();
|
||||||
/// ```
|
///
|
||||||
#[derive(Copy, Clone)]
|
/// assert_eq!(a, b);
|
||||||
pub struct DeallocatedP([usize; 2]);
|
/// assert!(b < c);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
mib_docs: /// See [`deallocatedp`].
|
||||||
|
}
|
||||||
|
|
||||||
impl DeallocatedP {
|
impl deallocatedp {
|
||||||
/// Returns a new `Deallocated`.
|
/// Reads value using string API.
|
||||||
pub fn new() -> Result<Self> {
|
pub fn read() -> Result<ThreadLocal<u64>> {
|
||||||
let mut mib = [0; 2];
|
unsafe { read(Self::name().as_bytes()).map(ThreadLocal) }
|
||||||
name_to_mib(DEALLOCATEDP, &mut mib)?;
|
|
||||||
Ok(DeallocatedP(mib))
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a thread-local pointer to the total number of bytes deallocated by this thread.
|
impl deallocatedp_mib {
|
||||||
pub fn get(&self) -> Result<ThreadLocal<u64>> {
|
/// Reads value using MIB API.
|
||||||
let ptr = unsafe { get_mib::<*mut u64>(&self.0)? };
|
pub fn read(&self) -> Result<ThreadLocal<u64>> {
|
||||||
Ok(ThreadLocal(ptr))
|
unsafe { read_mib(self.0.as_ref()).map(ThreadLocal) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,6 +117,7 @@ impl DeallocatedP {
|
||||||
///
|
///
|
||||||
/// It is neither `Sync` nor `Send`.
|
/// It is neither `Sync` nor `Send`.
|
||||||
// NB we need *const here specifically since it's !Sync + !Send
|
// NB we need *const here specifically since it's !Sync + !Send
|
||||||
|
#[repr(transparent)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct ThreadLocal<T>(*const T);
|
pub struct ThreadLocal<T>(*const T);
|
||||||
|
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
//! Version operations.
|
|
||||||
|
|
||||||
use error::Result;
|
|
||||||
use keys::{Access, AsName, MibStr};
|
|
||||||
|
|
||||||
const VERSION: &[u8] = b"version\0";
|
|
||||||
|
|
||||||
/// Returns the jemalloc version string.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// The version of jemalloc currently shipped with the Rust distribution has a bogus version string.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// println!("jemalloc version {}", jemalloc_ctl::version().unwrap());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn version() -> Result<&'static str> {
|
|
||||||
VERSION.name().read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type providing access to the jemalloc version string.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate jemallocator;
|
|
||||||
/// extern crate jemalloc_ctl;
|
|
||||||
///
|
|
||||||
/// use jemalloc_ctl::Version;
|
|
||||||
///
|
|
||||||
/// #[global_allocator]
|
|
||||||
/// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let version = Version::new().unwrap();
|
|
||||||
///
|
|
||||||
/// println!("jemalloc version {}", version.get().unwrap());
|
|
||||||
/// }
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct Version(MibStr<[usize; 1]>);
|
|
||||||
|
|
||||||
impl Version {
|
|
||||||
/// Returns a new `Version`.
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let mib = VERSION.name().mib_str()?;
|
|
||||||
Ok(Version(mib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the jemalloc version string.
|
|
||||||
pub fn get(self) -> Result<&'static str> {
|
|
||||||
self.0.read()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,7 +11,7 @@ static A: Jemalloc = Jemalloc;
|
||||||
|
|
||||||
// Returns true if background threads are enabled.
|
// Returns true if background threads are enabled.
|
||||||
fn background_threads() -> bool {
|
fn background_threads() -> bool {
|
||||||
jemalloc_ctl::opt::background_thread().unwrap()
|
jemalloc_ctl::opt::background_thread::read().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -32,5 +32,5 @@ pub static malloc_conf: Option<&'static libc::c_char> = Some(unsafe {
|
||||||
#[test]
|
#[test]
|
||||||
fn background_threads_enabled() {
|
fn background_threads_enabled() {
|
||||||
// Background threads are unconditionally enabled at run-time by default.
|
// Background threads are unconditionally enabled at run-time by default.
|
||||||
assert_eq!(jemalloc_ctl::opt::background_thread().unwrap(), true);
|
assert_eq!(jemalloc_ctl::opt::background_thread::read().unwrap(), true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ extern crate jemalloc_ctl;
|
||||||
extern crate jemallocator;
|
extern crate jemallocator;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
use jemalloc_ctl::{AsName, Access};
|
use jemalloc_ctl::{Access, AsName};
|
||||||
use jemallocator::Jemalloc;
|
use jemallocator::Jemalloc;
|
||||||
use std::alloc::{GlobalAlloc, Layout};
|
use std::alloc::{GlobalAlloc, Layout};
|
||||||
|
|
||||||
|
@ -21,33 +21,33 @@ fn smoke() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ctl_get_set() {
|
fn ctl_get_set() {
|
||||||
let epoch: u64 = b"epoch\0".name().read().unwrap();
|
let epoch: u64 = "epoch\0".name().read().unwrap();
|
||||||
assert!(epoch > 0);
|
assert!(epoch > 0);
|
||||||
b"epoch\0".name().write(epoch).unwrap();
|
"epoch\0".name().write(epoch).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn ctl_panic_empty_get() {
|
fn ctl_panic_empty_get() {
|
||||||
let _ : u64 = b"".name().read().unwrap();
|
let _: u64 = "".name().read().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn ctl_panic_empty_set() {
|
fn ctl_panic_empty_set() {
|
||||||
let epoch: u64 = b"epoch\0".name().read().unwrap();
|
let epoch: u64 = "epoch\0".name().read().unwrap();
|
||||||
b"".name().write(epoch).unwrap();
|
"".name().write(epoch).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn ctl_panic_non_null_terminated_get() {
|
fn ctl_panic_non_null_terminated_get() {
|
||||||
let _: u64 = b"epoch".name().read().unwrap();
|
let _: u64 = "epoch".name().read().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn ctl_panic_non_null_terminated_set() {
|
fn ctl_panic_non_null_terminated_set() {
|
||||||
let epoch: u64 = b"epoch\0".name().read().unwrap();
|
let epoch: u64 = "epoch\0".name().read().unwrap();
|
||||||
b"epoch".name().write(epoch).unwrap();
|
"epoch".name().write(epoch).unwrap();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue