Skip to content

Commit ab6fa89

Browse files
committed
Auto merge of #7429 - alexcrichton:fix-osx-cpu, r=ehuss
Fix macOS collection of CPU data There's very little documentation on `host_processor_info` from what I can tell, so I'm just cribbing examples I've found elsewhere on the internet. Turns out two things were wrong: * One is that `host_processor_info` returns allocated memory we need to deallocate. Who knew! * Next is that one of the out parameters, `cpu_info_cnt`, is only somehow related to the size of the return, but all example code appears to just read data regardless of what it is. In any case this commit reads [libuv's implementation](https://github.com/libuv/libuv/blob/040543eebf4983b1459a1e0e0e26dae68b80cc28/src/unix/darwin.c#L174-L225) which if good enough for node.js is probably good enough for us. Closes #7427
2 parents 249b31b + 0c812db commit ab6fa89

File tree

1 file changed

+31
-9
lines changed

1 file changed

+31
-9
lines changed

src/cargo/util/cpu.rs

+31-9
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,13 @@ mod imp {
9090
mod imp {
9191
use std::io;
9292
use std::ptr;
93-
use std::slice;
9493

9594
type host_t = u32;
9695
type mach_port_t = u32;
96+
type vm_map_t = mach_port_t;
97+
type vm_offset_t = usize;
98+
type vm_size_t = usize;
99+
type vm_address_t = vm_offset_t;
97100
type processor_flavor_t = i32;
98101
type natural_t = u32;
99102
type processor_info_array_t = *mut i32;
@@ -105,8 +108,11 @@ mod imp {
105108
const CPU_STATE_SYSTEM: usize = 1;
106109
const CPU_STATE_IDLE: usize = 2;
107110
const CPU_STATE_NICE: usize = 3;
111+
const CPU_STATE_MAX: usize = 4;
108112

109113
extern "C" {
114+
static mut mach_task_self_: mach_port_t;
115+
110116
fn mach_host_self() -> mach_port_t;
111117
fn host_processor_info(
112118
host: host_t,
@@ -115,6 +121,11 @@ mod imp {
115121
out_processor_info: *mut processor_info_array_t,
116122
out_processor_infoCnt: *mut mach_msg_type_number_t,
117123
) -> kern_return_t;
124+
fn vm_deallocate(
125+
target_task: vm_map_t,
126+
address: vm_address_t,
127+
size: vm_size_t,
128+
) -> kern_return_t;
118129
}
119130

120131
pub struct State {
@@ -124,34 +135,45 @@ mod imp {
124135
nice: u64,
125136
}
126137

138+
#[repr(C)]
139+
struct processor_cpu_load_info_data_t {
140+
cpu_ticks: [u32; CPU_STATE_MAX],
141+
}
142+
127143
pub fn current() -> io::Result<State> {
144+
// There's scant little documentation on `host_processor_info`
145+
// throughout the internet, so this is just modeled after what everyone
146+
// else is doing. For now this is modeled largely after libuv.
147+
128148
unsafe {
129149
let mut num_cpus_u = 0;
130150
let mut cpu_info = ptr::null_mut();
131-
let mut cpu_info_cnt = 0;
151+
let mut msg_type = 0;
132152
let err = host_processor_info(
133153
mach_host_self(),
134154
PROESSOR_CPU_LOAD_INFO,
135155
&mut num_cpus_u,
136156
&mut cpu_info,
137-
&mut cpu_info_cnt,
157+
&mut msg_type,
138158
);
139159
if err != 0 {
140160
return Err(io::Error::last_os_error());
141161
}
142-
let cpu_info = slice::from_raw_parts(cpu_info, cpu_info_cnt as usize);
143162
let mut ret = State {
144163
user: 0,
145164
system: 0,
146165
idle: 0,
147166
nice: 0,
148167
};
149-
for chunk in cpu_info.chunks(num_cpus_u as usize) {
150-
ret.user += chunk[CPU_STATE_USER] as u64;
151-
ret.system += chunk[CPU_STATE_SYSTEM] as u64;
152-
ret.idle += chunk[CPU_STATE_IDLE] as u64;
153-
ret.nice += chunk[CPU_STATE_NICE] as u64;
168+
let mut current = cpu_info as *const processor_cpu_load_info_data_t;
169+
for _ in 0..num_cpus_u {
170+
ret.user += (*current).cpu_ticks[CPU_STATE_USER] as u64;
171+
ret.system += (*current).cpu_ticks[CPU_STATE_SYSTEM] as u64;
172+
ret.idle += (*current).cpu_ticks[CPU_STATE_IDLE] as u64;
173+
ret.nice += (*current).cpu_ticks[CPU_STATE_NICE] as u64;
174+
current = current.offset(1);
154175
}
176+
vm_deallocate(mach_task_self_, cpu_info as vm_address_t, msg_type as usize);
155177
Ok(ret)
156178
}
157179
}

0 commit comments

Comments
 (0)