feat: resource_pressure - disk free, CPU freq/throttle/temp, GPU temp via nvidia-smi

This commit is contained in:
AetherForge
2026-05-30 23:22:32 -07:00
parent d010292333
commit 6704933568
13 changed files with 537 additions and 2 deletions

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