summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/wall_clock.cpp2
-rw-r--r--src/common/x64/cpu_detect.cpp13
-rw-r--r--src/common/x64/cpu_detect.h5
3 files changed, 19 insertions, 1 deletions
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp
index b4fb3a59f..ae07f2811 100644
--- a/src/common/wall_clock.cpp
+++ b/src/common/wall_clock.cpp
@@ -67,7 +67,7 @@ std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency,
const auto& caps = GetCPUCaps();
u64 rtsc_frequency = 0;
if (caps.invariant_tsc) {
- rtsc_frequency = EstimateRDTSCFrequency();
+ rtsc_frequency = caps.tsc_frequency ? caps.tsc_frequency : EstimateRDTSCFrequency();
}
// Fallback to StandardWallClock if the hardware TSC does not have the precision greater than:
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp
index 322aa1f08..4230b2da6 100644
--- a/src/common/x64/cpu_detect.cpp
+++ b/src/common/x64/cpu_detect.cpp
@@ -161,6 +161,19 @@ static CPUCaps Detect() {
caps.invariant_tsc = Common::Bit<8>(cpu_id[3]);
}
+ if (max_std_fn >= 0x15) {
+ __cpuid(cpu_id, 0x15);
+ caps.tsc_crystal_ratio_denominator = cpu_id[0];
+ caps.tsc_crystal_ratio_numerator = cpu_id[1];
+ caps.crystal_frequency = cpu_id[2];
+ // Some CPU models might not return a crystal frequency.
+ // The CPU model can be detected to use the values from turbostat
+ // https://github.com/torvalds/linux/blob/master/tools/power/x86/turbostat/turbostat.c#L5569
+ // but it's easier to just estimate the TSC tick rate for these cases.
+ caps.tsc_frequency = static_cast<u64>(caps.crystal_frequency) *
+ caps.tsc_crystal_ratio_numerator / caps.tsc_crystal_ratio_denominator;
+ }
+
if (max_std_fn >= 0x16) {
__cpuid(cpu_id, 0x16);
caps.base_frequency = cpu_id[0];
diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h
index 9bdc9dbfa..6830f3795 100644
--- a/src/common/x64/cpu_detect.h
+++ b/src/common/x64/cpu_detect.h
@@ -30,6 +30,11 @@ struct CPUCaps {
u32 max_frequency;
u32 bus_frequency;
+ u32 tsc_crystal_ratio_denominator;
+ u32 tsc_crystal_ratio_numerator;
+ u32 crystal_frequency;
+ u64 tsc_frequency; // Derived from the above three values
+
bool sse : 1;
bool sse2 : 1;
bool sse3 : 1;