//go:build windows // Package collector 提供 Windows CPU 指标采集能力。 // Logan.Li package collector import ( "fmt" "runtime" "sync" "syscall" "unsafe" "ezops/agent/model" ) type filetime struct { LowDateTime uint32 HighDateTime uint32 } type cpuSample struct { total uint64 idle uint64 iowait uint64 } type CPUCollector struct { mu sync.Mutex prev *cpuSample } func NewCPUCollector() *CPUCollector { return &CPUCollector{} } func (c *CPUCollector) Collect() (model.CPUStat, error) { stat := model.CPUStat{CoreCount: runtime.NumCPU()} cur, err := readCPUSample() if err != nil { return stat, fmt.Errorf("读取 Windows CPU 采样失败: %w", err) } c.mu.Lock() defer c.mu.Unlock() if c.prev != nil { totalDelta := cur.total - c.prev.total idleDelta := cur.idle - c.prev.idle if totalDelta > 0 { stat.UsagePercent = float64(totalDelta-idleDelta) / float64(totalDelta) * 100.0 if stat.UsagePercent < 0 { stat.UsagePercent = 0 } } } c.prev = &cur return stat, nil } func readCPUSample() (cpuSample, error) { var idle, kernel, user filetime proc := syscall.NewLazyDLL("kernel32.dll").NewProc("GetSystemTimes") ret, _, err := proc.Call( uintptr(unsafe.Pointer(&idle)), uintptr(unsafe.Pointer(&kernel)), uintptr(unsafe.Pointer(&user)), ) if ret == 0 { return cpuSample{}, err } idleTicks := filetimeToUint64(idle) kernelTicks := filetimeToUint64(kernel) userTicks := filetimeToUint64(user) return cpuSample{total: kernelTicks + userTicks, idle: idleTicks}, nil } func filetimeToUint64(ft filetime) uint64 { return uint64(ft.HighDateTime)<<32 | uint64(ft.LowDateTime) }