Files
2025-12-14 15:25:31 +08:00

183 lines
3.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"bufio"
"errors"
"os"
"strconv"
"strings"
"time"
)
// readCPUUsage 读取CPU整体使用率
func readCPUUsage() (float64, error) {
idle1, total1, err := readCPUTicks()
if err != nil {
return 0, err
}
time.Sleep(250 * time.Millisecond)
idle2, total2, err := readCPUTicks()
if err != nil {
return 0, err
}
if total2 == total1 {
return 0, errors.New("cpu totals unchanged")
}
idleDelta := float64(idle2 - idle1)
totalDelta := float64(total2 - total1)
usage := (1.0 - idleDelta/totalDelta) * 100
if usage < 0 {
usage = 0
}
return usage, nil
}
// readCPUTicks 读取CPU的idle和total ticks
func readCPUTicks() (idle, total uint64, err error) {
f, err := os.Open("/proc/stat")
if err != nil {
return 0, 0, err
}
defer f.Close()
scanner := bufio.NewScanner(f)
if !scanner.Scan() {
return 0, 0, errors.New("failed to scan /proc/stat")
}
fields := strings.Fields(scanner.Text())
if len(fields) < 5 {
return 0, 0, errors.New("unexpected /proc/stat format")
}
// fields[0] is "cpu"
var vals []uint64
for _, f := range fields[1:] {
v, err := strconv.ParseUint(f, 10, 64)
if err != nil {
return 0, 0, err
}
vals = append(vals, v)
}
for _, v := range vals {
total += v
}
if len(vals) > 3 {
idle = vals[3] // idle time
// 注意:不包含 iowait因为 iowait 不算真正的空闲时间
// 如果系统有 iowait它会在 total 中,但不应该算作 idle
}
return idle, total, nil
}
// readPerCoreUsage 读取每个CPU核心的使用率
func readPerCoreUsage() []CoreUsage {
coreUsages := []CoreUsage{}
// 第一次读取
cores1 := readPerCoreTicks()
time.Sleep(100 * time.Millisecond) // 减少到100ms
// 第二次读取
cores2 := readPerCoreTicks()
for i := 0; i < len(cores1) && i < len(cores2); i++ {
idle1, total1 := cores1[i][0], cores1[i][1]
idle2, total2 := cores2[i][0], cores2[i][1]
if total2 == total1 {
continue
}
idleDelta := float64(idle2 - idle1)
totalDelta := float64(total2 - total1)
usage := (1.0 - idleDelta/totalDelta) * 100
if usage < 0 {
usage = 0
}
coreUsages = append(coreUsages, CoreUsage{
Core: i,
Percent: round(usage, 1),
})
}
return coreUsages
}
// readPerCoreTicks 读取每个CPU核心的ticks
func readPerCoreTicks() [][2]uint64 {
var result [][2]uint64
f, err := os.Open("/proc/stat")
if err != nil {
return result
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
if !strings.HasPrefix(line, "cpu") {
continue
}
if strings.HasPrefix(line, "cpu ") {
continue // 跳过总的cpu行
}
fields := strings.Fields(line)
if len(fields) < 5 {
continue
}
var vals []uint64
for _, f := range fields[1:] {
v, err := strconv.ParseUint(f, 10, 64)
if err != nil {
break
}
vals = append(vals, v)
}
if len(vals) < 5 {
continue
}
var total, idle uint64
for _, v := range vals {
total += v
}
idle = vals[3] // idle time only, not including iowait
result = append(result, [2]uint64{idle, total})
}
return result
}
// readCPUTemperature 读取CPU温度
func readCPUTemperature() float64 {
// 尝试从常见位置读取温度
paths := []string{
"/sys/class/thermal/thermal_zone0/temp",
"/sys/class/hwmon/hwmon0/temp1_input",
"/sys/class/hwmon/hwmon1/temp1_input",
}
for _, path := range paths {
if temp := readTempFromFile(path); temp > 0 {
return temp
}
}
return 0
}
// readLoadAverages 读取系统负载平均值
func readLoadAverages() []float64 {
line := readFirstLine("/proc/loadavg")
fields := strings.Fields(line)
res := make([]float64, 0, 3)
for i := 0; i < len(fields) && i < 3; i++ {
v, err := strconv.ParseFloat(fields[i], 64)
if err == nil {
res = append(res, v)
}
}
return res
}