65 lines
1.7 KiB
Go
65 lines
1.7 KiB
Go
//go:build windows
|
|
|
|
package hoststats
|
|
|
|
import (
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
// GetSystemTimes isn't wrapped by x/sys/windows either -- same manual
|
|
// kernel32.dll binding as GlobalMemoryStatusEx in mem_windows.go.
|
|
var procGetSystemTimes = modkernel32.NewProc("GetSystemTimes")
|
|
|
|
// cpuSampler computes CPU busy% from successive cumulative GetSystemTimes
|
|
// snapshots, mirroring cpu_unix.go's /proc/stat delta approach: the kernel
|
|
// time value already includes idle time on Windows, so busy = (kernel -
|
|
// idle) + user, and total = kernel + user.
|
|
type cpuSampler struct {
|
|
prevIdle, prevKernel, prevUser uint64
|
|
have bool
|
|
}
|
|
|
|
func (c *cpuSampler) sample() float64 {
|
|
idle, kernel, user, ok := getSystemTimes()
|
|
if !ok {
|
|
return 0
|
|
}
|
|
if !c.have {
|
|
c.prevIdle, c.prevKernel, c.prevUser = idle, kernel, user
|
|
c.have = true
|
|
return 0
|
|
}
|
|
deltaIdle := idle - c.prevIdle
|
|
deltaTotal := (kernel - c.prevKernel) + (user - c.prevUser)
|
|
c.prevIdle, c.prevKernel, c.prevUser = idle, kernel, user
|
|
if deltaTotal == 0 {
|
|
return 0
|
|
}
|
|
pct := (1 - float64(deltaIdle)/float64(deltaTotal)) * 100
|
|
switch {
|
|
case pct < 0:
|
|
pct = 0
|
|
case pct > 100:
|
|
pct = 100
|
|
}
|
|
return pct
|
|
}
|
|
|
|
func getSystemTimes() (idle, kernel, user uint64, ok bool) {
|
|
var idleFT, kernelFT, userFT windows.Filetime
|
|
r, _, _ := procGetSystemTimes.Call(
|
|
uintptr(unsafe.Pointer(&idleFT)),
|
|
uintptr(unsafe.Pointer(&kernelFT)),
|
|
uintptr(unsafe.Pointer(&userFT)),
|
|
)
|
|
if r == 0 {
|
|
return 0, 0, 0, false
|
|
}
|
|
return filetimeToUint64(idleFT), filetimeToUint64(kernelFT), filetimeToUint64(userFT), true
|
|
}
|
|
|
|
func filetimeToUint64(ft windows.Filetime) uint64 {
|
|
return uint64(ft.HighDateTime)<<32 | uint64(ft.LowDateTime)
|
|
}
|