github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/platform/time_windows.go (about) 1 //go:build windows 2 3 package platform 4 5 import ( 6 "math/bits" 7 "time" 8 "unsafe" 9 ) 10 11 var ( 12 _QueryPerformanceCounter = kernel32.NewProc("QueryPerformanceCounter") 13 _QueryPerformanceFrequency = kernel32.NewProc("QueryPerformanceFrequency") 14 ) 15 16 var qpcfreq uint64 17 18 func init() { 19 _, _, _ = _QueryPerformanceFrequency.Call(uintptr(unsafe.Pointer(&qpcfreq))) 20 } 21 22 // On Windows, time.Time handled in time package cannot have the nanosecond precision. 23 // The reason is that by default, it doesn't use QueryPerformanceCounter[1], but instead, use "interrupt time" 24 // which doesn't support nanoseconds precision (though it is a monotonic) [2, 3, 4, 5]. 25 // 26 // [1] https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter 27 // [2] https://github.com/golang/go/blob/0cd309e12818f988693bf8e4d9f1453331dcf9f2/src/runtime/sys_windows_amd64.s#L297-L298 28 // [3] https://github.com/golang/go/blob/0cd309e12818f988693bf8e4d9f1453331dcf9f2/src/runtime/os_windows.go#L549-L551 29 // [4] https://github.com/golang/go/blob/master/src/runtime/time_windows.h#L7-L13 30 // [5] http://web.archive.org/web/20210411000829/https://wrkhpi.wordpress.com/2007/08/09/getting-os-information-the-kuser_shared_data-structure/ 31 // 32 // Therefore, on Windows, we directly invoke the syscall for QPC instead of time.Now or runtime.nanotime. 33 // See https://github.com/golang/go/issues/31160 for example. 34 func nanotime() int64 { 35 var counter uint64 36 _, _, _ = _QueryPerformanceCounter.Call(uintptr(unsafe.Pointer(&counter))) 37 hi, lo := bits.Mul64(counter, uint64(time.Second)) 38 nanos, _ := bits.Div64(hi, lo, qpcfreq) 39 return int64(nanos) 40 }