"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/timer/windows_timer.rs" between
hyperfine-1.14.0.tar.gz and hyperfine-1.15.0.tar.gz

About: hyperfine is a command-line benchmarking tool.

windows_timer.rs  (hyperfine-1.14.0):windows_timer.rs  (hyperfine-1.15.0)
#![cfg(windows)] #![cfg(windows)]
#![warn(unsafe_op_in_unsafe_fn)]
use std::mem; use std::{mem, os::windows::io::AsRawHandle, process, ptr};
use std::os::windows::io::{AsRawHandle, RawHandle};
use std::process::Child;
use winapi::um::processthreadsapi::GetProcessTimes; use winapi::{
use winapi::um::winnt::HANDLE; shared::{ntdef::NTSTATUS, ntstatus::STATUS_SUCCESS},
um::{
handleapi::CloseHandle,
jobapi2::{AssignProcessToJobObject, CreateJobObjectW, QueryInformationJo
bObject},
libloaderapi::{GetModuleHandleA, GetProcAddress},
winnt::{
JobObjectBasicAccountingInformation, HANDLE, JOBOBJECT_BASIC_ACCOUNT
ING_INFORMATION,
},
},
};
#[cfg(windows_process_extensions_main_thread_handle)]
use winapi::shared::minwindef::DWORD;
#[cfg(not(windows_process_extensions_main_thread_handle))]
use once_cell::sync::Lazy;
use crate::timer::CPUTimes;
use crate::util::units::Second; use crate::util::units::Second;
const HUNDRED_NS_PER_MS: i64 = 10; const HUNDRED_NS_PER_MS: i64 = 10;
#[cfg(not(windows_process_extensions_main_thread_handle))]
#[allow(non_upper_case_globals)]
static NtResumeProcess: Lazy<unsafe extern "system" fn(ProcessHandle: HANDLE) ->
NTSTATUS> =
Lazy::new(|| {
// SAFETY: Getting the module handle for ntdll.dll is safe
let ntdll = unsafe { GetModuleHandleA(b"ntdll.dll\0".as_ptr().cast()) };
assert!(!ntdll.is_null(), "GetModuleHandleA failed");
// SAFETY: The ntdll handle is valid
let nt_resume_process =
unsafe { GetProcAddress(ntdll, b"NtResumeProcess\0".as_ptr().cast())
};
assert!(!nt_resume_process.is_null(), "GetProcAddress failed");
// SAFETY: We transmute to the correct function signature
unsafe { mem::transmute(nt_resume_process) }
});
pub struct CPUTimer { pub struct CPUTimer {
handle: RawHandle, job_object: HANDLE,
} }
impl CPUTimer { impl CPUTimer {
pub fn start_for_process(process: &Child) -> Self { pub unsafe fn start_suspended_process(child: &process::Child) -> Self {
CPUTimer { // SAFETY: Creating a new job object is safe
handle: process.as_raw_handle(), let job_object = unsafe { CreateJobObjectW(ptr::null_mut(), ptr::null_mu
t()) };
assert!(!job_object.is_null(), "CreateJobObjectW failed");
// SAFETY: The job object handle is valid
let ret = unsafe { AssignProcessToJobObject(job_object, child.as_raw_han
dle()) };
assert!(ret != 0, "AssignProcessToJobObject failed");
#[cfg(windows_process_extensions_main_thread_handle)]
{
// SAFETY: The main thread handle is valid
let ret = unsafe { ResumeThread(child.main_thread_handle().as_raw_ha
ndle()) };
assert!(ret != -1 as DWORD, "ResumeThread failed");
} }
#[cfg(not(windows_process_extensions_main_thread_handle))]
{
// Since we can't get the main thread handle on stable rust, we use
// the undocumented but widely known `NtResumeProcess` function to
// resume a process by it's handle.
// SAFETY: The process handle is valid
let ret = unsafe { NtResumeProcess(child.as_raw_handle()) };
assert!(ret == STATUS_SUCCESS, "NtResumeProcess failed");
}
Self { job_object }
} }
pub fn stop(&self) -> (Second, Second) { pub fn stop(&self) -> (Second, Second) {
let times = get_cpu_times(self.handle); let mut job_object_info =
( mem::MaybeUninit::<JOBOBJECT_BASIC_ACCOUNTING_INFORMATION>::uninit()
times.user_usec as f64 * 1e-6, ;
times.system_usec as f64 * 1e-6,
)
}
}
/// Read CPU execution times // SAFETY: A valid job object got created in `start_suspended_process`
fn get_cpu_times(handle: RawHandle) -> CPUTimes { let res = unsafe {
let (user_usec, system_usec) = unsafe { QueryInformationJobObject(
let mut _ctime = mem::zeroed(); self.job_object,
let mut _etime = mem::zeroed(); JobObjectBasicAccountingInformation,
let mut kernel_time = mem::zeroed(); job_object_info.as_mut_ptr().cast(),
let mut user_time = mem::zeroed(); mem::size_of::<JOBOBJECT_BASIC_ACCOUNTING_INFORMATION>() as u32,
let res = GetProcessTimes( ptr::null_mut(),
handle as HANDLE, )
&mut _ctime, };
&mut _etime,
&mut kernel_time,
&mut user_time,
);
// GetProcessTimes will exit with non-zero if success as per: https://ms dn.microsoft.com/en-us/library/windows/desktop/ms683223(v=vs.85).aspx
if res != 0 { if res != 0 {
// Extract times as laid out here: https://support.microsoft.com/en- // SAFETY: The job object info got correctly initialized
us/help/188768/info-working-with-the-filetime-structure let job_object_info = unsafe { job_object_info.assume_init() };
// Both user_time and kernel_time are spans that the process spent i
n either. // SAFETY: The `TotalUserTime` is "The total amount of user-mode exe
let user: i64 = (((user_time.dwHighDateTime as i64) << 32) cution time for
+ user_time.dwLowDateTime as i64) // all active processes associated with the job, as well as all term
/ HUNDRED_NS_PER_MS; inated processes no
let kernel: i64 = (((kernel_time.dwHighDateTime as i64) << 32) // longer associated with the job, in 100-nanosecond ticks." and is
+ kernel_time.dwLowDateTime as i64) safe to extract
/ HUNDRED_NS_PER_MS; let user: i64 = unsafe { job_object_info.TotalUserTime.QuadPart() }
(user, kernel) / HUNDRED_NS_PER_MS;
// SAFETY: The `TotalKernelTime` is "The total amount of kernel-mode
execution time
// for all active processes associated with the job, as well as all
terminated
// processes no longer associated with the job, in 100-nanosecond ti
cks." and is safe
// to extract
let kernel: i64 =
unsafe { job_object_info.TotalKernelTime.QuadPart() } / HUNDRED_
NS_PER_MS;
(user as f64 * 1e-6, kernel as f64 * 1e-6)
} else { } else {
(0, 0) (0.0, 0.0)
} }
}; }
}
CPUTimes { impl Drop for CPUTimer {
user_usec, fn drop(self: &mut Self) {
system_usec, // SAFETY: A valid job object got created in `start_suspended_process`
unsafe { CloseHandle(self.job_object) };
} }
} }
 End of changes. 15 change blocks. 
48 lines changed or deleted 114 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)