初始化提交
This commit is contained in:
182
mengyamonitor-backend/cpu.go
Normal file
182
mengyamonitor-backend/cpu.go
Normal file
@@ -0,0 +1,182 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user