From fc01e4835d3c9c5d42444825d00fe584806316a9 Mon Sep 17 00:00:00 2001 From: temple3x Date: Mon, 14 Feb 2022 14:53:58 +0800 Subject: [PATCH] GetCurrentClockSource if CPUID detection failed --- README.md | 18 ++++++++++++++---- tsc.go | 27 +++++++++++++++++++++++++++ tsc_amd64.go | 6 +++++- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 91f66b5..b2140f6 100644 --- a/README.md +++ b/README.md @@ -146,9 +146,18 @@ If `tsc.Supported() == true`, it'll use tsc register. If not, it'll wrap `time.N 1. Using tools provided by this repo to learn how it works: [calibrate](tools/calibrate/README.md), [longdrift](tools/longdrift/README.md). And these tools could help you to detect how stable the tsc register & this lib is in your environment. -2. If your application doesn't care the accuracy of clock too much, you could invoke `tsc.ForceTSC()` for allowing unstable frequency. -3. Invoke `tsc.Calibrate()` periodically if you need to catch up system clock. 5 mins is a good start because the auto NTP adjust is always every 11 mins. -4. Set in-order execution by `tsc.ForbidOutOfOrder()` when you need to measure time cost for short statements. +2. Invoke `tsc.Calibrate()` periodically if you need to catch up system clock. 5 mins is a good start because the auto NTP adjust is always every 11 mins. +3. Set in-order execution by `tsc.ForbidOutOfOrder()` when you need to measure time cost for short statements. + +#### Virtual Machine + +On vm, the CPU feature detection may cannot work as expect because the CPUID limitation, the Invariant TSC feature cannot be detected if so. + +But if the tsc is the system clock source which means this cloud provider could handle tsc clock source well enough, in that situation this lib will enable TSC as clock source too. + +Some cloud vm could support tsc as clock source, e.g., [AWS EC2](https://aws.amazon.com/premiumsupport/knowledge-center/manage-ec2-linux-clock-source/?nc1=h_ls) + +Please contact your vm supports team to make sure the tsc clock source is reliable before using it. ## Limitation @@ -160,4 +169,5 @@ And these tools could help you to detect how stable the tsc register & this lib 1. [Question of linux gettimeofday on StackOverflow](https://stackoverflow.com/questions/13230719/how-is-the-microsecond-time-of-linux-gettimeofday-obtained-and-what-is-its-acc) 2. [Question of TSC frequency variations with temperature on Intel community](https://community.intel.com/t5/Software-Tuning-Performance/TSC-frequency-variations-with-temperature/td-p/1098982) -3. [Question of TSC frequency variations with temperature on Intel community(2)](https://community.intel.com/t5/Software-Tuning-Performance/TSC-frequency-variations-with-temperature/m-p/1126518) \ No newline at end of file +3. [Question of TSC frequency variations with temperature on Intel community(2)](https://community.intel.com/t5/Software-Tuning-Performance/TSC-frequency-variations-with-temperature/m-p/1126518) +4. [Pitfalls of TSC Usage](http://oliveryang.net/2015/09/pitfalls-of-TSC-usage) \ No newline at end of file diff --git a/tsc.go b/tsc.go index 4fefbfe..bd0fd19 100644 --- a/tsc.go +++ b/tsc.go @@ -1,6 +1,9 @@ package tsc import ( + "io/ioutil" + "os" + "runtime" "sync" "time" @@ -104,3 +107,27 @@ func IsOutOfOrder() bool { func isEven(n int) bool { return n&1 == 0 } + +var ( + linuxClockSourcePath = "/sys/devices/system/clocksource/clocksource0/current_clocksource" +) + +// GetCurrentClockSource gets clock source on Linux. +func GetCurrentClockSource() string { + + if runtime.GOOS != "linux" { + return "" + } + + f, err := os.Open(linuxClockSourcePath) + if err != nil { + return "" + } + defer f.Close() + + d, err := ioutil.ReadAll(f) + if err != nil { + return "" + } + return string(d) +} diff --git a/tsc_amd64.go b/tsc_amd64.go index 4784c62..1589232 100644 --- a/tsc_amd64.go +++ b/tsc_amd64.go @@ -48,8 +48,12 @@ func isHardwareSupported() bool { // Invariant TSC could make sure TSC got synced among multi CPUs. // They will be reset at same time, and run in same frequency. + // But in some VM, the max Extended Function in CPUID is < 0x80000007, + // we should enable TSC if the system clock source is TSC. if !cpu.X86.HasInvariantTSC { - return false + if GetCurrentClockSource() != "tsc" { + return false // Cannot detect invariant tsc by CPUID or linux clock source, return false. + } } // Some instructions need AVX, see tsc_amd64.s for details.