Commit ed4a196f authored by liming6's avatar liming6
Browse files

feature 优化取数据流程,优化启动性能

parent d5f04510
...@@ -14,7 +14,7 @@ import ( ...@@ -14,7 +14,7 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/shirou/gopsutil/v4/process" "github.com/shirou/gopsutil/v3/process"
) )
var ( var (
...@@ -352,6 +352,44 @@ func (m *DCUInfoMap) GetDCUProcessInfo() map[int][]DCUProcessInfo { ...@@ -352,6 +352,44 @@ func (m *DCUInfoMap) GetDCUProcessInfo() map[int][]DCUProcessInfo {
return result return result
} }
// GetDCUProcessInfo2 返回值的key为dcu index
func (m *DCUInfoMap) GetDCUProcessInfo2() map[int][]DCUProcessInfo {
result := make(map[int][]DCUProcessInfo)
info, err := gpu.GetDCUPidInfo()
if err != nil {
return result
}
pids := make([]int32, 0)
for _, v := range info {
pids = append(pids, int32(v.Pid))
}
pinfo := getProcessInfo(pids)
for _, v := range info {
index := make([]int, 0)
for _, i := range v.HCUIndex {
ii, err := strconv.Atoi(i)
if err != nil {
continue
}
index = append(index, ii)
}
for _, i := range index {
l, have := result[i]
if !have {
result[i] = make([]DCUProcessInfo, 0)
l = result[i]
}
item := DCUProcessInfo{DCU: i}
item.Info = pinfo[int32(v.Pid)]
item.DCUMem = v.VRamUsed.HumanReadStr(1)
item.SDMA = v.SDMAUsed
l = append(l, item)
result[i] = l
}
}
return result
}
// durationStr 将时间段格式化为 小时:分钟:秒s的格式 // durationStr 将时间段格式化为 小时:分钟:秒s的格式
func durationStr(d time.Duration) string { func durationStr(d time.Duration) string {
h := int(math.Floor(d.Hours())) h := int(math.Floor(d.Hours()))
......
...@@ -2,8 +2,7 @@ package tui ...@@ -2,8 +2,7 @@ package tui
import ( import (
"fmt" "fmt"
"get-container/cmd/hytop/backend" "get-container/utils"
"maps"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
...@@ -15,10 +14,10 @@ import ( ...@@ -15,10 +14,10 @@ import (
) )
type ModelDCUInfo struct { type ModelDCUInfo struct {
parent *ModelMain pro progress.Model // 进度条
info map[int]backend.DCUInfo // dcu相关信息 proWidth int // 进度条宽度
pro progress.Model // 进度条 modMsg *ModelMsg
proWidth int // 进度条宽度 width, height int
} }
const ( const (
...@@ -35,20 +34,17 @@ var ( ...@@ -35,20 +34,17 @@ var (
ReDCUName = regexp.MustCompile(`(?i)^[A-Z0-9-_]*`) ReDCUName = regexp.MustCompile(`(?i)^[A-Z0-9-_]*`)
) )
func NewModelDCUInfo(m *ModelMain) *ModelDCUInfo { func NewModelDCUInfo(w, h int) *ModelDCUInfo {
return &ModelDCUInfo{ return &ModelDCUInfo{width: w, height: h}
parent: m,
info: make(map[int]backend.DCUInfo),
}
} }
func (m *ModelDCUInfo) Init() tea.Cmd { func (m *ModelDCUInfo) Init() tea.Cmd {
if m.parent.width < StaticWidth+ProgressMinWidth+OtherWidth { if m.width < StaticWidth+ProgressMinWidth+OtherWidth {
return tea.Quit return tea.Quit
} }
m.proWidth = ProgressMinWidth m.proWidth = ProgressMinWidth
if m.parent.width > StaticWidth+ProgressMinWidth+OtherWidth { if m.width > StaticWidth+ProgressMinWidth+OtherWidth {
m.proWidth = m.parent.width - OtherWidth - StaticWidth m.proWidth = m.width - OtherWidth - StaticWidth
} }
m.pro = progress.New(progress.WithColorProfile(termenv.TrueColor), progress.WithGradient("#0000ffff", "#ff0000ff"), progress.WithWidth(m.proWidth)) m.pro = progress.New(progress.WithColorProfile(termenv.TrueColor), progress.WithGradient("#0000ffff", "#ff0000ff"), progress.WithWidth(m.proWidth))
return nil return nil
...@@ -57,43 +53,61 @@ func (m *ModelDCUInfo) Init() tea.Cmd { ...@@ -57,43 +53,61 @@ func (m *ModelDCUInfo) Init() tea.Cmd {
func (m *ModelDCUInfo) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { func (m *ModelDCUInfo) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := inputMsg.(type) { switch msg := inputMsg.(type) {
case *ModelMsg: case *ModelMsg:
clear(m.info) m.modMsg = msg
maps.Copy(m.info, msg.DCUInfo) return m, nil
case tea.WindowSizeMsg:
m.height = msg.Height
m.width = msg.Width
return m, nil return m, nil
} }
return m, nil return m, nil
} }
func (m *ModelDCUInfo) View() string { func (m *ModelDCUInfo) View() string {
if m.modMsg == nil {
return ""
}
lineWidth := 0 lineWidth := 0
l := len(m.info) qmap, qlock := m.modMsg.DCUInfo.GetQuitInfo()
smap, slock := m.modMsg.DCUInfo.GetSlowInfo()
defer slock.Unlock()
defer qlock.Unlock()
conTime := 0
strBuilder := strings.Builder{} strBuilder := strings.Builder{}
infos := make([]string, l) infos := make([]string, 0)
for i := range l { for i := range 128 {
ii := m.info[i] qinfo, haveq := qmap[i]
sinfo, haves := smap[i]
if !(haveq || haves) {
conTime++
if conTime > 8 {
break
}
continue
}
strBuilder.WriteString(myBorder.Left) strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(strconv.Itoa(ii.Id), 4, lipgloss.Left)) strBuilder.WriteString(FormatStr(strconv.Itoa(qinfo.Id), 4, lipgloss.Left))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(ReDCUName.FindString(ii.Name), 8, lipgloss.Left)) strBuilder.WriteString(FormatStr(ReDCUName.FindString(qinfo.Name), 8, lipgloss.Left))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(ii.PerformanceLevel, 15, lipgloss.Right)) strBuilder.WriteString(FormatStr(qinfo.PerformanceLevel, 15, lipgloss.Right))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left) strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(ii.BusId, 13, lipgloss.Left)) strBuilder.WriteString(FormatStr(qinfo.BusId, 13, lipgloss.Left))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr("Off", 6, lipgloss.Right)) strBuilder.WriteString(FormatStr("Off", 6, lipgloss.Right))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left) strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
if ii.Mig { if sinfo.Mig.Load() {
strBuilder.WriteString(FormatStr("On", 16, lipgloss.Left)) strBuilder.WriteString(FormatStr("On", 16, lipgloss.Left))
} else { } else {
strBuilder.WriteString(FormatStr("Off", 16, lipgloss.Left)) strBuilder.WriteString(FormatStr("Off", 16, lipgloss.Left))
} }
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
if ii.Ecc { if sinfo.Ecc.Load() {
strBuilder.WriteString(FormatStr("On", 3, lipgloss.Right)) strBuilder.WriteString(FormatStr("On", 3, lipgloss.Right))
} else { } else {
strBuilder.WriteString(FormatStr("Off", 3, lipgloss.Right)) strBuilder.WriteString(FormatStr("Off", 3, lipgloss.Right))
...@@ -101,36 +115,36 @@ func (m *ModelDCUInfo) View() string { ...@@ -101,36 +115,36 @@ func (m *ModelDCUInfo) View() string {
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left) strBuilder.WriteString(myBorder.Left)
strBuilder.WriteString(" DCU: ") strBuilder.WriteString(" DCU: ")
strBuilder.WriteString(m.pro.ViewAs(float64(ii.DCUUTil) / 100)) strBuilder.WriteString(m.pro.ViewAs(float64(qinfo.DCUUTil / 100)))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left) strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte('\n') strBuilder.WriteByte('\n')
strBuilder.WriteString(myBorder.Left) strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(ii.Fan, 4, lipgloss.Left)) strBuilder.WriteString(FormatStr(qinfo.Fan, 4, lipgloss.Left))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(fmt.Sprintf("%.1fC", ii.Temp), 6, lipgloss.Left)) strBuilder.WriteString(FormatStr(fmt.Sprintf("%.1fC", qinfo.Temp), 6, lipgloss.Left))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
// 18 // 18
strBuilder.WriteString(FormatStr(fmt.Sprintf("%.1fW / %.1fW", ii.PwrAvg, ii.PwrCap), 17, lipgloss.Right)) strBuilder.WriteString(FormatStr(fmt.Sprintf("%.1fW / %.1fW", qinfo.PwrAvg, qinfo.PwrCap), 17, lipgloss.Right))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left) strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
// 20 // 20
strBuilder.WriteString(FormatStr(fmt.Sprintf("%dMiB / %dMiB", ii.MemUsed, ii.MemTotal), 20, lipgloss.Right)) strBuilder.WriteString(FormatStr(fmt.Sprintf("%dMiB / %dMiB", qinfo.MemUsed/uint64(utils.MiB), qinfo.MemTotal/uint64(utils.MiB)), 20, lipgloss.Right))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left) strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(fmt.Sprintf("%.1f%%", ii.DCUUTil), 6, lipgloss.Left)) strBuilder.WriteString(FormatStr(fmt.Sprintf("%.1f%%", qinfo.DCUUTil), 6, lipgloss.Left))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(ii.PwrMode, 13, lipgloss.Right)) strBuilder.WriteString(FormatStr(sinfo.PwrMode.Load().(string), 13, lipgloss.Right))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left) strBuilder.WriteString(myBorder.Left)
strBuilder.WriteString(" Mem: ") strBuilder.WriteString(" Mem: ")
strBuilder.WriteString(m.pro.ViewAs(float64(ii.MemUsedPerent) / 100)) strBuilder.WriteString(m.pro.ViewAs(float64(qinfo.MemUsed) / float64(qinfo.MemTotal)))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left) strBuilder.WriteString(myBorder.Left)
infos[i] = strBuilder.String() infos = append(infos, strBuilder.String())
strBuilder.Reset() strBuilder.Reset()
} }
if len(infos) > 0 { if len(infos) > 0 {
......
...@@ -10,17 +10,14 @@ import ( ...@@ -10,17 +10,14 @@ import (
) )
type ModelHeader struct { type ModelHeader struct {
parent *ModelMain
t time.Time t time.Time
DCUTopVersion string DCUTopVersion string
SMIVersion string SMIVersion string
DriverVersion string DriverVersion string
} }
func NewModelHeader(m *ModelMain) *ModelHeader { func NewModelHeader() *ModelHeader {
return &ModelHeader{ return &ModelHeader{}
parent: m,
}
} }
func (mh *ModelHeader) Init() tea.Cmd { func (mh *ModelHeader) Init() tea.Cmd {
......
...@@ -40,8 +40,8 @@ func NewModelMain(width, height int) ModelMain { ...@@ -40,8 +40,8 @@ func NewModelMain(width, height int) ModelMain {
result := ModelMain{} result := ModelMain{}
result.width = width result.width = width
result.height = height result.height = height
result.Header = NewModelHeader(&result) result.Header = NewModelHeader()
result.DCUInfo = NewModelDCUInfo(&result) result.DCUInfo = NewModelDCUInfo(width, height)
result.SysLoad = NewModelSysLoad(width) result.SysLoad = NewModelSysLoad(width)
result.ProcessInfo = NewModelProcessInfo(width) result.ProcessInfo = NewModelProcessInfo(width)
return result return result
...@@ -112,8 +112,16 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { ...@@ -112,8 +112,16 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
m.SysLoad = sysLoad.(*ModelSysLoad) m.SysLoad = sysLoad.(*ModelSysLoad)
m.ProcessInfo = pidinfo.(*ModelProcessInfo) m.ProcessInfo = pidinfo.(*ModelProcessInfo)
return m, nil return m, nil
case tea.WindowSizeMsg: case tea.WindowSizeMsg: // 窗口尺寸变化
m.width, m.height = msg.Width, msg.Height m.width, m.height = msg.Width, msg.Height
header, _ := m.Header.Update(msg)
dcuInfo, _ := m.DCUInfo.Update(msg)
sysLoad, _ := m.SysLoad.Update(msg)
pidinfo, _ := m.ProcessInfo.Update(msg)
m.Header = header.(*ModelHeader)
m.DCUInfo = dcuInfo.(*ModelDCUInfo)
m.SysLoad = sysLoad.(*ModelSysLoad)
m.ProcessInfo = pidinfo.(*ModelProcessInfo)
return m, nil return m, nil
} }
return m, nil return m, nil
...@@ -142,21 +150,38 @@ var myBorder = lipgloss.Border{ ...@@ -142,21 +150,38 @@ var myBorder = lipgloss.Border{
func initModelInfo(model *ModelMsg) error { func initModelInfo(model *ModelMsg) error {
model.t = time.Now() model.t = time.Now()
model.MyVersion = DCUTopVersion model.MyVersion = DCUTopVersion
if ver, err := gpu.GetHYVersionInfo(); err != nil { if ver, err := gpu.GetHYVersionInfo(); err != nil {
return err return err
} else { } else {
model.Version = ver model.Version = ver
} }
model.DCUInfo = backend.DCUSInfoMap
return err model.DCUPidInfo = backend.DCUSInfoMap.GetDCUProcessInfo2()
if sinfo, err := utils.GetSysInfo(); err != nil {
return err
} else {
model.systemInfo = sinfo
}
if err := model.DCUInfo.UpdateQuickInfo(); err != nil {
return err
}
if err := model.DCUInfo.UpdateSlowInfo(); err != nil {
return err
}
return nil
} }
// updateModelInfo 更新模型信息 // updateModelInfo 更新模型信息
func updateModelInfo(modelMsg *ModelMsg, t time.Time) { func updateModelInfo(modelMsg *ModelMsg, t time.Time) error {
modelMsg.t = t modelMsg.t = t
if sinfo, err := utils.GetSysInfo(); err != nil {
modelMsg.DCUInfo = backend.GetDCUInfo() return err
modelMsg.systemInfo, _ = utils.GetSysInfo() } else {
modelMsg.DCUPidInfo = backend.GetDCUProcessInfo() modelMsg.systemInfo = sinfo
}
modelMsg.DCUPidInfo = modelMsg.DCUInfo.GetDCUProcessInfo2()
if err := modelMsg.DCUInfo.UpdateQuickInfo(); err != nil {
return err
}
return nil
} }
...@@ -19,11 +19,12 @@ type ModelProcessInfo struct { ...@@ -19,11 +19,12 @@ type ModelProcessInfo struct {
Cache map[int][]backend.DCUProcessInfo Cache map[int][]backend.DCUProcessInfo
width int width int
style lipgloss.Style style lipgloss.Style
modMsg *ModelMsg
} }
const ( const (
Processes = " Processes:" Processes = " Processes:"
ModelProcessInfoTitle = " DCU PID USER DCU-MEM SDMA %CPU %MEM TIME Command" ModelProcessInfoTitle = " DCU PID USER DCU-MEM SDMA %CPU %MEM TIME Docker Command"
ModelProcessInfoNoPro = " No running processes found" ModelProcessInfoNoPro = " No running processes found"
) )
...@@ -72,9 +73,9 @@ func (m *ModelProcessInfo) View() string { ...@@ -72,9 +73,9 @@ func (m *ModelProcessInfo) View() string {
sb.WriteString(myBorder.Left) sb.WriteString(myBorder.Left)
sb.WriteString(FormatStr(fmt.Sprintf("%d", process.DCU), 4, lipgloss.Right)) sb.WriteString(FormatStr(fmt.Sprintf("%d", process.DCU), 4, lipgloss.Right))
sb.WriteByte(' ') sb.WriteByte(' ')
sb.WriteString(FormatStr(fmt.Sprintf("%d", process.Info.Pid), 6, lipgloss.Right)) sb.WriteString(FormatStr(fmt.Sprintf("%d", process.Info.Pid), 7, lipgloss.Right))
sb.WriteByte(' ') sb.WriteByte(' ')
sb.WriteString(FormatStr(process.Info.User, 9, lipgloss.Right)) sb.WriteString(FormatStr(process.Info.User, 8, lipgloss.Right))
sb.WriteByte(' ') sb.WriteByte(' ')
sb.WriteString(FormatStr(process.DCUMem, 8, lipgloss.Right)) sb.WriteString(FormatStr(process.DCUMem, 8, lipgloss.Right))
sb.WriteByte(' ') sb.WriteByte(' ')
...@@ -85,7 +86,13 @@ func (m *ModelProcessInfo) View() string { ...@@ -85,7 +86,13 @@ func (m *ModelProcessInfo) View() string {
sb.WriteString(FormatStr(fmt.Sprintf("%.1f", process.Info.Mem), 5, lipgloss.Right)) sb.WriteString(FormatStr(fmt.Sprintf("%.1f", process.Info.Mem), 5, lipgloss.Right))
sb.WriteByte(' ') sb.WriteByte(' ')
sb.WriteString(FormatStr(process.Info.Time, 9, lipgloss.Right)) sb.WriteString(FormatStr(process.Info.Time, 9, lipgloss.Right))
sb.WriteString(" ") sb.WriteByte(' ')
if process.Info.ContInfo != nil {
sb.WriteString(FormatStr(process.Info.ContInfo.Name, 20, lipgloss.Left))
} else {
sb.WriteString(FormatStr(" - ", 20, lipgloss.Right))
}
sb.WriteByte(' ')
w := m.width - lipgloss.Width(sb.String()) - 2 w := m.width - lipgloss.Width(sb.String()) - 2
tw := lipgloss.Width(process.Info.Cmd) tw := lipgloss.Width(process.Info.Cmd)
if w >= tw { if w >= tw {
...@@ -122,6 +129,8 @@ func (m *ModelProcessInfo) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { ...@@ -122,6 +129,8 @@ func (m *ModelProcessInfo) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
case *ModelMsg: case *ModelMsg:
clear(m.Cache) clear(m.Cache)
maps.Copy(m.Cache, msg.DCUPidInfo) maps.Copy(m.Cache, msg.DCUPidInfo)
m.modMsg = msg
return m, nil
} }
return m, nil return m, nil
} }
...@@ -2,11 +2,9 @@ package tui ...@@ -2,11 +2,9 @@ package tui
import ( import (
"fmt" "fmt"
"get-container/cmd/hytop/backend"
"get-container/cmd/hytop/tchart" "get-container/cmd/hytop/tchart"
"get-container/utils" "get-container/utils"
"image/color" "image/color"
"maps"
"strings" "strings"
"sync" "sync"
"time" "time"
...@@ -31,7 +29,6 @@ type ModelSysLoad struct { ...@@ -31,7 +29,6 @@ type ModelSysLoad struct {
SysCPU *MyTimeChart SysCPU *MyTimeChart
DCU *MyTimeChart DCU *MyTimeChart
DCUMem *MyTimeChart DCUMem *MyTimeChart
Cache map[int]backend.DCUInfo
SysInfo *linkedhashmap.Map[time.Time, SysLoadInfo] SysInfo *linkedhashmap.Map[time.Time, SysLoadInfo]
Keys *binaryheap.Heap[time.Time] Keys *binaryheap.Heap[time.Time]
current *SysLoadInfo current *SysLoadInfo
...@@ -58,7 +55,6 @@ type SysLoadInfo struct { ...@@ -58,7 +55,6 @@ type SysLoadInfo struct {
func NewModelSysLoad(width int) *ModelSysLoad { func NewModelSysLoad(width int) *ModelSysLoad {
result := ModelSysLoad{} result := ModelSysLoad{}
result.width = width result.width = width
result.Cache = make(map[int]backend.DCUInfo)
result.SysInfo = linkedhashmap.New[time.Time, SysLoadInfo]() result.SysInfo = linkedhashmap.New[time.Time, SysLoadInfo]()
result.Keys = binaryheap.NewWith(func(a, b time.Time) int { result.Keys = binaryheap.NewWith(func(a, b time.Time) int {
if a.After(b) { if a.After(b) {
...@@ -96,9 +92,6 @@ func (m *ModelSysLoad) Init() tea.Cmd { ...@@ -96,9 +92,6 @@ func (m *ModelSysLoad) Init() tea.Cmd {
if c := m.SysCPU.Init(); c != nil { if c := m.SysCPU.Init(); c != nil {
result = append(result, c) result = append(result, c)
} }
if len(result) > 0 {
return tea.Batch(result...)
}
sysInfo, _ := utils.GetSysInfo() sysInfo, _ := utils.GetSysInfo()
s := SysLoadInfo{} s := SysLoadInfo{}
s.Load1 = sysInfo.LoadAverage1 s.Load1 = sysInfo.LoadAverage1
...@@ -115,15 +108,44 @@ func (m *ModelSysLoad) Init() tea.Cmd { ...@@ -115,15 +108,44 @@ func (m *ModelSysLoad) Init() tea.Cmd {
s.DCUUsageAvg = 0 s.DCUUsageAvg = 0
s.DCUMemUsageAvg = 0 s.DCUMemUsageAvg = 0
m.current = &s m.current = &s
return nil return tea.Batch(result...)
}
func (m *ModelSysLoad) init() [6]time.Time {
var result [6]time.Time
result[0] = time.Now()
m.DCU.Init()
result[1] = time.Now()
m.DCUMem.Init()
result[2] = time.Now()
m.SysMem.Init()
result[3] = time.Now()
m.SysCPU.Init()
result[4] = time.Now()
sysInfo, _ := utils.GetSysInfo()
result[5] = time.Now()
s := SysLoadInfo{}
s.Load1 = sysInfo.LoadAverage1
s.Load5 = sysInfo.LoadAverage5
s.Load15 = sysInfo.LoadAverage15
s.MemTotal = sysInfo.MemTotal
s.MemUsed = sysInfo.MemUsage
s.SwapTotal = sysInfo.SwapTotal
s.SwapUsed = sysInfo.SwapUsage
s.MemUsedPercent = sysInfo.MemUsagePercent
s.SwapUsedPercent = sysInfo.SwapUsagePercent
s.T = time.Now()
s.CPUPercent = sysInfo.CPUPercent
s.DCUUsageAvg = 0
s.DCUMemUsageAvg = 0
m.current = &s
return result
} }
func (m *ModelSysLoad) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { func (m *ModelSysLoad) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := inputMsg.(type) { switch msg := inputMsg.(type) {
case *ModelMsg: case *ModelMsg:
clear(m.Cache) m.updateInfo(msg)
maps.Copy(m.Cache, msg.DCUInfo)
m.updateInfo(msg.t)
return m, nil return m, nil
} }
return m, nil return m, nil
...@@ -155,7 +177,7 @@ func (m *ModelSysLoad) View() string { ...@@ -155,7 +177,7 @@ func (m *ModelSysLoad) View() string {
} }
// updateInfo // updateInfo
func (m *ModelSysLoad) updateInfo(t time.Time) { func (m *ModelSysLoad) updateInfo(t *ModelMsg) {
sysInfo, _ := utils.GetSysInfo() sysInfo, _ := utils.GetSysInfo()
s := SysLoadInfo{} s := SysLoadInfo{}
s.Load1 = sysInfo.LoadAverage1 s.Load1 = sysInfo.LoadAverage1
...@@ -167,18 +189,22 @@ func (m *ModelSysLoad) updateInfo(t time.Time) { ...@@ -167,18 +189,22 @@ func (m *ModelSysLoad) updateInfo(t time.Time) {
s.SwapUsed = sysInfo.SwapUsage s.SwapUsed = sysInfo.SwapUsage
s.MemUsedPercent = sysInfo.MemUsagePercent s.MemUsedPercent = sysInfo.MemUsagePercent
s.SwapUsedPercent = sysInfo.SwapUsagePercent s.SwapUsedPercent = sysInfo.SwapUsagePercent
s.T = t s.T = t.t
s.CPUPercent = sysInfo.CPUPercent s.CPUPercent = sysInfo.CPUPercent
s.DCUUsage = make(map[int]float32) s.DCUUsage = make(map[int]float32)
s.DCUMemUsage = make(map[int]float32) s.DCUMemUsage = make(map[int]float32)
s.DCUMemUsageAvg, s.DCUUsageAvg = 0, 0 s.DCUMemUsageAvg, s.DCUUsageAvg = 0, 0
for k, v := range m.Cache {
qinfo, lock := t.DCUInfo.GetQuitInfo()
defer lock.Unlock()
for k, v := range qinfo {
s.DCUMemUsageAvg += v.MemUsedPerent s.DCUMemUsageAvg += v.MemUsedPerent
s.DCUMemUsage[k] = v.MemUsedPerent s.DCUMemUsage[k] = v.MemUsedPerent
s.DCUUsageAvg += v.DCUUTil s.DCUUsageAvg += v.DCUUTil
s.DCUUsage[k] = v.DCUUTil s.DCUUsage[k] = v.DCUUTil
} }
l := len(m.Cache) l := len(qinfo)
s.DCUMemUsageAvg /= float32(l) s.DCUMemUsageAvg /= float32(l)
s.DCUUsageAvg /= float32(l) s.DCUUsageAvg /= float32(l)
m.current = &s m.current = &s
...@@ -186,27 +212,27 @@ func (m *ModelSysLoad) updateInfo(t time.Time) { ...@@ -186,27 +212,27 @@ func (m *ModelSysLoad) updateInfo(t time.Time) {
wg.Add(4) wg.Add(4)
go func() { go func() {
defer wg.Done() defer wg.Done()
m1, _ := m.SysMem.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t, Value: s.MemUsedPercent}}}}) m1, _ := m.SysMem.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t.t, Value: s.MemUsedPercent}}}})
m.SysMem = m1.(*MyTimeChart) m.SysMem = m1.(*MyTimeChart)
}() }()
go func() { go func() {
defer wg.Done() defer wg.Done()
m2, _ := m.SysCPU.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t, Value: s.CPUPercent}}}}) m2, _ := m.SysCPU.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t.t, Value: s.CPUPercent}}}})
m.SysCPU = m2.(*MyTimeChart) m.SysCPU = m2.(*MyTimeChart)
}() }()
go func() { go func() {
defer wg.Done() defer wg.Done()
m3, _ := m.DCU.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t, Value: float64(s.DCUUsageAvg)}}}}) m3, _ := m.DCU.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t.t, Value: float64(s.DCUUsageAvg)}}}})
m.DCU = m3.(*MyTimeChart) m.DCU = m3.(*MyTimeChart)
}() }()
go func() { go func() {
defer wg.Done() defer wg.Done()
m4, _ := m.DCUMem.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t, Value: float64(s.DCUMemUsageAvg)}}}}) m4, _ := m.DCUMem.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t.t, Value: float64(s.DCUMemUsageAvg)}}}})
m.DCUMem = m4.(*MyTimeChart) m.DCUMem = m4.(*MyTimeChart)
}() }()
// 存放数据 // 存放数据
m.SysInfo.Put(t, s) m.SysInfo.Put(t.t, s)
m.Keys.Push(t) m.Keys.Push(t.t)
if m.Keys.Size() > SysLoadCap { if m.Keys.Size() > SysLoadCap {
delKey, have := m.Keys.Pop() delKey, have := m.Keys.Pop()
if have { if have {
......
...@@ -2,6 +2,7 @@ package tui ...@@ -2,6 +2,7 @@ package tui
import ( import (
"fmt" "fmt"
"get-container/cmd/hytop/backend"
"get-container/cmd/hytop/tchart" "get-container/cmd/hytop/tchart"
"testing" "testing"
"time" "time"
...@@ -71,6 +72,28 @@ func TestMyTimeChart(t *testing.T) { ...@@ -71,6 +72,28 @@ func TestMyTimeChart(t *testing.T) {
} }
func TestBinaryHeap(t *testing.T) { func TestBinaryHeap(t *testing.T) {
t.Log(ReDCUName.FindString("BW200, U")) err := backend.Init()
t.Log(ReDCUName.FindString("K100_Ai, U")) if err != nil {
t.Error(err)
}
defer backend.Shutdown()
main := NewModelMain(200, 60)
c := main.Init()
main.Update(c)
main.View()
}
func TestSysloadInit(t *testing.T) {
start := time.Now()
sys := NewModelSysLoad(200)
d := time.Since(start)
t.Logf("%d ms", d.Milliseconds())
start = time.Now()
ts := sys.init()
d = time.Since(start)
t.Logf("%d ms", d.Milliseconds())
for _, tt := range ts[1:] {
t.Logf("%d ms", tt.Sub(ts[0]).Milliseconds())
}
} }
...@@ -5,16 +5,18 @@ go 1.24.2 ...@@ -5,16 +5,18 @@ 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/emirpasic/gods/v2 v2.0.0-alpha
github.com/lrstanley/bubblezone v0.0.0-20240914071701-b48c55a5e78e 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/v3 v3.24.5
github.com/shirou/gopsutil/v4 v4.25.9 github.com/shirou/gopsutil/v4 v4.25.9
) )
require ( require (
github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect
github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762 // indirect github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762 // indirect
github.com/muesli/kmeans v0.3.1 // indirect github.com/muesli/kmeans v0.3.1 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
) )
...@@ -43,7 +45,7 @@ require ( ...@@ -43,7 +45,7 @@ require (
github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-localereader v0.0.1 // indirect
...@@ -53,7 +55,7 @@ require ( ...@@ -53,7 +55,7 @@ require (
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/gamut v0.3.1 github.com/muesli/gamut v0.3.1
github.com/muesli/termenv v0.16.0 // indirect github.com/muesli/termenv v0.16.0
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
......
...@@ -4,9 +4,6 @@ import ( ...@@ -4,9 +4,6 @@ import (
"github.com/shirou/gopsutil/v4/cpu" "github.com/shirou/gopsutil/v4/cpu"
"github.com/shirou/gopsutil/v4/load" "github.com/shirou/gopsutil/v4/load"
"github.com/shirou/gopsutil/v4/mem" "github.com/shirou/gopsutil/v4/mem"
"os"
"strconv"
"time"
) )
/* /*
...@@ -14,28 +11,20 @@ import ( ...@@ -14,28 +11,20 @@ import (
*/ */
type SysInfo struct { type SysInfo struct {
Hostname string // 主机名 CPUPercent float64 // CPU使用率
CPUPercent float64 // CPU使用率 LoadAverage1 float64 // 1分钟内平均负载
LoadAverage1 float64 // 1分钟内平均负载 LoadAverage5 float64 // 5分钟平均负载
LoadAverage5 float64 // 5分钟平均负载 LoadAverage15 float64 // 15分钟平均负载
LoadAverage15 float64 // 15分钟平均负载 MemTotal uint64 // 总内存
MemTotal uint64 // 总内存 SwapTotal uint64 // 总swap
SwapTotal uint64 // 总swap MemUsage uint64 // 已使用内存
MemUsage uint64 // 已使用内存 SwapUsage uint64 // 已使用swap
SwapUsage uint64 // 已使用swap MemUsagePercent float64 // 已使用内存百分比
MemUsagePercent float64 // 已使用内存百分比 SwapUsagePercent float64 // 已使用swap百分比
SwapUsagePercent float64 // 已使用swap百分比
DateTime time.Time // 系统时间
SysUser string // 当前用户
} }
func GetSysInfo() (*SysInfo, error) { func GetSysInfo() (*SysInfo, error) {
hn, err := os.Hostname()
if err != nil {
return nil, err
}
result := SysInfo{} result := SysInfo{}
result.Hostname = hn
l, err := load.Avg() l, err := load.Avg()
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -62,12 +51,5 @@ func GetSysInfo() (*SysInfo, error) { ...@@ -62,12 +51,5 @@ func GetSysInfo() (*SysInfo, error) {
result.MemTotal = vm.Total result.MemTotal = vm.Total
result.MemUsage = vm.Used result.MemUsage = vm.Used
result.MemUsagePercent = vm.UsedPercent result.MemUsagePercent = vm.UsedPercent
result.DateTime = time.Now()
sysu, err := GetSysUserById(os.Getuid())
if err != nil || sysu == nil {
result.SysUser = strconv.Itoa(os.Getuid())
} else {
result.SysUser = sysu.Name
}
return &result, nil return &result, nil
} }
...@@ -17,13 +17,13 @@ func TestGetSysUsers(t *testing.T) { ...@@ -17,13 +17,13 @@ func TestGetSysUsers(t *testing.T) {
} }
func TestGetSysInfo(t *testing.T) { func TestGetSysInfo(t *testing.T) {
start := time.Now start := time.Now()
info, err := GetSysInfo() info, err := GetSysInfo()
d := time.Since(start()) d := time.Since(start)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
t.Logf("%d: %+v", d.Nanoseconds(), *info) t.Logf("%d: %+v", d.Microseconds(), *info)
} }
func BenchmarkGetSysInfo(b *testing.B) { func BenchmarkGetSysInfo(b *testing.B) {
......
...@@ -23,7 +23,7 @@ var SysUserInfo = sync.Map{} ...@@ -23,7 +23,7 @@ var SysUserInfo = sync.Map{}
// detectNis 探测系统是否为Nis的客户端,即解析是否存在ypbind命令,且ypbind命令在运行 // detectNis 探测系统是否为Nis的客户端,即解析是否存在ypbind命令,且ypbind命令在运行
func detectNis() (bool, error) { func detectNis() (bool, error) {
haveCmd, _ := DetectCmd(NISClient) haveCmd, _ := DetectCmd(NISClient)
if haveCmd == false { if !haveCmd {
return false, nil return false, nil
} }
ps, err := GetProcessByName(NISClient) ps, err := GetProcessByName(NISClient)
......
...@@ -65,6 +65,9 @@ type MemorySize struct { ...@@ -65,6 +65,9 @@ type MemorySize struct {
// HumanReadStr 显示人类可读性的字符串,参数i表示精度 // HumanReadStr 显示人类可读性的字符串,参数i表示精度
func (s MemorySize) HumanReadStr(i int) string { func (s MemorySize) HumanReadStr(i int) string {
if s.Num == 0 {
return fmt.Sprintf("0%s", s.Unit)
}
total := s.Num * uint64(s.Unit) total := s.Num * uint64(s.Unit)
units := []StorageCapacityUnit{Byte, KiB, MiB, GiB, TiB, PiB} units := []StorageCapacityUnit{Byte, KiB, MiB, GiB, TiB, PiB}
var target StorageCapacityUnit var target StorageCapacityUnit
......
...@@ -56,7 +56,7 @@ func TestParseMemorySize(t *testing.T) { ...@@ -56,7 +56,7 @@ func TestParseMemorySize(t *testing.T) {
} }
func TestHumanReadStr(t *testing.T) { func TestHumanReadStr(t *testing.T) {
ms := MemorySize{Num: 1025, Unit: Byte} ms := MemorySize{Num: 0, Unit: Byte}
t.Log(ms.HumanReadStr(2)) t.Log(ms.HumanReadStr(2))
ms.Num = 1025 ms.Num = 1025
ms.Unit = PiB ms.Unit = PiB
......
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