use crate::error::{MemError, Result};
pub fn bind_thread_to_local_numa() -> Result<()> {
#[cfg(target_os = "linux")]
{
let numa_node = local_numa_node()?;
tracing::debug!(numa_node, "binding Data Plane thread to NUMA node");
let mut nodemask: libc::c_ulong =
1 << (numa_node as usize % (8 * std::mem::size_of::<libc::c_ulong>()));
let maxnode: libc::c_ulong = numa_node as libc::c_ulong + 2;
let ret = unsafe {
libc::syscall(
libc::SYS_set_mempolicy,
2i64, &mut nodemask as *mut libc::c_ulong,
maxnode,
)
};
if ret != 0 {
let errno = unsafe { *libc::__errno_location() };
if errno == libc::ENOSYS || errno == libc::EPERM {
tracing::debug!(errno, "set_mempolicy not available; using default policy");
return Ok(());
}
return Err(MemError::Jemalloc(format!(
"set_mempolicy(MPOL_BIND, node={numa_node}) failed: errno={errno}"
)));
}
}
Ok(())
}
#[cfg(target_os = "linux")]
fn local_numa_node() -> Result<u32> {
let mut cpu: u32 = 0;
let mut node: u32 = 0;
let ret = unsafe {
libc::syscall(
libc::SYS_getcpu,
&mut cpu as *mut u32,
&mut node as *mut u32,
std::ptr::null_mut::<libc::c_void>(),
)
};
if ret != 0 {
return Ok(0);
}
Ok(node)
}
pub fn pin_thread_arena(arena_index: u32) -> Result<u32> {
let narenas = read_narenas()?;
let target_arena = if (arena_index as usize) < narenas {
arena_index
} else {
create_arena()?
};
set_thread_arena(target_arena)?;
Ok(target_arena)
}
fn read_narenas() -> Result<usize> {
tikv_jemalloc_ctl::arenas::narenas::read()
.map(|v| v as usize)
.map_err(|e| MemError::Jemalloc(format!("failed to read narenas: {e:?}")))
}
fn create_arena() -> Result<u32> {
let arena_idx: u32 = unsafe { tikv_jemalloc_ctl::raw::read(b"arenas.create\0") }
.map_err(|e| MemError::Jemalloc(format!("failed to create arena: {e:?}")))?;
Ok(arena_idx)
}
fn set_thread_arena(arena: u32) -> Result<()> {
unsafe { tikv_jemalloc_ctl::raw::write(b"thread.arena\0", arena) }
.map_err(|e| MemError::Jemalloc(format!("failed to set thread arena: {e:?}")))?;
Ok(())
}
pub fn current_thread_arena() -> Result<u32> {
let arena: u32 = unsafe { tikv_jemalloc_ctl::raw::read(b"thread.arena\0") }
.map_err(|e| MemError::Jemalloc(format!("failed to read thread arena: {e:?}")))?;
Ok(arena)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pin_and_read_arena() {
let assigned = pin_thread_arena(0).unwrap();
assert_eq!(assigned, 0);
let current = current_thread_arena().unwrap();
assert_eq!(current, 0);
}
#[test]
fn create_and_pin_new_arena() {
let narenas = read_narenas().unwrap();
let assigned = pin_thread_arena(narenas as u32 + 100).unwrap();
let current = current_thread_arena().unwrap();
assert_eq!(current, assigned);
}
}