Skip to content

Commit

Permalink
add test to determine the TSC frequency
Browse files Browse the repository at this point in the history
  • Loading branch information
stlankes committed May 22, 2020
1 parent cabdbce commit b994cf1
Showing 1 changed file with 86 additions and 0 deletions.
86 changes: 86 additions & 0 deletions src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -811,11 +811,97 @@ fn get_cpu_frequency_from_os() -> std::result::Result<u32, ()> {

#[cfg(test)]
mod tests {
const MHZ_TO_HZ: u64 = 1000000;
const KHZ_TO_HZ: u64 = 1000;

#[cfg(target_os = "linux")]
use crate::linux::tests::has_vm_support;
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::_rdtsc as rdtsc;
use std::time;

use super::*;

#[test]
fn test_detect_freq_from_cpuid() {
let cpuid = CpuId::new();
let has_tsc = cpuid
.get_feature_info()
.map_or(false, |finfo| finfo.has_tsc());

let has_invariant_tsc = cpuid
.get_extended_function_info()
.map_or(false, |efinfo| efinfo.has_invariant_tsc());

let tsc_frequency_hz = cpuid.get_tsc_info().map(|tinfo| {
if tinfo.nominal_frequency() != 0 {
tinfo.tsc_frequency()
} else if tinfo.numerator() != 0 && tinfo.denominator() != 0 {
// Skylake and Kabylake don't report the crystal clock, approximate with base frequency:
cpuid
.get_processor_frequency_info()
.map(|pinfo| pinfo.processor_base_frequency() as u64 * MHZ_TO_HZ)
.map(|cpu_base_freq_hz| {
let crystal_hz = cpu_base_freq_hz * tinfo.denominator() as u64
/ tinfo.numerator() as u64;
crystal_hz * tinfo.numerator() as u64 / tinfo.denominator() as u64
})
} else {
None
}
});

if has_tsc {
// Try to figure out TSC frequency with CPUID
println!(
"TSC Frequency is: {} ({})",
match tsc_frequency_hz {
Some(x) => format!("{} Hz", x.unwrap_or(0)),
None => String::from("unknown"),
},
if has_invariant_tsc {
"invariant"
} else {
"TSC frequency varies with speed-stepping"
}
);

// Check if we run in a VM and the hypervisor can give us the TSC frequency
cpuid.get_hypervisor_info().map(|hv| {
hv.tsc_frequency().map(|tsc_khz| {
let virtual_tsc_frequency_hz = tsc_khz as u64 * KHZ_TO_HZ;
println!(
"Hypervisor reports TSC Frequency at: {} Hz",
virtual_tsc_frequency_hz
);
})
});

// Determine TSC frequency by measuring it (loop for a second, record ticks)
let one_second = time::Duration::from_secs(1);
let now = time::Instant::now();
let start = unsafe { rdtsc() };
if start > 0 {
loop {
if now.elapsed() >= one_second {
break;
}
}
let end = unsafe { rdtsc() };
println!(
"Empirical measurement of TSC frequency was: {} Hz",
(end - start)
);
} else {
println!("Don't have rdtsc on stable!");
assert!(true);
}
} else {
println!("System does not have a TSC.");
assert!(true);
}
}

#[cfg(target_os = "linux")]
#[test]
fn test_get_cpu_frequency_from_os() {
Expand Down

0 comments on commit b994cf1

Please sign in to comment.