gdt_cpus/lib.rs
1//! GDT-CPUs: Game Developer's Toolkit for CPU Management
2//!
3//! This crate provides detailed CPU information and thread management capabilities
4//! specifically designed for game developers. It aims to simplify tasks such as
5//! querying CPU features, understanding core architecture (including hybrid designs
6//! like P-cores and E-cores), and managing thread affinity and priority.
7//!
8//! # Key Features
9//!
10//! * **Detailed CPU Information**: Access vendor, model name, supported instruction sets
11//! (e.g., AVX2, NEON), cache details, and core topology via the [`CpuInfo`] struct.
12//! * **Hybrid Architecture Support**: Differentiates between performance and
13//! efficiency cores.
14//! * **Thread Affinity**: (Via the `affinity` module) Pin threads to specific
15//! logical or physical cores.
16//! * **Thread Priority**: (Via the `affinity` module) Set thread priorities for
17//! different operating systems.
18//! * **Platform Abstraction**: Provides a consistent API across Windows, macOS, and Linux.
19//! * **Lazy Initialization**: CPU information is detected once and cached globally.
20//!
21//! # Getting Started
22//!
23//! The primary way to get CPU information is through the [`cpu_info()`] function:
24//!
25//! ```
26//! use gdt_cpus::{cpu_info, CpuInfo, Error, CpuFeatures};
27//!
28//! fn main() -> Result<(), Error> {
29//! let info = cpu_info()?;
30//!
31//! println!("CPU Vendor: {}", info.vendor);
32//! println!("CPU Model: {}", info.model_name);
33//! println!("Total Physical Cores: {}", info.total_physical_cores);
34//! println!("Total Logical Processors: {}", info.total_logical_processors);
35//!
36//! if info.is_hybrid() {
37//! println!("This is a hybrid CPU with:");
38//! println!(" Performance Cores: {}", info.total_performance_cores);
39//! println!(" Efficiency Cores: {}", info.total_efficiency_cores);
40//! }
41//!
42//! #[cfg(target_arch = "x86_64")]
43//! if info.features.contains(CpuFeatures::AVX2) {
44//! println!("AVX2 is supported!");
45//! }
46//! #[cfg(target_arch = "aarch64")]
47//! if info.features.contains(CpuFeatures::NEON) {
48//! println!("NEON is supported!");
49//! }
50//!
51//! // You can also use helper functions:
52//! let phys_cores = gdt_cpus::num_physical_cores()?;
53//! println!("Physical cores (via helper): {}", phys_cores);
54//!
55//! Ok(())
56//! }
57//! ```
58//!
59//! # Cargo Features
60//!
61//! * `serde`: Enables serialization and deserialization of CPU information structures
62//! (like [`CpuInfo`], [`CoreInfo`], etc.) using the Serde library.
63
64// #![forbid(unsafe_code)] // Will be selectively allowed in platform-specific modules
65
66// Modules
67mod affinity;
68mod affinity_mask;
69mod cpu;
70mod error;
71mod platform;
72mod priority;
73
74// Re-exports - Public API
75pub use affinity::*;
76pub use affinity_mask::AffinityMask;
77pub use cpu::{
78 CacheInfo, CacheLevel, CacheType, CoreInfo, CoreType, CpuFeatures, CpuInfo, SocketInfo, Vendor,
79};
80pub use error::{Error, Result};
81pub use platform::SchedulingPolicy;
82pub use priority::ThreadPriority;
83
84/// Retrieves a static reference to the globally detected CPU information.
85///
86/// This function utilizes a thread-safe lazy initialization pattern. The CPU
87/// information is detected only once during the first call to this function
88/// (or any related helper function like [`num_physical_cores()`]) within the
89/// program's execution. Subsequent calls return a reference to the cached data.
90///
91/// # Returns
92///
93/// A `Result<&'static CpuInfo, Error>`. You'll typically want to handle the `Result`
94/// to access the `CpuInfo` struct.
95///
96/// # Examples
97///
98/// ```
99/// use gdt_cpus::{cpu_info, CpuInfo, Error};
100///
101/// match cpu_info() {
102/// Ok(info) => {
103/// println!("CPU Model: {}", info.model_name);
104/// println!("This system has {} physical cores.", info.num_physical_cores());
105/// }
106/// Err(e) => {
107/// eprintln!("Failed to get CPU info: {:?}", e);
108/// }
109/// }
110/// ```
111///
112/// For more direct access to the `CpuInfo` struct if successful, you might do:
113/// ```
114/// # use gdt_cpus::{cpu_info, CpuInfo, Error};
115/// # fn main() -> Result<(), Error> {
116/// let info = cpu_info()?;
117/// println!("Successfully retrieved CPU info for: {}", info.model_name);
118/// # Ok(())
119/// # }
120/// ```
121pub fn cpu_info() -> Result<&'static CpuInfo> {
122 static CPU_INFO: std::sync::OnceLock<Result<CpuInfo>> = std::sync::OnceLock::new();
123 match CPU_INFO.get_or_init(CpuInfo::detect) {
124 Ok(cpu_info) => Ok(cpu_info),
125 Err(e) => Err(e.clone()),
126 }
127}
128
129/// Returns the total number of physical cores in the system.
130///
131/// This is a convenience function that calls [`cpu_info()`] and extracts
132/// `total_physical_cores` from the [`CpuInfo`] struct.
133///
134/// # Returns
135///
136/// A `Result<usize, Error>` containing the number of physical cores on success.
137///
138/// # Examples
139///
140/// ```
141/// use gdt_cpus::num_physical_cores;
142///
143/// match num_physical_cores() {
144/// Ok(count) => println!("Number of physical cores: {}", count),
145/// Err(e) => eprintln!("Error getting physical core count: {:?}", e),
146/// }
147/// ```
148pub fn num_physical_cores() -> Result<usize> {
149 cpu_info().map(|info| info.num_physical_cores())
150}
151
152/// Returns the total number of logical cores (hardware threads) in the system.
153///
154/// This count includes threads from technologies like Intel's Hyper-Threading or AMD's SMT.
155/// This is a convenience function that calls [`cpu_info()`] and extracts
156/// `total_logical_processors` from the [`CpuInfo`] struct.
157///
158/// # Returns
159///
160/// A `Result<usize, Error>` containing the number of logical cores on success.
161///
162/// # Examples
163///
164/// ```
165/// use gdt_cpus::num_logical_cores;
166///
167/// match num_logical_cores() {
168/// Ok(count) => println!("Number of logical cores: {}", count),
169/// Err(e) => eprintln!("Error getting logical core count: {:?}", e),
170/// }
171/// ```
172pub fn num_logical_cores() -> Result<usize> {
173 cpu_info().map(|info| info.num_logical_cores())
174}
175
176/// Returns the total number of performance-type physical cores in the system.
177///
178/// This is relevant for hybrid architectures (e.g., Intel P-cores, ARM big cores).
179/// Returns number of physical cores if the system does not have a hybrid architecture.
180/// This is a convenience function that calls [`cpu_info()`] and extracts
181/// `total_performance_cores` from the [`CpuInfo`] struct.
182///
183/// # Returns
184///
185/// A `Result<usize, Error>` containing the number of performance cores on success.
186///
187/// # Examples
188///
189/// ```
190/// use gdt_cpus::num_performance_cores;
191///
192/// match num_performance_cores() {
193/// Ok(count) => println!("Number of performance cores: {}", count),
194/// Err(e) => eprintln!("Error getting performance core count: {:?}", e),
195/// }
196/// ```
197pub fn num_performance_cores() -> Result<usize> {
198 cpu_info().map(|info| info.num_performance_cores())
199}
200
201/// Returns the total number of efficiency-type physical cores in the system.
202///
203/// This is relevant for hybrid architectures (e.g., Intel E-cores, ARM LITTLE cores).
204/// Returns 0 if the system does not have a hybrid architecture or if this information
205/// could not be determined.
206/// This is a convenience function that calls [`cpu_info()`] and extracts
207/// `total_efficiency_cores` from the [`CpuInfo`] struct.
208///
209/// # Returns
210///
211/// A `Result<usize, Error>` containing the number of efficiency cores on success.
212///
213/// # Examples
214///
215/// ```
216/// use gdt_cpus::num_efficiency_cores;
217///
218/// match num_efficiency_cores() {
219/// Ok(count) => println!("Number of efficiency cores: {}", count),
220/// Err(e) => eprintln!("Error getting efficiency core count: {:?}", e),
221/// }
222/// ```
223pub fn num_efficiency_cores() -> Result<usize> {
224 cpu_info().map(|info| info.num_efficiency_cores())
225}
226
227/// Returns `true` if the system CPU has a hybrid architecture (e.g., both P-cores and E-cores).
228///
229/// This is determined by checking if both `total_performance_cores` and
230/// `total_efficiency_cores` (from [`CpuInfo`]) are greater than zero.
231/// This is a convenience function that calls [`cpu_info()`].
232///
233/// # Returns
234///
235/// A `Result<bool, Error>` which is `Ok(true)` if hybrid, `Ok(false)` if not, or an `Err`
236/// if CPU information could not be obtained.
237///
238/// # Examples
239///
240/// ```
241/// use gdt_cpus::is_hybrid;
242///
243/// match is_hybrid() {
244/// Ok(hybrid) => if hybrid {
245/// println!("This system has a hybrid CPU architecture.");
246/// } else {
247/// println!("This system does not have a hybrid CPU architecture.");
248/// }
249/// Err(e) => eprintln!("Error determining if CPU is hybrid: {:?}", e),
250/// }
251/// ```
252pub fn is_hybrid() -> Result<bool> {
253 cpu_info().map(|info| info.is_hybrid())
254}