1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2019 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker //! Wrappers for CPU affinity functions.
6*bb4ee6a4SAndroid Build Coastguard Worker
7*bb4ee6a4SAndroid Build Coastguard Worker use std::iter::FromIterator;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
9*bb4ee6a4SAndroid Build Coastguard Worker
10*bb4ee6a4SAndroid Build Coastguard Worker use libc::cpu_set_t;
11*bb4ee6a4SAndroid Build Coastguard Worker use libc::prctl;
12*bb4ee6a4SAndroid Build Coastguard Worker use libc::sched_getaffinity;
13*bb4ee6a4SAndroid Build Coastguard Worker use libc::sched_setaffinity;
14*bb4ee6a4SAndroid Build Coastguard Worker use libc::CPU_ISSET;
15*bb4ee6a4SAndroid Build Coastguard Worker use libc::CPU_SET;
16*bb4ee6a4SAndroid Build Coastguard Worker use libc::CPU_SETSIZE;
17*bb4ee6a4SAndroid Build Coastguard Worker use libc::CPU_ZERO;
18*bb4ee6a4SAndroid Build Coastguard Worker use libc::EINVAL;
19*bb4ee6a4SAndroid Build Coastguard Worker
20*bb4ee6a4SAndroid Build Coastguard Worker use super::Error;
21*bb4ee6a4SAndroid Build Coastguard Worker use super::Result;
22*bb4ee6a4SAndroid Build Coastguard Worker
23*bb4ee6a4SAndroid Build Coastguard Worker // This is needed because otherwise the compiler will complain that the
24*bb4ee6a4SAndroid Build Coastguard Worker // impl doesn't reference any types from inside this crate.
25*bb4ee6a4SAndroid Build Coastguard Worker struct CpuSet(cpu_set_t);
26*bb4ee6a4SAndroid Build Coastguard Worker
27*bb4ee6a4SAndroid Build Coastguard Worker impl CpuSet {
new() -> CpuSet28*bb4ee6a4SAndroid Build Coastguard Worker pub fn new() -> CpuSet {
29*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
30*bb4ee6a4SAndroid Build Coastguard Worker // cpu_set_t is a C struct and can be safely initialized with zeroed memory.
31*bb4ee6a4SAndroid Build Coastguard Worker let mut cpuset: cpu_set_t = unsafe { mem::MaybeUninit::zeroed().assume_init() };
32*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
33*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we pass a valid cpuset pointer.
34*bb4ee6a4SAndroid Build Coastguard Worker unsafe { CPU_ZERO(&mut cpuset) };
35*bb4ee6a4SAndroid Build Coastguard Worker CpuSet(cpuset)
36*bb4ee6a4SAndroid Build Coastguard Worker }
37*bb4ee6a4SAndroid Build Coastguard Worker
38*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::unnecessary_cast)]
to_cpus(&self) -> Vec<usize>39*bb4ee6a4SAndroid Build Coastguard Worker pub fn to_cpus(&self) -> Vec<usize> {
40*bb4ee6a4SAndroid Build Coastguard Worker let mut cpus = Vec::new();
41*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..(CPU_SETSIZE as usize) {
42*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: Safe because `i` and `self.0` are valid.
43*bb4ee6a4SAndroid Build Coastguard Worker if unsafe { CPU_ISSET(i, &self.0) } {
44*bb4ee6a4SAndroid Build Coastguard Worker cpus.push(i);
45*bb4ee6a4SAndroid Build Coastguard Worker }
46*bb4ee6a4SAndroid Build Coastguard Worker }
47*bb4ee6a4SAndroid Build Coastguard Worker cpus
48*bb4ee6a4SAndroid Build Coastguard Worker }
49*bb4ee6a4SAndroid Build Coastguard Worker }
50*bb4ee6a4SAndroid Build Coastguard Worker
51*bb4ee6a4SAndroid Build Coastguard Worker impl FromIterator<usize> for CpuSet {
from_iter<I: IntoIterator<Item = usize>>(cpus: I) -> Self52*bb4ee6a4SAndroid Build Coastguard Worker fn from_iter<I: IntoIterator<Item = usize>>(cpus: I) -> Self {
53*bb4ee6a4SAndroid Build Coastguard Worker let mut cpuset = CpuSet::new();
54*bb4ee6a4SAndroid Build Coastguard Worker for cpu in cpus {
55*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
56*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we pass a valid cpu index and cpuset.0 is a valid pointer.
57*bb4ee6a4SAndroid Build Coastguard Worker unsafe { CPU_SET(cpu, &mut cpuset.0) };
58*bb4ee6a4SAndroid Build Coastguard Worker }
59*bb4ee6a4SAndroid Build Coastguard Worker cpuset
60*bb4ee6a4SAndroid Build Coastguard Worker }
61*bb4ee6a4SAndroid Build Coastguard Worker }
62*bb4ee6a4SAndroid Build Coastguard Worker
63*bb4ee6a4SAndroid Build Coastguard Worker /// Set the CPU affinity of the current thread to a given set of CPUs.
64*bb4ee6a4SAndroid Build Coastguard Worker ///
65*bb4ee6a4SAndroid Build Coastguard Worker /// # Examples
66*bb4ee6a4SAndroid Build Coastguard Worker ///
67*bb4ee6a4SAndroid Build Coastguard Worker /// Set the calling thread's CPU affinity so it will run on only CPUs
68*bb4ee6a4SAndroid Build Coastguard Worker /// 0, 1, 5, and 6.
69*bb4ee6a4SAndroid Build Coastguard Worker ///
70*bb4ee6a4SAndroid Build Coastguard Worker /// ```
71*bb4ee6a4SAndroid Build Coastguard Worker /// # use base::linux::set_cpu_affinity;
72*bb4ee6a4SAndroid Build Coastguard Worker /// set_cpu_affinity(vec![0, 1, 5, 6]).unwrap();
73*bb4ee6a4SAndroid Build Coastguard Worker /// ```
74*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::unnecessary_cast)]
set_cpu_affinity<I: IntoIterator<Item = usize>>(cpus: I) -> Result<()>75*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_cpu_affinity<I: IntoIterator<Item = usize>>(cpus: I) -> Result<()> {
76*bb4ee6a4SAndroid Build Coastguard Worker let CpuSet(cpuset) = cpus
77*bb4ee6a4SAndroid Build Coastguard Worker .into_iter()
78*bb4ee6a4SAndroid Build Coastguard Worker .map(|cpu| {
79*bb4ee6a4SAndroid Build Coastguard Worker if cpu < CPU_SETSIZE as usize {
80*bb4ee6a4SAndroid Build Coastguard Worker Ok(cpu)
81*bb4ee6a4SAndroid Build Coastguard Worker } else {
82*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::new(EINVAL))
83*bb4ee6a4SAndroid Build Coastguard Worker }
84*bb4ee6a4SAndroid Build Coastguard Worker })
85*bb4ee6a4SAndroid Build Coastguard Worker .collect::<Result<CpuSet>>()?;
86*bb4ee6a4SAndroid Build Coastguard Worker
87*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
88*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we pass 0 for the current thread, and cpuset is a valid pointer and only
89*bb4ee6a4SAndroid Build Coastguard Worker // used for the duration of this call.
90*bb4ee6a4SAndroid Build Coastguard Worker crate::syscall!(unsafe { sched_setaffinity(0, mem::size_of_val(&cpuset), &cpuset) })?;
91*bb4ee6a4SAndroid Build Coastguard Worker
92*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
93*bb4ee6a4SAndroid Build Coastguard Worker }
94*bb4ee6a4SAndroid Build Coastguard Worker
get_cpu_affinity() -> Result<Vec<usize>>95*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_cpu_affinity() -> Result<Vec<usize>> {
96*bb4ee6a4SAndroid Build Coastguard Worker let mut cpu_set = CpuSet::new();
97*bb4ee6a4SAndroid Build Coastguard Worker
98*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
99*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we pass 0 for the current thread, and cpu_set.0 is a valid pointer and only
100*bb4ee6a4SAndroid Build Coastguard Worker // used for the duration of this call.
101*bb4ee6a4SAndroid Build Coastguard Worker crate::syscall!(unsafe { sched_getaffinity(0, mem::size_of_val(&cpu_set.0), &mut cpu_set.0) })?;
102*bb4ee6a4SAndroid Build Coastguard Worker
103*bb4ee6a4SAndroid Build Coastguard Worker Ok(cpu_set.to_cpus())
104*bb4ee6a4SAndroid Build Coastguard Worker }
105*bb4ee6a4SAndroid Build Coastguard Worker
106*bb4ee6a4SAndroid Build Coastguard Worker /// Enable experimental core scheduling for the current thread.
107*bb4ee6a4SAndroid Build Coastguard Worker ///
108*bb4ee6a4SAndroid Build Coastguard Worker /// If successful, the kernel should not schedule this thread with any other thread within the same
109*bb4ee6a4SAndroid Build Coastguard Worker /// SMT core. Because this is experimental, this will return success on kernels which do not support
110*bb4ee6a4SAndroid Build Coastguard Worker /// this function.
enable_core_scheduling() -> Result<()>111*bb4ee6a4SAndroid Build Coastguard Worker pub fn enable_core_scheduling() -> Result<()> {
112*bb4ee6a4SAndroid Build Coastguard Worker const PR_SCHED_CORE: i32 = 62;
113*bb4ee6a4SAndroid Build Coastguard Worker const PR_SCHED_CORE_CREATE: i32 = 1;
114*bb4ee6a4SAndroid Build Coastguard Worker
115*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::upper_case_acronyms, non_camel_case_types, dead_code)]
116*bb4ee6a4SAndroid Build Coastguard Worker /// Specifies the scope of the pid parameter of `PR_SCHED_CORE`.
117*bb4ee6a4SAndroid Build Coastguard Worker enum pid_type {
118*bb4ee6a4SAndroid Build Coastguard Worker /// `PID` refers to threads.
119*bb4ee6a4SAndroid Build Coastguard Worker PIDTYPE_PID,
120*bb4ee6a4SAndroid Build Coastguard Worker /// `TGPID` refers to a process.
121*bb4ee6a4SAndroid Build Coastguard Worker PIDTYPE_TGID,
122*bb4ee6a4SAndroid Build Coastguard Worker /// `TGPID` refers to a process group.
123*bb4ee6a4SAndroid Build Coastguard Worker PIDTYPE_PGID,
124*bb4ee6a4SAndroid Build Coastguard Worker }
125*bb4ee6a4SAndroid Build Coastguard Worker
126*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: Safe because we check the return value to prctl.
127*bb4ee6a4SAndroid Build Coastguard Worker let ret = unsafe {
128*bb4ee6a4SAndroid Build Coastguard Worker prctl(
129*bb4ee6a4SAndroid Build Coastguard Worker PR_SCHED_CORE,
130*bb4ee6a4SAndroid Build Coastguard Worker PR_SCHED_CORE_CREATE,
131*bb4ee6a4SAndroid Build Coastguard Worker 0, // id of target task, 0 indicates current task
132*bb4ee6a4SAndroid Build Coastguard Worker pid_type::PIDTYPE_PID as i32, // PID scopes to this thread only
133*bb4ee6a4SAndroid Build Coastguard Worker 0, // ignored by PR_SCHED_CORE_CREATE command
134*bb4ee6a4SAndroid Build Coastguard Worker )
135*bb4ee6a4SAndroid Build Coastguard Worker };
136*bb4ee6a4SAndroid Build Coastguard Worker if ret == -1 {
137*bb4ee6a4SAndroid Build Coastguard Worker let error = Error::last();
138*bb4ee6a4SAndroid Build Coastguard Worker // prctl returns EINVAL for unknown functions, which we will ignore for now.
139*bb4ee6a4SAndroid Build Coastguard Worker if error.errno() != libc::EINVAL {
140*bb4ee6a4SAndroid Build Coastguard Worker return Err(error);
141*bb4ee6a4SAndroid Build Coastguard Worker }
142*bb4ee6a4SAndroid Build Coastguard Worker }
143*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
144*bb4ee6a4SAndroid Build Coastguard Worker }
145