feat: resource_pressure - disk free, CPU freq/throttle/temp, GPU temp via nvidia-smi
This commit is contained in:
93
agent/client/resource_windows.go
Normal file
93
agent/client/resource_windows.go
Normal file
@@ -0,0 +1,93 @@
|
||||
//go:build windows
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// collectResourcePressure gathers disk, CPU throttle, and GPU metrics on Windows.
|
||||
func collectResourcePressure() *ResourcePressure {
|
||||
r := &ResourcePressure{}
|
||||
|
||||
// ── Disk free space ───────────────────────────────────────────────────────
|
||||
// Check the drive that hosts the running binary.
|
||||
exe, _ := os.Executable()
|
||||
if exe == "" {
|
||||
exe = `C:\`
|
||||
}
|
||||
freeGB, totalGB, freePct := winDiskStats(filepath.VolumeName(exe))
|
||||
if freePct >= 0 {
|
||||
r.DiskFreeGB = &freeGB
|
||||
r.DiskTotalGB = &totalGB
|
||||
r.DiskFreePct = &freePct
|
||||
}
|
||||
|
||||
// ── CPU frequency via short PowerShell call ───────────────────────────────
|
||||
const cpuScript = `$c=Get-CimInstance Win32_Processor|Select-Object -First 1 CurrentClockSpeed,MaxClockSpeed;@{freq=[int]$c.CurrentClockSpeed;max=[int]$c.MaxClockSpeed}|ConvertTo-Json -Compress`
|
||||
if out, err := exec.Command("powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", cpuScript).Output(); err == nil {
|
||||
var m map[string]interface{}
|
||||
if json.Unmarshal([]byte(strings.TrimSpace(string(out))), &m) == nil {
|
||||
if freq, ok := m["freq"].(float64); ok && freq > 0 {
|
||||
n := int(freq)
|
||||
r.CPUFreqMHz = &n
|
||||
}
|
||||
if max, ok := m["max"].(float64); ok && max > 0 {
|
||||
n := int(max)
|
||||
r.CPUMaxMHz = &n
|
||||
if r.CPUFreqMHz != nil {
|
||||
throttled := float64(*r.CPUFreqMHz) < float64(n)*0.80
|
||||
r.CPUThrottle = &throttled
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── GPU (NVIDIA) ──────────────────────────────────────────────────────────
|
||||
r.GPUTempC, r.GPUUsagePct = probeGPU()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// winDiskStats returns (freeGB, totalGB, freePct) for the given drive letter root.
|
||||
// e.g. pass "C:" — the function appends the backslash.
|
||||
// Returns freePct = -1 on failure.
|
||||
func winDiskStats(volumeName string) (freeGB, totalGB float64, freePct int) {
|
||||
root := volumeName
|
||||
if root == "" {
|
||||
root = "C:"
|
||||
}
|
||||
root += `\`
|
||||
|
||||
kernel32 := syscall.NewLazyDLL("kernel32.dll")
|
||||
getDiskFreeSpaceEx := kernel32.NewProc("GetDiskFreeSpaceExW")
|
||||
|
||||
rootPtr, err := syscall.UTF16PtrFromString(root)
|
||||
if err != nil {
|
||||
return 0, 0, -1
|
||||
}
|
||||
|
||||
var freeAvail, total, totalFree uint64
|
||||
ret, _, _ := getDiskFreeSpaceEx.Call(
|
||||
uintptr(unsafe.Pointer(rootPtr)),
|
||||
uintptr(unsafe.Pointer(&freeAvail)),
|
||||
uintptr(unsafe.Pointer(&total)),
|
||||
uintptr(unsafe.Pointer(&totalFree)),
|
||||
)
|
||||
if ret == 0 || total == 0 {
|
||||
return 0, 0, -1
|
||||
}
|
||||
|
||||
const gb = 1024 * 1024 * 1024
|
||||
freeGB = math.Round(float64(freeAvail)/gb*100) / 100
|
||||
totalGB = math.Round(float64(total)/gb*100) / 100
|
||||
freePct = int(float64(freeAvail) / float64(total) * 100)
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user