mirror of
https://github.com/tw93/Mole.git
synced 2026-02-12 19:15:13 +00:00
Enhance CPU/GPU display for Apple Silicon
- Show all CPU cores instead of top 3 busiest - Add P-CPU/E-CPU core grouping (Performance/Efficiency) - Display GPU core count from system_profiler - Add GPU usage meter via powermetrics (requires sudo) - Show hint to run with sudo for GPU metrics Tested on M2 Pro (6P + 4E cores, 16 GPU cores)
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -13,17 +14,29 @@ import (
|
||||
const (
|
||||
systemProfilerTimeout = 4 * time.Second
|
||||
macGPUInfoTTL = 10 * time.Minute
|
||||
powermetricsTimeout = 2 * time.Second
|
||||
)
|
||||
|
||||
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
|
||||
// Get static GPU info (cached for 10 min)
|
||||
if len(c.cachedGPU) == 0 || c.lastGPUAt.IsZero() || now.Sub(c.lastGPUAt) >= macGPUInfoTTL {
|
||||
if gpus, err := readMacGPUInfo(); err == nil && len(gpus) > 0 {
|
||||
c.cachedGPU = gpus
|
||||
c.lastGPUAt = now
|
||||
}
|
||||
}
|
||||
if gpus, err := readMacGPUInfo(); err == nil && len(gpus) > 0 {
|
||||
c.cachedGPU = gpus
|
||||
c.lastGPUAt = now
|
||||
return gpus, nil
|
||||
|
||||
// Get real-time GPU usage
|
||||
if len(c.cachedGPU) > 0 {
|
||||
usage := getMacGPUUsage()
|
||||
result := make([]GPUStatus, len(c.cachedGPU))
|
||||
copy(result, c.cachedGPU)
|
||||
// Apply usage to first GPU (Apple Silicon has one integrated GPU)
|
||||
if len(result) > 0 {
|
||||
result[0].Usage = usage
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +104,7 @@ func readMacGPUInfo() ([]GPUStatus, error) {
|
||||
VRAM string `json:"spdisplays_vram"`
|
||||
Vendor string `json:"spdisplays_vendor"`
|
||||
Metal string `json:"spdisplays_metal"`
|
||||
Cores string `json:"sppci_cores"`
|
||||
} `json:"SPDisplaysDataType"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(out), &data); err != nil {
|
||||
@@ -113,10 +127,12 @@ func readMacGPUInfo() ([]GPUStatus, error) {
|
||||
noteParts = append(noteParts, d.Vendor)
|
||||
}
|
||||
note := strings.Join(noteParts, " · ")
|
||||
coreCount, _ := strconv.Atoi(d.Cores)
|
||||
gpus = append(gpus, GPUStatus{
|
||||
Name: d.Name,
|
||||
Usage: -1,
|
||||
Note: note,
|
||||
Name: d.Name,
|
||||
Usage: -1, // Will be updated with real-time data
|
||||
CoreCount: coreCount,
|
||||
Note: note,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -129,3 +145,38 @@ func readMacGPUInfo() ([]GPUStatus, error) {
|
||||
|
||||
return gpus, nil
|
||||
}
|
||||
|
||||
// getMacGPUUsage gets GPU active residency from powermetrics.
|
||||
// Returns -1 if unavailable (e.g., not running as root).
|
||||
func getMacGPUUsage() float64 {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), powermetricsTimeout)
|
||||
defer cancel()
|
||||
|
||||
// powermetrics requires root, but we try anyway - some systems may have it enabled
|
||||
out, err := runCmd(ctx, "powermetrics", "--samplers", "gpu_power", "-i", "500", "-n", "1")
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
// Parse "GPU HW active residency: X.XX%"
|
||||
re := regexp.MustCompile(`GPU HW active residency:\s+([\d.]+)%`)
|
||||
matches := re.FindStringSubmatch(out)
|
||||
if len(matches) >= 2 {
|
||||
usage, err := strconv.ParseFloat(matches[1], 64)
|
||||
if err == nil {
|
||||
return usage
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: parse "GPU idle residency: X.XX%" and calculate active
|
||||
reIdle := regexp.MustCompile(`GPU idle residency:\s+([\d.]+)%`)
|
||||
matchesIdle := reIdle.FindStringSubmatch(out)
|
||||
if len(matchesIdle) >= 2 {
|
||||
idle, err := strconv.ParseFloat(matchesIdle[1], 64)
|
||||
if err == nil {
|
||||
return 100.0 - idle
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user