1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-04 17:24:45 +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:
bsisduck
2025-12-07 17:12:48 +01:00
parent e7fd73302d
commit 32ac98f06a
5 changed files with 157 additions and 35 deletions

View File

@@ -2,7 +2,6 @@ package main
import (
"fmt"
"sort"
"strconv"
"strings"
@@ -163,8 +162,8 @@ func buildCards(m MetricsSnapshot, _ int) []cardData {
renderProcessCard(m.TopProcesses),
renderNetworkCard(m.Network, m.Proxy),
}
// Only show GPU card if there are GPUs with usage data
if len(m.GPU) > 0 && m.GPU[0].Usage >= 0 {
// Only show GPU card if there are GPUs with usage data or core count
if len(m.GPU) > 0 && (m.GPU[0].Usage >= 0 || m.GPU[0].CoreCount > 0) {
cards = append(cards, renderGPUCard(m.GPU))
}
// Only show sensors if we have valid temperature readings
@@ -186,29 +185,36 @@ func hasSensorData(sensors []SensorReading) bool {
func renderCPUCard(cpu CPUStatus) cardData {
var lines []string
lines = append(lines, fmt.Sprintf("Total %s %5.1f%%", progressBar(cpu.Usage), cpu.Usage))
lines = append(lines, subtleStyle.Render(fmt.Sprintf("%.2f / %.2f / %.2f (%d cores)", cpu.Load1, cpu.Load5, cpu.Load15, cpu.LogicalCPU)))
// Show core topology info if available (Apple Silicon)
if cpu.PCoreCount > 0 && cpu.ECoreCount > 0 {
lines = append(lines, subtleStyle.Render(fmt.Sprintf("%.2f / %.2f / %.2f (%dP + %dE cores)",
cpu.Load1, cpu.Load5, cpu.Load15, cpu.PCoreCount, cpu.ECoreCount)))
} else {
lines = append(lines, subtleStyle.Render(fmt.Sprintf("%.2f / %.2f / %.2f (%d cores)",
cpu.Load1, cpu.Load5, cpu.Load15, cpu.LogicalCPU)))
}
if cpu.PerCoreEstimated {
lines = append(lines, subtleStyle.Render("Per-core data unavailable (using averaged load)"))
} else if len(cpu.PerCore) > 0 {
// Show top 3 busiest cores
type coreUsage struct {
idx int
val float64
}
var cores []coreUsage
for i, v := range cpu.PerCore {
cores = append(cores, coreUsage{i, v})
}
sort.Slice(cores, func(i, j int) bool { return cores[i].val > cores[j].val })
maxCores := 3
if len(cores) < maxCores {
maxCores = len(cores)
}
for i := 0; i < maxCores; i++ {
c := cores[i]
lines = append(lines, fmt.Sprintf("Core%-2d %s %5.1f%%", c.idx+1, progressBar(c.val), c.val))
// Apple Silicon: Group cores into P-CPU and E-CPU
if cpu.PCoreCount > 0 && cpu.ECoreCount > 0 {
// P-cores (Performance) come first
lines = append(lines, titleStyle.Render("P-CPU"))
for i := 0; i < cpu.PCoreCount && i < len(cpu.PerCore); i++ {
lines = append(lines, fmt.Sprintf("Core%-2d %s %5.1f%%", i+1, progressBar(cpu.PerCore[i]), cpu.PerCore[i]))
}
// E-cores (Efficiency) come after P-cores
lines = append(lines, titleStyle.Render("E-CPU"))
for i := cpu.PCoreCount; i < cpu.PCoreCount+cpu.ECoreCount && i < len(cpu.PerCore); i++ {
lines = append(lines, fmt.Sprintf("Core%-2d %s %5.1f%%", i+1, progressBar(cpu.PerCore[i]), cpu.PerCore[i]))
}
} else {
// Non-Apple Silicon: Show all cores without grouping
for i, v := range cpu.PerCore {
lines = append(lines, fmt.Sprintf("Core%-2d %s %5.1f%%", i+1, progressBar(v), v))
}
}
}
@@ -221,11 +227,19 @@ func renderGPUCard(gpus []GPUStatus) cardData {
lines = append(lines, subtleStyle.Render("No GPU detected"))
} else {
for _, g := range gpus {
name := shorten(g.Name, 12)
// Line 1: Usage bar (if available)
if g.Usage >= 0 {
lines = append(lines, fmt.Sprintf("%-12s %s %5.1f%%", name, progressBar(g.Usage), g.Usage))
} else {
lines = append(lines, name)
lines = append(lines, fmt.Sprintf("Total %s %5.1f%%", progressBar(g.Usage), g.Usage))
}
// Line 2: GPU name and core count
coreInfo := ""
if g.CoreCount > 0 {
coreInfo = fmt.Sprintf(" (%d cores)", g.CoreCount)
}
lines = append(lines, subtleStyle.Render(g.Name+coreInfo))
// Line 3: Hint for sudo if usage unavailable
if g.Usage < 0 {
lines = append(lines, subtleStyle.Render("Run with sudo for usage metrics"))
}
}
}