You need to sign in or sign up before continuing.
Commit fbb93034 authored by liming6's avatar liming6
Browse files

feature 完成表格部分

parent 687d3e07
...@@ -156,3 +156,14 @@ func UpdateDCUInfo(full bool) { ...@@ -156,3 +156,14 @@ func UpdateDCUInfo(full bool) {
d.PwrMode = v.PwrMode d.PwrMode = v.PwrMode
} }
} }
func GetDCUInfo() map[int]DCUInfo {
result := make(map[int]DCUInfo)
MapIdDCU.Range(func(key, value any) bool {
id := key.(int)
val := value.(*DCUInfo)
result[id] = *val
return true
})
return result
}
...@@ -8,8 +8,22 @@ import ( ...@@ -8,8 +8,22 @@ import (
func TestUpdateDCUInfo(t *testing.T) { func TestUpdateDCUInfo(t *testing.T) {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
start := time.Now() start := time.Now()
UpdateDCUInfo(true) UpdateDCUInfo(false)
end := time.Now() end := time.Now()
t.Logf("%d ms", end.Sub(start).Milliseconds()) t.Logf("%d ms", end.Sub(start).Milliseconds())
} }
} }
func TestGetDCUInfo(t *testing.T) {
UpdateDCUInfo(true)
info := GetDCUInfo()
t.Logf("%+v", info)
for i := range 10 {
time.Sleep(time.Second)
start := time.Now()
UpdateDCUInfo(false)
info = GetDCUInfo()
tt := time.Since(start).Milliseconds()
t.Logf("%d|%d : %+v", i, tt, info)
}
}
package tui package tui
import ( import (
"get-container/gpu" "fmt"
"get-container/cmd/dcutop/backend"
"maps"
"strconv"
"strings"
"github.com/charmbracelet/bubbles/progress"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
) )
type ModelDCUInfo struct { type ModelDCUInfo struct {
DCUNum int // dcu数量 DCUNum int // dcu数量
width, height int // 终端的尺寸 width, height int // 终端的尺寸
DCUStaticInfo []gpu.SMIAllOutput info map[int]backend.DCUInfo // dcu相关信息
DCURunningInfo []gpu.DCURunningInfo pro progress.Model // 进度条
proWidth int // 进度条宽度
} }
const (
TopLine = `╞═══════════════════════════════╪══════════════════════╪══════════════════════╪`
MiddleLine = `├───────────────────────────────┼──────────────────────┼──────────────────────┼`
BottomLine = `╞═══════════════════════════════╧══════════════════════╧══════════════════════╪`
OtherWidth = 8
StaticWidth = 87 // 固定表格的宽度
ProgressMaxWidth = 105 // 进度条最大宽度
ProgressMinWidth = 15 // 进度条最小宽度
)
func (m *ModelDCUInfo) Init() tea.Cmd { func (m *ModelDCUInfo) Init() tea.Cmd {
if m.width < StaticWidth+ProgressMinWidth {
return tea.Quit
}
m.proWidth = ProgressMinWidth
if m.width > StaticWidth+ProgressMaxWidth {
m.proWidth = ProgressMaxWidth
} else {
m.proWidth = m.width - StaticWidth
}
m.pro = progress.New(progress.WithDefaultGradient(), progress.WithWidth(m.proWidth))
return nil return nil
} }
func (m *ModelDCUInfo) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (m *ModelDCUInfo) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := inputMsg.(type) {
case *ModelMsg:
clear(m.info)
maps.Copy(m.info, msg.DCUInfo)
return m, nil
}
return m, nil return m, nil
} }
func (m *ModelDCUInfo) View() string { func (m *ModelDCUInfo) View() string {
return "" lineWidth := 0
l := len(m.info)
strBuilder := strings.Builder{}
infos := make([]string, l)
for i := range l {
ii := m.info[i]
strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(strconv.Itoa(ii.Id), 4, lipgloss.Left))
strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(ii.Name, 6, lipgloss.Left))
strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(ii.PerformanceLevel, 17, lipgloss.Right))
strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(ii.BusId, 13, lipgloss.Left))
strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr("Off", 6, lipgloss.Right))
strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte(' ')
if ii.Mig {
strBuilder.WriteString(FormatStr("On", 16, lipgloss.Left))
} else {
strBuilder.WriteString(FormatStr("Off", 16, lipgloss.Left))
}
strBuilder.WriteByte(' ')
if ii.Ecc {
strBuilder.WriteString(FormatStr("On", 3, lipgloss.Right))
} else {
strBuilder.WriteString(FormatStr("Off", 3, lipgloss.Right))
}
strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left)
strBuilder.WriteString(" DCU: ")
strBuilder.WriteString(m.pro.ViewAs(float64(ii.DCUUTil) / 100))
strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte('\n')
strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(ii.Fan, 4, lipgloss.Left))
strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(fmt.Sprintf("%.1fC", ii.Temp), 6, lipgloss.Left))
strBuilder.WriteByte(' ')
// 18
strBuilder.WriteString(FormatStr(fmt.Sprintf("%.1fW / %.1fW", ii.PwrAvg, ii.PwrCap), 17, lipgloss.Right))
strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte(' ')
// 20
strBuilder.WriteString(FormatStr(fmt.Sprintf("%dMiB / %dMiB", ii.MemUsed, ii.MemTotal), 20, lipgloss.Right))
strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(fmt.Sprintf("%.1f%%", ii.DCUUTil), 6, lipgloss.Left))
strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(ii.PwrMode, 13, lipgloss.Right))
strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left)
strBuilder.WriteString(" Mem: ")
strBuilder.WriteString(m.pro.ViewAs(float64(ii.MemUsedPerent) / 100))
strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left)
infos[i] = strBuilder.String()
strBuilder.Reset()
}
if len(infos) > 0 {
lineWidth = lipgloss.Width(infos[0])
}
subLen := lineWidth - StaticWidth + OtherWidth - 1
if subLen <= 0 {
subLen = 0
}
top := TopLine + strings.Repeat("═", subLen) + "╕\n"
middle := "\n" + MiddleLine + strings.Repeat("─", subLen) + "┤\n"
bottom := "\n" + BottomLine + strings.Repeat("═", subLen) + "╡\n"
return top + strings.Join(infos, middle) + bottom
} }
...@@ -23,12 +23,6 @@ func (mh *ModelHeader) Init() tea.Cmd { ...@@ -23,12 +23,6 @@ func (mh *ModelHeader) Init() tea.Cmd {
func (mh *ModelHeader) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { func (mh *ModelHeader) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := inputMsg.(type) { switch msg := inputMsg.(type) {
case ModelMsg:
mh.t = msg.t
mh.DCUTopVersion = msg.MyVersion
mh.DriverVersion = msg.Version.DriverVersion
mh.SMIVersion = msg.Version.SMIVersion
return mh, nil
case *ModelMsg: case *ModelMsg:
mh.t = msg.t mh.t = msg.t
mh.DCUTopVersion = msg.MyVersion mh.DCUTopVersion = msg.MyVersion
...@@ -42,8 +36,8 @@ func (mh *ModelHeader) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { ...@@ -42,8 +36,8 @@ func (mh *ModelHeader) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
const ( const (
Title = ` Title = `
├───────────────────────────────┬──────────────────────┬──────────────────────┤ ├───────────────────────────────┬──────────────────────┬──────────────────────┤
│ DCU Name Performance Level│ Bus-Id DisP.A │ MIG M. ECC │ │ DCU Name Performance Level │ Bus-Id DisP.A │ MIG M. ECC │
│ Fan Temp Pwr:Usage/Cap│ Memory-Usage │ DCU-Util PowerMode │ │ Fan Temp Pwr:Usage/Cap │ Memory-Usage │ DCU-Util PowerMode │
` `
) )
......
package tui package tui
import ( import (
"get-container/cmd/dcutop/backend"
"get-container/gpu" "get-container/gpu"
"time" "time"
...@@ -14,12 +15,11 @@ const ( ...@@ -14,12 +15,11 @@ const (
// ModelMsg 模型信息,在父组件和各个子组件间共享信息 // ModelMsg 模型信息,在父组件和各个子组件间共享信息
type ModelMsg struct { type ModelMsg struct {
t time.Time // 当前时间 t time.Time // 当前时间
index uint64 // update次数 index uint64 // update次数
Version *gpu.HYVersionInfo // gpu版本相关信息 Version *gpu.HYVersionInfo // gpu版本相关信息
MyVersion string MyVersion string
DCUInfo []gpu.DCUInfo // DCU全量信息 DCUInfo map[int]backend.DCUInfo // DCU全量信息
DCURunningInfo []gpu.DCURunningInfo // DCU运行时信息
// DCUPidInfo []gpu.DCUPidInfo // 使用dcu的进程信息 // DCUPidInfo []gpu.DCUPidInfo // 使用dcu的进程信息
} }
...@@ -41,7 +41,7 @@ func NewModelMain(width, height int) ModelMain { ...@@ -41,7 +41,7 @@ func NewModelMain(width, height int) ModelMain {
result.width = width result.width = width
result.height = height result.height = height
result.Header = &ModelHeader{} result.Header = &ModelHeader{}
result.DCUInfo = &ModelDCUInfo{width: width, height: height} result.DCUInfo = &ModelDCUInfo{width: width, height: height, info: make(map[int]backend.DCUInfo)}
return result return result
} }
...@@ -59,17 +59,21 @@ func sendMsgCmd(modelMsg *ModelMsg) tea.Cmd { ...@@ -59,17 +59,21 @@ func sendMsgCmd(modelMsg *ModelMsg) tea.Cmd {
// Init 初始化信息 // Init 初始化信息
func (m *ModelMain) Init() tea.Cmd { func (m *ModelMain) Init() tea.Cmd {
modelMsg := &ModelMsg{} modelMsg := ModelMsg{}
if err := initModelInfo(modelMsg); err != nil { if err := initModelInfo(&modelMsg); err != nil {
return tea.Quit return tea.Quit
} }
cmds := make([]tea.Cmd, 0) cmds := make([]tea.Cmd, 0)
if c := m.Header.Init(); c != nil { if c := m.Header.Init(); c != nil {
cmds = append(cmds, c) cmds = append(cmds, c)
} }
m.modelMsg = modelMsg m.DCUInfo.DCUNum = len(modelMsg.DCUInfo)
if c := m.DCUInfo.Init(); c != nil {
cmds = append(cmds, c)
}
m.modelMsg = &modelMsg
// 将调用初始化方法 // 将调用初始化方法
cmds = append(cmds, tickCmd(), sendMsgCmd(modelMsg)) cmds = append(cmds, tickCmd(), sendMsgCmd(&modelMsg))
return tea.Batch(cmds...) return tea.Batch(cmds...)
} }
...@@ -85,15 +89,23 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { ...@@ -85,15 +89,23 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
updateModelInfo(m.modelMsg, m.index, time.Time(msg)) updateModelInfo(m.modelMsg, m.index, time.Time(msg))
cmds := make([]tea.Cmd, 0) cmds := make([]tea.Cmd, 0)
header, cmdHeader := m.Header.Update(m.modelMsg) header, cmdHeader := m.Header.Update(m.modelMsg)
dcuInfo, dcuHeader := m.DCUInfo.Update(m.modelMsg)
m.Header = header.(*ModelHeader) m.Header = header.(*ModelHeader)
cmds = append(cmds, cmdHeader, tickCmd()) m.DCUInfo = dcuInfo.(*ModelDCUInfo)
cmds = append(cmds, cmdHeader, dcuHeader, tickCmd())
return m, tea.Batch(cmds...) return m, tea.Batch(cmds...)
case ModelMsg: // 初始化
header, _ := m.Header.Update(m.modelMsg)
dcuInfo, _ := m.DCUInfo.Update(m.modelMsg)
m.Header = header.(*ModelHeader)
m.DCUInfo = dcuInfo.(*ModelDCUInfo)
return m, nil
} }
return m, nil return m, nil
} }
func (m *ModelMain) View() string { func (m *ModelMain) View() string {
return m.Header.View() return m.Header.View() + m.DCUInfo.View()
} }
// type ModelDCUInfo struct{} // type ModelDCUInfo struct{}
...@@ -125,6 +137,12 @@ func initModelInfo(model *ModelMsg) error { ...@@ -125,6 +137,12 @@ func initModelInfo(model *ModelMsg) error {
return err return err
} }
model.Version = ver model.Version = ver
if model.index%20 == 0 {
backend.UpdateDCUInfo(true)
} else {
backend.UpdateDCUInfo(false)
}
model.DCUInfo = backend.GetDCUInfo()
return nil return nil
} }
...@@ -132,4 +150,10 @@ func initModelInfo(model *ModelMsg) error { ...@@ -132,4 +150,10 @@ func initModelInfo(model *ModelMsg) error {
func updateModelInfo(modelMsg *ModelMsg, index uint64, t time.Time) { func updateModelInfo(modelMsg *ModelMsg, index uint64, t time.Time) {
modelMsg.index = index modelMsg.index = index
modelMsg.t = t modelMsg.t = t
if modelMsg.index%20 == 0 {
backend.UpdateDCUInfo(true)
} else {
backend.UpdateDCUInfo(false)
}
modelMsg.DCUInfo = backend.GetDCUInfo()
} }
...@@ -2,15 +2,17 @@ package tui ...@@ -2,15 +2,17 @@ package tui
import ( import (
"fmt" "fmt"
"strings"
"testing" "testing"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
) )
const Border = `├───────────────────────────────┬──────────────────────┬──────────────────────┤ const S = `├───────────────────────────────┼──────────────────────┼──────────────────────┼
│ GPU Name Persistence-M│ Bus-Id Disp.A │ MIG M. Uncorr. ECC │ │ 2 BW200, manual │ 0000:5e:00.0 Off │ Off On │ DCU: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │`
│ Fan Temp Perf Pwr:Usage/Cap│ Memory-Usage │ GPU-Util Compute M. │`
func TestLine(t *testing.T) {
t.Logf("%d", lipgloss.Width(S))
}
func TestHeader(t *testing.T) { func TestHeader(t *testing.T) {
m := ModelHeader{} m := ModelHeader{}
...@@ -19,13 +21,6 @@ func TestHeader(t *testing.T) { ...@@ -19,13 +21,6 @@ func TestHeader(t *testing.T) {
fmt.Println(m.View()) fmt.Println(m.View())
} }
func TestBorder(t *testing.T) {
lines := strings.Split(Border, "\n")
for _, i := range lines {
t.Logf("%d", lipgloss.Width(i))
}
}
func TestAis(t *testing.T) { func TestAis(t *testing.T) {
for i := 10; i < 180; i++ { for i := 10; i < 180; i++ {
str := genXAxis(i) str := genXAxis(i)
...@@ -35,3 +30,19 @@ func TestAis(t *testing.T) { ...@@ -35,3 +30,19 @@ func TestAis(t *testing.T) {
fmt.Println(str) fmt.Println(str)
} }
} }
func TestFormatStr(t *testing.T) {
str := lipgloss.NewStyle().Foreground(lipgloss.Color("#2b95ffff")).SetString("hello world!").String()
t.Logf("|%s|", FormatStr(str, 5, lipgloss.Left))
t.Logf("|%s|", FormatStr(str, 5, lipgloss.Right))
t.Logf("|%s|", FormatStr(str, 20, lipgloss.Left))
t.Logf("|%s|", FormatStr(str, 20, lipgloss.Right))
}
func TestModel(t *testing.T) {
m := NewModelMain(200, 100)
m.Init()
m.DCUInfo.Update(m.modelMsg)
str := m.View()
t.Log(str)
}
...@@ -128,3 +128,26 @@ func StackPosition(up, down string, vPos, hPos lipgloss.Position) string { ...@@ -128,3 +128,26 @@ func StackPosition(up, down string, vPos, hPos lipgloss.Position) string {
return "" return ""
} }
// FormatStr 格式化字符串,输出的字符串可视长度为length,hPos表示是左对齐还是右对齐
// str必须为单行字符串,没有\n
func FormatStr(str string, length int, hPos lipgloss.Position) string {
realLen := lipgloss.Width(str)
if realLen < length {
switch hPos {
case lipgloss.Left:
return str + strings.Repeat(" ", length-realLen)
case lipgloss.Right:
return strings.Repeat(" ", length-realLen) + str
}
} else if realLen > length {
// 需要截断
switch hPos {
case lipgloss.Left: // 左对齐
return ansi.Truncate(str, length, "")
case lipgloss.Right: // 右对齐
return ansi.TruncateLeft(str, realLen-length, "")
}
}
return str
}
...@@ -5,14 +5,15 @@ go 1.24.2 ...@@ -5,14 +5,15 @@ go 1.24.2
require ( require (
github.com/charmbracelet/bubbletea v1.3.10 github.com/charmbracelet/bubbletea v1.3.10
github.com/charmbracelet/lipgloss v1.1.0 github.com/charmbracelet/lipgloss v1.1.0
github.com/lrstanley/bubblezone v0.0.0-20240914071701-b48c55a5e78e
github.com/moby/moby/api v1.52.0-beta.2 github.com/moby/moby/api v1.52.0-beta.2
github.com/moby/moby/client v0.1.0-beta.2 github.com/moby/moby/client v0.1.0-beta.2
github.com/shirou/gopsutil/v4 v4.25.9 github.com/shirou/gopsutil/v4 v4.25.9
) )
require ( require (
github.com/charmbracelet/bubbles v0.20.0 // indirect github.com/charmbracelet/bubbles v0.20.0
github.com/lrstanley/bubblezone v0.0.0-20240914071701-b48c55a5e78e // indirect github.com/charmbracelet/harmonica v0.2.0 // indirect
) )
require ( require (
...@@ -21,9 +22,9 @@ require ( ...@@ -21,9 +22,9 @@ require (
github.com/NimbleMarkets/ntcharts v0.3.1 github.com/NimbleMarkets/ntcharts v0.3.1
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
github.com/charmbracelet/x/ansi v0.10.1 // indirect github.com/charmbracelet/x/ansi v0.10.1
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect github.com/charmbracelet/x/term v0.2.1
github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/distribution/reference v0.6.0 // indirect github.com/distribution/reference v0.6.0 // indirect
......
...@@ -51,7 +51,7 @@ var ( ...@@ -51,7 +51,7 @@ var (
RePCIeRelay = regexp.MustCompile(`(?mi)^PCIe\s*Replay\s*Count\s*:\s*([0-9]*)$`) RePCIeRelay = regexp.MustCompile(`(?mi)^PCIe\s*Replay\s*Count\s*:\s*([0-9]*)$`)
ReSerialNum = regexp.MustCompile(`(?mi)^Serial\s*Number\s*:\s*([0-9a-zA-Z]*)$`) ReSerialNum = regexp.MustCompile(`(?mi)^Serial\s*Number\s*:\s*([0-9a-zA-Z]*)$`)
ReVoltage = regexp.MustCompile(`(?mi)^Voltage\s*\((.*)\)\s*:\s*([0-9.]*)$`) ReVoltage = regexp.MustCompile(`(?mi)^Voltage\s*\((.*)\)\s*:\s*([0-9.]*)$`)
RePCIBus = regexp.MustCompile(`(?mi)^PCI\s*Bus\s*:\s*([0-9a-zA-Z.:]*)$`) RePCIBus = regexp.MustCompile(`(?mi)^PCI\s*Bus\s*:\s*([0-9a-zA-Z.:]*).*$`)
ReMECFWVersion = regexp.MustCompile(`(?mi)^MEC\s*Firmware\s*Version\s*:\s*([0-9.]*)$`) ReMECFWVersion = regexp.MustCompile(`(?mi)^MEC\s*Firmware\s*Version\s*:\s*([0-9.]*)$`)
ReMEC2FWVersion = regexp.MustCompile(`(?mi)^MEC2\s*Firmware\s*Version\s*:\s*([0-9.]*)$`) ReMEC2FWVersion = regexp.MustCompile(`(?mi)^MEC2\s*Firmware\s*Version\s*:\s*([0-9.]*)$`)
ReRLCFWVersion = regexp.MustCompile(`(?mi)^RLC\s*Firmware\s*Version\s*:\s*([0-9.]*)$`) ReRLCFWVersion = regexp.MustCompile(`(?mi)^RLC\s*Firmware\s*Version\s*:\s*([0-9.]*)$`)
...@@ -342,7 +342,7 @@ func parseSMIAllOutput(id int, str string) (*SMIAllOutput, error) { ...@@ -342,7 +342,7 @@ func parseSMIAllOutput(id int, str string) (*SMIAllOutput, error) {
result.Voltage = float32(p) result.Voltage = float32(p)
} }
} }
if s := regMatch(RePCIBus, str, 2); s != nil { if s := regMatch(RePCIBus, str, 1); s != nil {
result.PCIBus = s[0] result.PCIBus = s[0]
} }
if s := regMatch(ReMECFWVersion, str, 1); s != nil { if s := regMatch(ReMECFWVersion, str, 1); s != nil {
......
...@@ -291,5 +291,16 @@ func TestParseSMIAllOutput(t *testing.T) { ...@@ -291,5 +291,16 @@ func TestParseSMIAllOutput(t *testing.T) {
for _, i := range result { for _, i := range result {
t.Logf("%+v", *i) t.Logf("%+v", *i)
} }
}
func TestPCIBus(t *testing.T) {
f := RePCIBus.FindStringSubmatch("PCI Bus: 0000:9f:00.0 --> Socket id: 1")
for _, l := range f {
t.Logf("%s", l)
}
if s := regMatch(RePCIBus, "PCI Bus: 0000:9f:00.0 --> Socket id: 1", 1); s != nil {
t.Logf("%+v", s)
}
} }
2025-11-12 17:04:45 (Press h for help or q for quit)
╒═════════════════════════════════════════════════════════════════════════════╕
│ hytop: 1.0.0 Driver Version: 6.3.16-V1.1.0 SMI Version: 1.20.0 │
├───────────────────────────────┬──────────────────────┬──────────────────────┤
│ DCU Name Performance Level │ Bus-Id DisP.A │ MIG M. ECC │
│ Fan Temp Pwr:Usage/Cap │ Memory-Usage │ DCU-Util PowerMode │
╞═════════════════════════════════════════════════════════════════════════════╪
│ 0 BW200, manual │ 0000:49:00.0 Off │ Off On │ DCU: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
│ N/A 32.0C 132.0W / 800.0W │ 2MiB / 65520MiB │ 0.0% Normal │ Mem: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
├───────────────────────────────┼──────────────────────┼──────────────────────┼
│ 1 BW200, manual │ 0000:54:00.0 Off │ Off On │ DCU: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
│ N/A 32.0C 126.0W / 800.0W │ 2MiB / 65520MiB │ 0.0% Normal │ Mem: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
├───────────────────────────────┼──────────────────────┼──────────────────────┼
│ 2 BW200, manual │ 0000:5e:00.0 Off │ Off On │ DCU: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
│ N/A 33.0C 132.0W / 800.0W │ 2MiB / 65520MiB │ 0.0% Normal │ Mem: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
├───────────────────────────────┼──────────────────────┼──────────────────────┼
│ 3 BW200, manual │ 0000:67:00.0 Off │ Off On │ DCU: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
│ N/A 34.0C 133.0W / 800.0W │ 2MiB / 65520MiB │ 0.0% Normal │ Mem: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
├───────────────────────────────┼──────────────────────┼──────────────────────┼
│ 4 BW200, manual │ 0000:9c:00.0 Off │ Off On │ DCU: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
│ N/A 34.0C 134.0W / 800.0W │ 2MiB / 65520MiB │ 0.0% Normal │ Mem: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
├───────────────────────────────┼──────────────────────┼──────────────────────┼
│ 5 BW200, manual │ 0000:bc:00.0 Off │ Off On │ DCU: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
│ N/A 34.0C 133.0W / 800.0W │ 2MiB / 65520MiB │ 0.0% Normal │ Mem: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
├───────────────────────────────┼──────────────────────┼──────────────────────┼
│ 6 BW200, manual │ 0000:cd:00.0 Off │ Off On │ DCU: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
│ N/A 32.0C 132.0W / 800.0W │ 2MiB / 65520MiB │ 0.0% Normal │ Mem: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
├───────────────────────────────┼──────────────────────┼──────────────────────┼
│ 7 BW200, manual │ 0000:dd:00.0 Off │ Off On │ DCU: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
│ N/A 31.0C 128.0W / 800.0W │ 2MiB / 65520MiB │ 0.0% Normal │ Mem: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
╘═══════════════════════════════╧══════════════════════╧══════════════════════╧
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment