cpu.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::io;
  19. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
  20. pub struct CpuThread {
  21. affinity: i32,
  22. intensity: u32,
  23. }
  24. impl CpuThread {
  25. pub fn new(affinity: i32, intensity: Option<u32>) -> Self {
  26. Self { affinity, intensity: intensity.unwrap_or(0) }
  27. }
  28. #[inline]
  29. pub fn is_valid(&self) -> bool {
  30. self.intensity <= 8
  31. }
  32. #[inline]
  33. pub fn affinity(&self) -> i32 {
  34. self.affinity
  35. }
  36. #[inline]
  37. pub fn intensity(&self) -> u32 {
  38. if self.intensity == 0 {
  39. 1
  40. } else {
  41. self.intensity
  42. }
  43. }
  44. }
  45. #[derive(Debug, Clone, PartialEq, Eq)]
  46. pub struct CpuThreads {
  47. affinity: i32,
  48. data: Vec<CpuThread>,
  49. }
  50. impl CpuThreads {
  51. pub fn new(count: usize, intensity: u32) -> Self {
  52. let mut self_ = Self { affinity: -1, data: Vec::with_capacity(count) };
  53. for _ in 0..count {
  54. self_.add(CpuThread::new(-1, Some(intensity)));
  55. }
  56. self_
  57. }
  58. pub fn is_empty(&self) -> bool {
  59. self.data.is_empty()
  60. }
  61. pub fn add(&mut self, thread: CpuThread) {
  62. self.data.push(thread)
  63. }
  64. pub fn threads(&self) -> &[CpuThread] {
  65. &self.data
  66. }
  67. }
  68. #[inline]
  69. pub fn get_affinity(index: u64, affinity: i32) -> i32 {
  70. if affinity < 0 {
  71. return -1
  72. }
  73. let affinity = affinity as u64;
  74. let mut idx = 0u64;
  75. for i in 0..64 {
  76. if (affinity & (1u64 << i)) == 0 {
  77. continue
  78. }
  79. if idx == index {
  80. return i
  81. }
  82. idx += 1;
  83. }
  84. -1
  85. }
  86. /// Binds the current thread to the specified core(s)
  87. pub fn set_thread_affinity<B: AsRef<[usize]>>(core_ids: B) -> io::Result<()> {
  88. os::set_thread_affinity(core_ids.as_ref())
  89. }
  90. /// Returns a list of cores that the current thread is bound to
  91. pub fn get_thread_affinity() -> io::Result<Vec<usize>> {
  92. os::get_thread_affinity()
  93. }
  94. // https://github.com/elast0ny/affinity/
  95. // Licensed under MIT
  96. #[cfg(target_os = "linux")]
  97. mod os {
  98. use libc::{
  99. cpu_set_t, pid_t, sched_getaffinity, sched_setaffinity, CPU_ISSET, CPU_SET, CPU_SETSIZE,
  100. };
  101. use std::{
  102. io,
  103. mem::{size_of, zeroed},
  104. };
  105. pub(super) fn set_thread_affinity(core_ids: &[usize]) -> io::Result<()> {
  106. let mut set: cpu_set_t = unsafe { zeroed() };
  107. unsafe {
  108. for core_id in core_ids {
  109. CPU_SET(*core_id, &mut set);
  110. }
  111. }
  112. _sched_setaffinity(0, size_of::<cpu_set_t>(), &set)
  113. }
  114. pub(super) fn get_thread_affinity() -> io::Result<Vec<usize>> {
  115. let mut affinity = vec![];
  116. let mut set: cpu_set_t = unsafe { zeroed() };
  117. _sched_getaffinity(0, size_of::<cpu_set_t>(), &mut set)?;
  118. for i in 0..CPU_SETSIZE as usize {
  119. if unsafe { CPU_ISSET(i, &set) } {
  120. affinity.push(i);
  121. }
  122. }
  123. Ok(affinity)
  124. }
  125. fn _sched_setaffinity(pid: pid_t, cpusetsize: usize, mask: &cpu_set_t) -> io::Result<()> {
  126. let res = unsafe { sched_setaffinity(pid, cpusetsize, mask) };
  127. if res != 0 {
  128. return Err(io::Error::last_os_error())
  129. }
  130. Ok(())
  131. }
  132. fn _sched_getaffinity(pid: pid_t, cpusetsize: usize, mask: &mut cpu_set_t) -> io::Result<()> {
  133. let res = unsafe { sched_getaffinity(pid, cpusetsize, mask) };
  134. if res != 0 {
  135. return Err(io::Error::last_os_error())
  136. }
  137. Ok(())
  138. }
  139. }