Skip to main content

corescout_substrate/platform/linux/
mod.rs

1//! Linux backend.
2//!
3//! Topology comes from sysfs ([`sysfs`]); pinning, affinity and thread
4//! accounting come from syscalls (`affinity`).
5//!
6//! Note that [`sysfs`] is compiled on *every* platform, not just Linux: it is
7//! pure file parsing, and keeping it portable is what lets its tests run on any
8//! developer machine against captured sysfs trees. Only the syscall layer is
9//! gated behind `cfg(target_os = "linux")`.
10
11pub mod sysfs;
12
13#[cfg(target_os = "linux")]
14mod affinity;
15
16#[cfg(target_os = "linux")]
17pub use linux_platform::LinuxPlatform;
18
19#[cfg(target_os = "linux")]
20mod linux_platform {
21    use std::process::{Child, Command};
22
23    use super::{affinity, sysfs::Sysfs};
24    use crate::platform::{Platform, SwitchCounters};
25    use crate::topology::{LogicalId, Topology};
26    use corescout_core::cpuset::CpuSet;
27    use corescout_core::error::Result;
28
29    /// The Linux implementation of [`Platform`].
30    pub struct LinuxPlatform {
31        sysfs: Sysfs,
32    }
33
34    impl LinuxPlatform {
35        pub fn new() -> Self {
36            LinuxPlatform {
37                sysfs: Sysfs::system(),
38            }
39        }
40
41        /// Read topology from an alternate filesystem root. Used by tests and
42        /// by the hidden `--sysroot` flag for inspecting a captured tree.
43        pub fn with_sysfs(sysfs: Sysfs) -> Self {
44            LinuxPlatform { sysfs }
45        }
46    }
47
48    impl Default for LinuxPlatform {
49        fn default() -> Self {
50            Self::new()
51        }
52    }
53
54    impl Platform for LinuxPlatform {
55        fn name(&self) -> &'static str {
56            "linux"
57        }
58
59        fn discover_topology(&self) -> Result<Topology> {
60            // The process mask is read first so the topology records what we
61            // were actually allowed to use at discovery time, before any
62            // benchmark thread starts narrowing its own affinity.
63            let affinity = affinity::process_affinity().ok();
64            self.sysfs.read_topology(affinity)
65        }
66
67        fn pin_current_thread(&self, cpu: LogicalId) -> Result<()> {
68            affinity::pin_current_thread(cpu)
69        }
70
71        fn set_current_thread_affinity(&self, cpus: &CpuSet) -> Result<()> {
72            affinity::set_current_thread_affinity(cpus)
73        }
74
75        fn current_thread_affinity(&self) -> Result<CpuSet> {
76            affinity::current_thread_affinity()
77        }
78
79        fn process_affinity(&self) -> Result<CpuSet> {
80            affinity::process_affinity()
81        }
82
83        fn thread_switch_counters(&self) -> Option<SwitchCounters> {
84            affinity::thread_switch_counters()
85        }
86
87        fn spawn_with_affinity(&self, command: &mut Command, cpus: &CpuSet) -> Result<Child> {
88            affinity::spawn_with_affinity(command, cpus)
89        }
90    }
91}