mirror of
https://github.com/tw93/Mole.git
synced 2026-02-11 22:53:59 +00:00
Reconstruct the structure of go
This commit is contained in:
131
cmd/status/metrics_gpu.go
Normal file
131
cmd/status/metrics_gpu.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
systemProfilerTimeout = 4 * time.Second
|
||||
macGPUInfoTTL = 10 * time.Minute
|
||||
)
|
||||
|
||||
func (c *Collector) collectGPU(now time.Time) ([]GPUStatus, error) {
|
||||
if runtime.GOOS == "darwin" {
|
||||
if len(c.cachedGPU) > 0 && !c.lastGPUAt.IsZero() && now.Sub(c.lastGPUAt) < macGPUInfoTTL {
|
||||
return c.cachedGPU, nil
|
||||
}
|
||||
if gpus, err := readMacGPUInfo(); err == nil && len(gpus) > 0 {
|
||||
c.cachedGPU = gpus
|
||||
c.lastGPUAt = now
|
||||
return gpus, nil
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 600*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
if !commandExists("nvidia-smi") {
|
||||
return []GPUStatus{{
|
||||
Name: "No GPU metrics available",
|
||||
Note: "Install nvidia-smi or use platform-specific metrics",
|
||||
}}, nil
|
||||
}
|
||||
|
||||
out, err := runCmd(ctx, "nvidia-smi", "--query-gpu=utilization.gpu,memory.used,memory.total,name", "--format=csv,noheader,nounits")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines := strings.Split(strings.TrimSpace(out), "\n")
|
||||
var gpus []GPUStatus
|
||||
for _, line := range lines {
|
||||
fields := strings.Split(line, ",")
|
||||
if len(fields) < 4 {
|
||||
continue
|
||||
}
|
||||
util, _ := strconv.ParseFloat(strings.TrimSpace(fields[0]), 64)
|
||||
memUsed, _ := strconv.ParseFloat(strings.TrimSpace(fields[1]), 64)
|
||||
memTotal, _ := strconv.ParseFloat(strings.TrimSpace(fields[2]), 64)
|
||||
name := strings.TrimSpace(fields[3])
|
||||
|
||||
gpus = append(gpus, GPUStatus{
|
||||
Name: name,
|
||||
Usage: util,
|
||||
MemoryUsed: memUsed,
|
||||
MemoryTotal: memTotal,
|
||||
})
|
||||
}
|
||||
|
||||
if len(gpus) == 0 {
|
||||
return []GPUStatus{{
|
||||
Name: "GPU read failed",
|
||||
Note: "Verify nvidia-smi availability",
|
||||
}}, nil
|
||||
}
|
||||
|
||||
return gpus, nil
|
||||
}
|
||||
|
||||
func readMacGPUInfo() ([]GPUStatus, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), systemProfilerTimeout)
|
||||
defer cancel()
|
||||
|
||||
if !commandExists("system_profiler") {
|
||||
return nil, errors.New("system_profiler unavailable")
|
||||
}
|
||||
|
||||
out, err := runCmd(ctx, "system_profiler", "-json", "SPDisplaysDataType")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var data struct {
|
||||
Displays []struct {
|
||||
Name string `json:"_name"`
|
||||
VRAM string `json:"spdisplays_vram"`
|
||||
Vendor string `json:"spdisplays_vendor"`
|
||||
Metal string `json:"spdisplays_metal"`
|
||||
} `json:"SPDisplaysDataType"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(out), &data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var gpus []GPUStatus
|
||||
for _, d := range data.Displays {
|
||||
if d.Name == "" {
|
||||
continue
|
||||
}
|
||||
noteParts := []string{}
|
||||
if d.VRAM != "" {
|
||||
noteParts = append(noteParts, "VRAM "+d.VRAM)
|
||||
}
|
||||
if d.Metal != "" {
|
||||
noteParts = append(noteParts, d.Metal)
|
||||
}
|
||||
if d.Vendor != "" {
|
||||
noteParts = append(noteParts, d.Vendor)
|
||||
}
|
||||
note := strings.Join(noteParts, " · ")
|
||||
gpus = append(gpus, GPUStatus{
|
||||
Name: d.Name,
|
||||
Usage: -1,
|
||||
Note: note,
|
||||
})
|
||||
}
|
||||
|
||||
if len(gpus) == 0 {
|
||||
return []GPUStatus{{
|
||||
Name: "GPU info unavailable",
|
||||
Note: "Unable to parse system_profiler output",
|
||||
}}, nil
|
||||
}
|
||||
|
||||
return gpus, nil
|
||||
}
|
||||
Reference in New Issue
Block a user