100 lines
2.4 KiB
Go
100 lines
2.4 KiB
Go
//go:build windows
|
|
|
|
package loadaverage
|
|
|
|
import (
|
|
"fmt"
|
|
"rpi5-health/internal/windows_system"
|
|
"sync"
|
|
"syscall"
|
|
"time"
|
|
"unsafe"
|
|
)
|
|
|
|
const (
|
|
// Formatting flag for PdhGetFormattedCounterValue to return a float64
|
|
PDH_FMT_DOUBLE = 0x00000200
|
|
ERROR_SUCCESS = 0
|
|
)
|
|
|
|
// PDH_FMT_COUNTERVALUE_DOUBLE maps the C struct _PDH_FMT_COUNTERVALUE for double values.
|
|
// * Note the explicit padding: C++ unions align to 8 bytes on 64-bit systems.
|
|
type PDH_FMT_COUNTERVALUE_DOUBLE struct {
|
|
CStatus uint32
|
|
Pad uint32 // ! Crucial padding for 64-bit alignment before the float64
|
|
DoubleValue float64 // Represents the union where the double is stored
|
|
}
|
|
|
|
var (
|
|
GlobalLoadAverage LoadAverageInformation
|
|
|
|
// 1. A RWMutex protects the struct from concurrent reads/writes
|
|
loadMu sync.RWMutex
|
|
|
|
startWorker = sync.OnceFunc(func() {
|
|
go loadAverageWorker()
|
|
})
|
|
)
|
|
|
|
func loadAverageWorker() {
|
|
var hQuery syscall.Handle // PDH_HQUERY
|
|
var hCounter syscall.Handle // PDH_HCOUNTER
|
|
|
|
wintools := windows_system.GetWindowsTools()
|
|
|
|
// initialize query
|
|
ret, _, _ := wintools.ProcPdhOpenQuery.Call(0, 0, uintptr(unsafe.Pointer(&hQuery)))
|
|
if ret != ERROR_SUCCESS {
|
|
fmt.Printf("PdhOpenQueryW failed: %x\n", ret)
|
|
return
|
|
}
|
|
defer wintools.ProcPdhCloseQuery.Call(uintptr(hQuery))
|
|
|
|
counterPath, _ := syscall.UTF16PtrFromString(`\Processor(_Total)\% Processor Time`)
|
|
ret, _, _ = wintools.ProcPdhAddCounter.Call(
|
|
uintptr(hQuery),
|
|
uintptr(unsafe.Pointer(counterPath)),
|
|
0,
|
|
uintptr(unsafe.Pointer(&hCounter)),
|
|
)
|
|
if ret != ERROR_SUCCESS {
|
|
fmt.Printf("PdhAddCounterW failed: %x\n", ret)
|
|
return
|
|
}
|
|
|
|
// Collect initial data, "priming the counter"
|
|
wintools.ProcPdhCollectQueryData.Call(uintptr(hQuery))
|
|
|
|
// Infinite collection loop
|
|
for {
|
|
time.Sleep(SAMPLE_DELAY)
|
|
|
|
wintools.ProcPdhCollectQueryData.Call(uintptr(hQuery))
|
|
|
|
var counterType uint32
|
|
var value PDH_FMT_COUNTERVALUE_DOUBLE
|
|
|
|
ret, _, _ = wintools.ProcPdhGetFormattedCounterValue.Call(
|
|
uintptr(hCounter),
|
|
uintptr(PDH_FMT_DOUBLE),
|
|
uintptr(unsafe.Pointer(&counterType)),
|
|
uintptr(unsafe.Pointer(&value)),
|
|
)
|
|
|
|
if ret == ERROR_SUCCESS {
|
|
loadMu.Lock()
|
|
GlobalLoadAverage.Update(value.DoubleValue)
|
|
loadMu.Unlock()
|
|
} else {
|
|
fmt.Printf("PdhGetFormattedCounterValue failed: %x\n", ret)
|
|
}
|
|
}
|
|
}
|
|
|
|
func GetLoadAverage() (LoadAverageInformation, error) {
|
|
startWorker()
|
|
loadMu.RLock()
|
|
defer loadMu.RUnlock()
|
|
return GlobalLoadAverage, nil
|
|
}
|