Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[host] windows: use millisecond precision for BootTime() #1397

Merged
merged 1 commit into from
Jan 5, 2023

Conversation

jefferbrecht
Copy link
Contributor

Previously, system uptime is truncated to seconds, and then the subtraction from time.Now() is performed. Because uptime does not roll over to the next second at the same instant as time.Now(), then BootTime() ends up not being precise, and often varies by 1 second.

This commit does the subtraction before truncating to seconds, which results in a significantly lower chance of variance in BootTime().

Old behaviour before change:

PS C:\Users\jefferbrecht\go\src\boottime> cat main.go
package main
import (
        "fmt"
        "syscall"
        "time"
        "github.com/shirou/gopsutil/v3/host"
        "golang.org/x/sys/windows"
)
var (
        kernel32DLL      = windows.NewLazyDLL("kernel32.dll")
        procGetTickCount = kernel32DLL.NewProc("GetTickCount64")
)
func main() {
        ticks, _, _ := syscall.Syscall(procGetTickCount.Addr(), 0, 0, 0, 0)
        boot, _ := host.BootTime()
        now := time.Now().Unix()
        fmt.Printf("%d\t%d\t%d\n", ticks, boot, now)
}
PS C:\Users\jefferbrecht\go\src\boottime> go build .
PS C:\Users\jefferbrecht\go\src\boottime> for ($i = 0; $i -lt 5; $i++) { .\boottime.exe }
GetTickCount()  host.BootTime() time.Now()
374255953       1671094442      1671468697
374255984       1671094442      1671468697
374256000       1671094441      1671468697  <-- host.BootTime() rolls over
374256031       1671094441      1671468697
374256093       1671094441      1671468697

New behaviour after change:

PS C:\Users\jefferbrecht\go\src\boottime> for ($i = 0; $i -lt 5; $i++) { .\boottime.exe }
GetTickCount()  host.BootTime() time.Now()
374009953       1671094441      1671468451
374009968       1671094441      1671468451
374010000       1671094441      1671468451  <-- host.BootTime() does not roll over
374010015       1671094441      1671468451
374010046       1671094441      1671468451

Note that there is still a chance for BootTime() to roll over e.g. if the true boot time's milliseconds portion is close to 0. There is not much to be done about this since we cannot get both GetTickCount and time.Now atomically at the same instant.

Copy link
Owner

@shirou shirou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! It seems good to me. But could you change line endings to fix lint error?

host/host.go Outdated Show resolved Hide resolved
Previously, system uptime is truncated to seconds, and then the
subtraction from `time.Now()` is performed. Because uptime does not roll
over to the next second at the same instant as `time.Now()`, then
`BootTime()` ends up not being precise, and often varies by 1 second.

This commit does the subtraction before truncating to seconds, which
results in a significantly lower chance of variance in `BootTime()`.
Copy link
Owner

@shirou shirou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, Thank you so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants