init
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
//go:build windows
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const cpuSampleInterval = 100 * time.Millisecond
|
||||
|
||||
var (
|
||||
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
getSystemTimesProc = kernel32.NewProc("GetSystemTimes")
|
||||
globalMemoryStatusExProc = kernel32.NewProc("GlobalMemoryStatusEx")
|
||||
)
|
||||
|
||||
type windowsFileTime struct {
|
||||
lowDateTime uint32
|
||||
highDateTime uint32
|
||||
}
|
||||
|
||||
type windowsMemoryStatusEx struct {
|
||||
dwLength uint32
|
||||
dwMemoryLoad uint32
|
||||
ullTotalPhys uint64
|
||||
ullAvailPhys uint64
|
||||
ullTotalPageFile uint64
|
||||
ullAvailPageFile uint64
|
||||
ullTotalVirtual uint64
|
||||
ullAvailVirtual uint64
|
||||
ullAvailExtendedVirtual uint64
|
||||
}
|
||||
|
||||
type windowsCPUStat struct {
|
||||
idle uint64
|
||||
total uint64
|
||||
}
|
||||
|
||||
func hostCPUPercent(ctx context.Context) (float64, error) {
|
||||
first, err := readWindowsCPUStat()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
timer := time.NewTimer(cpuSampleInterval)
|
||||
defer timer.Stop()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return 0, ctx.Err()
|
||||
case <-timer.C:
|
||||
}
|
||||
second, err := readWindowsCPUStat()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
totalDelta := second.total - first.total
|
||||
idleDelta := second.idle - first.idle
|
||||
if totalDelta == 0 || idleDelta > totalDelta {
|
||||
return 0, fmt.Errorf("Windows CPU counters did not advance")
|
||||
}
|
||||
return clampMetricPercent(100 * float64(totalDelta-idleDelta) / float64(totalDelta)), nil
|
||||
}
|
||||
|
||||
func readWindowsCPUStat() (windowsCPUStat, error) {
|
||||
var idle, kernel, user windowsFileTime
|
||||
result, _, callErr := getSystemTimesProc.Call(uintptr(unsafe.Pointer(&idle)), uintptr(unsafe.Pointer(&kernel)), uintptr(unsafe.Pointer(&user)))
|
||||
if result == 0 {
|
||||
return windowsCPUStat{}, callErr
|
||||
}
|
||||
idleTicks := windowsFileTimeValue(idle)
|
||||
return windowsCPUStat{idle: idleTicks, total: idleTicks + windowsFileTimeValue(kernel) + windowsFileTimeValue(user)}, nil
|
||||
}
|
||||
|
||||
func windowsFileTimeValue(value windowsFileTime) uint64 {
|
||||
return uint64(value.highDateTime)<<32 | uint64(value.lowDateTime)
|
||||
}
|
||||
|
||||
func hostMemoryPercent() (float64, error) {
|
||||
status := windowsMemoryStatusEx{dwLength: uint32(unsafe.Sizeof(windowsMemoryStatusEx{}))}
|
||||
result, _, callErr := globalMemoryStatusExProc.Call(uintptr(unsafe.Pointer(&status)))
|
||||
if result == 0 {
|
||||
return 0, callErr
|
||||
}
|
||||
if status.ullTotalPhys == 0 || status.ullAvailPhys > status.ullTotalPhys {
|
||||
return 0, fmt.Errorf("Windows memory counters are invalid")
|
||||
}
|
||||
return clampMetricPercent(100 * float64(status.ullTotalPhys-status.ullAvailPhys) / float64(status.ullTotalPhys)), nil
|
||||
}
|
||||
|
||||
func clampMetricPercent(value float64) float64 {
|
||||
if value < 0 {
|
||||
return 0
|
||||
}
|
||||
if value > 100 {
|
||||
return 100
|
||||
}
|
||||
return value
|
||||
}
|
||||
Reference in New Issue
Block a user