owpengram-server/internal/hoststats/cpu_windows.go
2026-08-07 04:26:56 +03:00

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)
}