128 lines
3.1 KiB
Go
128 lines
3.1 KiB
Go
|
|
package main
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"os/exec"
|
|||
|
|
"strconv"
|
|||
|
|
"strings"
|
|||
|
|
"sync"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"github.com/shirou/gopsutil/v4/cpu"
|
|||
|
|
"github.com/shirou/gopsutil/v4/mem"
|
|||
|
|
gnet "github.com/shirou/gopsutil/v4/net"
|
|||
|
|
"view/platform"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// HostMetrics 本机总览快照(端口监控页轮询)。
|
|||
|
|
type HostMetrics struct {
|
|||
|
|
At string `json:"at"`
|
|||
|
|
CPUPercent float64 `json:"cpu"`
|
|||
|
|
MemUsedMB float64 `json:"memUsedMB"`
|
|||
|
|
MemTotalMB float64 `json:"memTotalMB"`
|
|||
|
|
MemPercent float64 `json:"memPercent"`
|
|||
|
|
GPUPercent float64 `json:"gpu"` // -1 表示不可用
|
|||
|
|
GPUMemUsedMB float64 `json:"gpuMemUsedMB"`
|
|||
|
|
GPUMemTotalMB float64 `json:"gpuMemTotalMB"`
|
|||
|
|
GPUName string `json:"gpuName"`
|
|||
|
|
NetRecvKBs float64 `json:"netRecvKBs"`
|
|||
|
|
NetSentKBs float64 `json:"netSentKBs"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var (
|
|||
|
|
hostNetMu sync.Mutex
|
|||
|
|
hostNetAt time.Time
|
|||
|
|
hostNetRecv uint64
|
|||
|
|
hostNetSent uint64
|
|||
|
|
hostNetInit bool
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// GetHostMetrics 采集 CPU / 内存 / 网卡吞吐;GPU 在有 nvidia-smi 时附带利用率。
|
|||
|
|
func (a *App) GetHostMetrics() (HostMetrics, error) {
|
|||
|
|
out := HostMetrics{At: time.Now().Format(time.RFC3339), GPUPercent: -1}
|
|||
|
|
|
|||
|
|
if percents, err := cpu.Percent(0, false); err == nil && len(percents) > 0 {
|
|||
|
|
out.CPUPercent = percents[0]
|
|||
|
|
if out.CPUPercent < 0 {
|
|||
|
|
out.CPUPercent = 0
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if vm, err := mem.VirtualMemory(); err == nil && vm != nil {
|
|||
|
|
out.MemUsedMB = float64(vm.Used) / 1024 / 1024
|
|||
|
|
out.MemTotalMB = float64(vm.Total) / 1024 / 1024
|
|||
|
|
out.MemPercent = vm.UsedPercent
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
recvKB, sentKB := sampleHostNet()
|
|||
|
|
out.NetRecvKBs = recvKB
|
|||
|
|
out.NetSentKBs = sentKB
|
|||
|
|
|
|||
|
|
fillGPU(&out)
|
|||
|
|
return out, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func sampleHostNet() (recvKBs, sentKBs float64) {
|
|||
|
|
counters, err := gnet.IOCounters(false)
|
|||
|
|
if err != nil || len(counters) == 0 {
|
|||
|
|
return 0, 0
|
|||
|
|
}
|
|||
|
|
c := counters[0]
|
|||
|
|
now := time.Now()
|
|||
|
|
|
|||
|
|
hostNetMu.Lock()
|
|||
|
|
defer hostNetMu.Unlock()
|
|||
|
|
if !hostNetInit {
|
|||
|
|
hostNetInit = true
|
|||
|
|
hostNetAt = now
|
|||
|
|
hostNetRecv = c.BytesRecv
|
|||
|
|
hostNetSent = c.BytesSent
|
|||
|
|
return 0, 0
|
|||
|
|
}
|
|||
|
|
wall := now.Sub(hostNetAt).Seconds()
|
|||
|
|
if wall <= 0 {
|
|||
|
|
return 0, 0
|
|||
|
|
}
|
|||
|
|
recvKBs = float64(c.BytesRecv-hostNetRecv) / 1024 / wall
|
|||
|
|
sentKBs = float64(c.BytesSent-hostNetSent) / 1024 / wall
|
|||
|
|
if recvKBs < 0 {
|
|||
|
|
recvKBs = 0
|
|||
|
|
}
|
|||
|
|
if sentKBs < 0 {
|
|||
|
|
sentKBs = 0
|
|||
|
|
}
|
|||
|
|
hostNetAt = now
|
|||
|
|
hostNetRecv = c.BytesRecv
|
|||
|
|
hostNetSent = c.BytesSent
|
|||
|
|
return recvKBs, sentKBs
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// fillGPU 优先 nvidia-smi;失败则保持 gpu=-1。无窗口执行,避免端口监控轮询闪 cmd。
|
|||
|
|
func fillGPU(out *HostMetrics) {
|
|||
|
|
cmd := exec.Command("nvidia-smi",
|
|||
|
|
"--query-gpu=name,utilization.gpu,memory.used,memory.total",
|
|||
|
|
"--format=csv,noheader,nounits")
|
|||
|
|
platform.ConfigureHidden(cmd)
|
|||
|
|
raw, err := cmd.Output()
|
|||
|
|
if err != nil {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
line := strings.TrimSpace(strings.Split(string(raw), "\n")[0])
|
|||
|
|
if line == "" {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
parts := strings.Split(line, ",")
|
|||
|
|
if len(parts) < 4 {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
out.GPUName = strings.TrimSpace(parts[0])
|
|||
|
|
if v, e := strconv.ParseFloat(strings.TrimSpace(parts[1]), 64); e == nil {
|
|||
|
|
out.GPUPercent = v
|
|||
|
|
}
|
|||
|
|
if v, e := strconv.ParseFloat(strings.TrimSpace(parts[2]), 64); e == nil {
|
|||
|
|
out.GPUMemUsedMB = v
|
|||
|
|
}
|
|||
|
|
if v, e := strconv.ParseFloat(strings.TrimSpace(parts[3]), 64); e == nil {
|
|||
|
|
out.GPUMemTotalMB = v
|
|||
|
|
}
|
|||
|
|
}
|