]>
Commit | Line | Data |
---|---|---|
476ff2be SL |
1 | //! Replaces the deprecated functionality of std::os::num_cpus. |
2 | #![cfg_attr(test, deny(warnings))] | |
3 | #![deny(missing_docs)] | |
4 | #![allow(non_snake_case)] | |
5 | ||
6 | #[cfg(not(windows))] | |
7 | extern crate libc; | |
8 | ||
9 | /// Returns the number of CPUs of the current machine. | |
10 | #[inline] | |
11 | pub fn get() -> usize { | |
12 | get_num_cpus() | |
13 | } | |
14 | ||
7cac9316 XL |
15 | /// Returns the number of physical cores of the current machine. |
16 | /// If not possible on the particular architecture returns same as get() which | |
17 | /// is the logical CPUs. | |
18 | #[inline] | |
19 | pub fn get_physical() -> usize { | |
20 | get_num_physical_cpus() | |
21 | } | |
22 | ||
23 | ||
24 | #[cfg(not(target_os = "linux"))] | |
25 | #[inline] | |
26 | fn get_num_physical_cpus() -> usize { | |
27 | // Not implemented, fallback | |
28 | get_num_cpus() | |
29 | } | |
30 | ||
31 | #[cfg(target_os = "linux")] | |
32 | fn get_num_physical_cpus() -> usize { | |
33 | use std::io::BufReader; | |
34 | use std::io::BufRead; | |
35 | use std::fs::File; | |
36 | use std::collections::HashSet; | |
37 | ||
38 | let file = match File::open("/proc/cpuinfo") { | |
39 | Ok(val) => val, | |
40 | Err(_) => {return get_num_cpus()}, | |
41 | }; | |
42 | let reader = BufReader::new(file); | |
43 | let mut set = HashSet::new(); | |
44 | let mut coreid: u32 = 0; | |
45 | let mut physid: u32 = 0; | |
46 | let mut chgcount = 0; | |
47 | for line in reader.lines().filter_map(|result| result.ok()) { | |
48 | let parts: Vec<&str> = line.split(':').map(|s| s.trim()).collect(); | |
49 | if parts.len() != 2 { | |
50 | continue | |
51 | } | |
52 | if parts[0] == "core id" || parts[0] == "physical id" { | |
53 | let value = match parts[1].trim().parse() { | |
54 | Ok(val) => val, | |
55 | Err(_) => break, | |
56 | }; | |
57 | match parts[0] { | |
58 | "core id" => coreid = value, | |
59 | "physical id" => physid = value, | |
60 | _ => {}, | |
61 | } | |
62 | chgcount += 1; | |
63 | } | |
64 | if chgcount == 2 { | |
65 | set.insert((physid, coreid)); | |
66 | chgcount = 0; | |
67 | } | |
68 | } | |
69 | let count = set.len(); | |
70 | if count == 0 { get_num_cpus() } else { count } | |
71 | } | |
72 | ||
476ff2be SL |
73 | #[cfg(windows)] |
74 | fn get_num_cpus() -> usize { | |
75 | #[repr(C)] | |
76 | struct SYSTEM_INFO { | |
77 | wProcessorArchitecture: u16, | |
78 | wReserved: u16, | |
79 | dwPageSize: u32, | |
80 | lpMinimumApplicationAddress: *mut u8, | |
81 | lpMaximumApplicationAddress: *mut u8, | |
82 | dwActiveProcessorMask: *mut u8, | |
83 | dwNumberOfProcessors: u32, | |
84 | dwProcessorType: u32, | |
85 | dwAllocationGranularity: u32, | |
86 | wProcessorLevel: u16, | |
87 | wProcessorRevision: u16, | |
88 | } | |
89 | ||
90 | extern "system" { | |
91 | fn GetSystemInfo(lpSystemInfo: *mut SYSTEM_INFO); | |
92 | } | |
93 | ||
94 | unsafe { | |
95 | let mut sysinfo: SYSTEM_INFO = std::mem::uninitialized(); | |
96 | GetSystemInfo(&mut sysinfo); | |
97 | sysinfo.dwNumberOfProcessors as usize | |
98 | } | |
99 | } | |
100 | ||
101 | #[cfg(any(target_os = "freebsd", | |
102 | target_os = "dragonfly", | |
103 | target_os = "bitrig", | |
104 | target_os = "netbsd"))] | |
105 | fn get_num_cpus() -> usize { | |
106 | let mut cpus: libc::c_uint = 0; | |
107 | let mut cpus_size = std::mem::size_of_val(&cpus); | |
108 | ||
109 | unsafe { | |
110 | cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint; | |
111 | } | |
112 | if cpus < 1 { | |
113 | let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; | |
114 | unsafe { | |
115 | libc::sysctl(mib.as_mut_ptr(), | |
116 | 2, | |
117 | &mut cpus as *mut _ as *mut _, | |
118 | &mut cpus_size as *mut _ as *mut _, | |
119 | 0 as *mut _, | |
120 | 0); | |
121 | } | |
122 | if cpus < 1 { | |
123 | cpus = 1; | |
124 | } | |
125 | } | |
126 | cpus as usize | |
127 | } | |
128 | ||
129 | #[cfg(target_os = "openbsd")] | |
130 | fn get_num_cpus() -> usize { | |
131 | let mut cpus: libc::c_uint = 0; | |
132 | let mut cpus_size = std::mem::size_of_val(&cpus); | |
133 | let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; | |
134 | ||
135 | unsafe { | |
136 | libc::sysctl(mib.as_mut_ptr(), | |
137 | 2, | |
138 | &mut cpus as *mut _ as *mut _, | |
139 | &mut cpus_size as *mut _ as *mut _, | |
140 | 0 as *mut _, | |
141 | 0); | |
142 | } | |
143 | if cpus < 1 { | |
144 | cpus = 1; | |
145 | } | |
146 | cpus as usize | |
147 | } | |
148 | ||
149 | #[cfg( | |
150 | any( | |
151 | target_os = "linux", | |
152 | target_os = "nacl", | |
153 | target_os = "macos", | |
154 | target_os = "ios", | |
155 | target_os = "android", | |
156 | target_os = "solaris", | |
7cac9316 | 157 | target_os = "fuchsia", |
476ff2be SL |
158 | ) |
159 | )] | |
160 | fn get_num_cpus() -> usize { | |
161 | unsafe { | |
162 | libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize | |
163 | } | |
164 | } | |
7cac9316 XL |
165 | #[cfg(any(target_os = "emscripten", target_os = "redox", target_os = "haiku"))] |
166 | fn get_num_cpus() -> usize { | |
167 | 1 | |
168 | } | |
476ff2be SL |
169 | |
170 | #[test] | |
171 | fn lower_bound() { | |
172 | assert!(get() > 0); | |
7cac9316 | 173 | assert!(get_physical() > 0); |
476ff2be SL |
174 | } |
175 | ||
176 | ||
177 | #[test] | |
178 | fn upper_bound() { | |
179 | assert!(get() < 236_451); | |
7cac9316 | 180 | assert!(get_physical() < 236_451); |
476ff2be | 181 | } |