/* This file is part of DarkFi (https://dark.fi) * * Copyright (C) 2020-2025 Dyne.org foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ use std::io; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct CpuThread { affinity: i32, intensity: u32, } impl CpuThread { pub fn new(affinity: i32, intensity: Option) -> Self { Self { affinity, intensity: intensity.unwrap_or(0) } } #[inline] pub fn is_valid(&self) -> bool { self.intensity <= 8 } #[inline] pub fn affinity(&self) -> i32 { self.affinity } #[inline] pub fn intensity(&self) -> u32 { if self.intensity == 0 { 1 } else { self.intensity } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct CpuThreads { affinity: i32, data: Vec, } impl CpuThreads { pub fn new(count: usize, intensity: u32) -> Self { let mut self_ = Self { affinity: -1, data: Vec::with_capacity(count) }; for _ in 0..count { self_.add(CpuThread::new(-1, Some(intensity))); } self_ } pub fn is_empty(&self) -> bool { self.data.is_empty() } pub fn add(&mut self, thread: CpuThread) { self.data.push(thread) } pub fn threads(&self) -> &[CpuThread] { &self.data } } #[inline] pub fn get_affinity(index: u64, affinity: i32) -> i32 { if affinity < 0 { return -1 } let affinity = affinity as u64; let mut idx = 0u64; for i in 0..64 { if (affinity & (1u64 << i)) == 0 { continue } if idx == index { return i } idx += 1; } -1 } /// Binds the current thread to the specified core(s) pub fn set_thread_affinity>(core_ids: B) -> io::Result<()> { os::set_thread_affinity(core_ids.as_ref()) } /// Returns a list of cores that the current thread is bound to pub fn get_thread_affinity() -> io::Result> { os::get_thread_affinity() } // https://github.com/elast0ny/affinity/ // Licensed under MIT #[cfg(target_os = "linux")] mod os { use libc::{ cpu_set_t, pid_t, sched_getaffinity, sched_setaffinity, CPU_ISSET, CPU_SET, CPU_SETSIZE, }; use std::{ io, mem::{size_of, zeroed}, }; pub(super) fn set_thread_affinity(core_ids: &[usize]) -> io::Result<()> { let mut set: cpu_set_t = unsafe { zeroed() }; unsafe { for core_id in core_ids { CPU_SET(*core_id, &mut set); } } _sched_setaffinity(0, size_of::(), &set) } pub(super) fn get_thread_affinity() -> io::Result> { let mut affinity = vec![]; let mut set: cpu_set_t = unsafe { zeroed() }; _sched_getaffinity(0, size_of::(), &mut set)?; for i in 0..CPU_SETSIZE as usize { if unsafe { CPU_ISSET(i, &set) } { affinity.push(i); } } Ok(affinity) } fn _sched_setaffinity(pid: pid_t, cpusetsize: usize, mask: &cpu_set_t) -> io::Result<()> { let res = unsafe { sched_setaffinity(pid, cpusetsize, mask) }; if res != 0 { return Err(io::Error::last_os_error()) } Ok(()) } fn _sched_getaffinity(pid: pid_t, cpusetsize: usize, mask: &mut cpu_set_t) -> io::Result<()> { let res = unsafe { sched_getaffinity(pid, cpusetsize, mask) }; if res != 0 { return Err(io::Error::last_os_error()) } Ok(()) } }