Commit fd13705b authored by liming6's avatar liming6
Browse files

fix 修改部分bug

parent 6e2dd6f5
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Delve Server",
"type": "go",
"request": "attach",
"mode": "remote",
"host": "127.0.0.1", // dlv服务器的IP地址(如果是本地就是127.0.0.1
"port": 43000, // dlv服务器监听的端口
"remotePath": "/root/cache/dcu-process-montor/cmd/hytop", // **重要:远程机器上Go源代码的绝对路径**
}
]
}
\ No newline at end of file
...@@ -2,7 +2,7 @@ package lib ...@@ -2,7 +2,7 @@ package lib
/* /*
#cgo CFLAGS: -I. #cgo CFLAGS: -I.
#cgo LDFLAGS: -L/opt/hyhal/lib/ -lrocm_smi64 #cgo LDFLAGS: -L/opt/hyhal/lib -lamd_smi
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
......
package tui
const (
HelpStr = `
hytop 1.0.0 - (C) Ming Li, 2025-2025.
Released under the GNU GPLv3 License.
hytop is a tool for monitoring DCUs from the command line.
Button function introduction:
h: show help info
`
)
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"get-container/gpu" "get-container/gpu"
"get-container/utils" "get-container/utils"
"slices" "slices"
"syscall"
"time" "time"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
...@@ -64,6 +65,7 @@ const ( ...@@ -64,6 +65,7 @@ const (
VMTree ViewMode = 1 VMTree ViewMode = 1
VMOneProcess ViewMode = 2 VMOneProcess ViewMode = 2
VMProcessEnv ViewMode = 3 VMProcessEnv ViewMode = 3
VMHelp ViewMode = 4
) )
func (pa ProcessAction) String() string { func (pa ProcessAction) String() string {
...@@ -79,6 +81,19 @@ func (pa ProcessAction) String() string { ...@@ -79,6 +81,19 @@ func (pa ProcessAction) String() string {
} }
} }
func (pa ProcessAction) Signal() syscall.Signal {
switch pa {
case PAKill:
return syscall.SIGKILL
case PAInt:
return syscall.SIGINT
case PATerm:
return syscall.SIGTERM
default:
return syscall.SIGTERM
}
}
// ActionMsg 动作消息 // ActionMsg 动作消息
type ActionMsg struct { type ActionMsg struct {
VM ViewMode // 所在视图,默认为0,即主视图 VM ViewMode // 所在视图,默认为0,即主视图
...@@ -166,8 +181,11 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { ...@@ -166,8 +181,11 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := inputMsg.(type) { switch msg := inputMsg.(type) {
case tea.KeyMsg: // 键盘事件 case tea.KeyMsg: // 键盘事件
switch msg.String() { switch msg.String() {
case "ctrl+c", "q": case "q":
return m, tea.Quit return m, tea.Quit
case "ctrl+c":
cmd := m.handleCtrlC()
return m, cmd
case "up": case "up":
cmd := m.handleKeyUp() cmd := m.handleKeyUp()
return m, cmd return m, cmd
...@@ -237,15 +255,64 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { ...@@ -237,15 +255,64 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil return m, nil
} }
func (m *ModelMain) handleCtrlC() tea.Cmd {
if m.actionMsg.Action != nil || m.actionMsg.VM != VMTree {
return nil
}
if len(m.actionMsg.SelectPids) != 0 || m.actionMsg.PointPid != nil {
action := PAInt
m.actionMsg.Action = &action
pstree, _ := m.pstree.Update(m.actionMsg)
dialog, _ := m.dialog.Update(m.actionMsg)
m.dialog = dialog.(*Dialog)
m.pstree = pstree.(*ModelPsTree)
}
return nil
}
func (m *ModelMain) handleKeyEnter() tea.Cmd { func (m *ModelMain) handleKeyEnter() tea.Cmd {
if m.actionMsg.VM != VMMain || m.actionMsg.PointPid == nil { if m.actionMsg.VM == VMMain && m.actionMsg.Action == nil {
pid := *m.actionMsg.PointPid
m.actionMsg.PidView = &pid
m.processDetail = NewModelProcessDetail(m.width, m.height, pid)
m.processDetail.Update(m.modelMsg)
m.actionMsg.VM = VMOneProcess
return nil return nil
} }
pid := *m.actionMsg.PointPid if m.actionMsg.Action != nil {
m.actionMsg.PidView = &pid target := make([]int32, 0, 8)
m.processDetail = NewModelProcessDetail(m.width, m.height, pid) if len(m.actionMsg.SelectPids) > 0 {
m.processDetail.Update(m.modelMsg) for k := range m.actionMsg.SelectPids {
m.actionMsg.VM = VMOneProcess target = append(target, k)
}
} else if m.actionMsg.PointPid != nil {
target = append(target, *m.actionMsg.PointPid)
}
switch *m.actionMsg.Action {
case PANone:
m.actionMsg.Action = nil
switch m.actionMsg.VM {
case VMMain:
header, _ := m.Header.Update(m.actionMsg)
dcuInfo, _ := m.DCUInfo.Update(m.actionMsg)
sysLoad, _ := m.SysLoad.Update(m.actionMsg)
pidinfo, _ := m.ProcessInfo.Update(m.actionMsg)
m.Header = header.(*ModelHeader)
m.DCUInfo = dcuInfo.(*ModelDCUInfo)
m.SysLoad = sysLoad.(*ModelSysLoad)
m.ProcessInfo = pidinfo.(*ModelProcessInfo)
case VMTree:
pstree, _ := m.pstree.Update(m.actionMsg)
m.pstree = pstree.(*ModelPsTree)
}
case PAKill:
go utils.SendSignal(target, PAKill.Signal())
case PATerm:
go utils.SendSignal(target, PATerm.Signal())
case PAInt:
go utils.SendSignal(target, PAInt.Signal())
}
}
return nil return nil
} }
...@@ -315,12 +382,12 @@ func (m *ModelMain) handleKeyK() tea.Cmd { ...@@ -315,12 +382,12 @@ func (m *ModelMain) handleKeyK() tea.Cmd {
if m.actionMsg.Action != nil { if m.actionMsg.Action != nil {
return nil return nil
} }
var pa ProcessAction = PANone
if m.actionMsg.Action == nil {
m.actionMsg.Action = &pa
}
switch m.actionMsg.VM { switch m.actionMsg.VM {
case VMMain: case VMMain:
var pa ProcessAction = PANone
if m.actionMsg.Action == nil {
m.actionMsg.Action = &pa
}
header, _ := m.Header.Update(m.actionMsg) header, _ := m.Header.Update(m.actionMsg)
dcuInfo, _ := m.DCUInfo.Update(m.actionMsg) dcuInfo, _ := m.DCUInfo.Update(m.actionMsg)
sysLoad, _ := m.SysLoad.Update(m.actionMsg) sysLoad, _ := m.SysLoad.Update(m.actionMsg)
...@@ -333,6 +400,10 @@ func (m *ModelMain) handleKeyK() tea.Cmd { ...@@ -333,6 +400,10 @@ func (m *ModelMain) handleKeyK() tea.Cmd {
m.dialog = dialog.(*Dialog) m.dialog = dialog.(*Dialog)
return nil return nil
case VMTree: case VMTree:
var pa ProcessAction = PAKill
if m.actionMsg.Action == nil {
m.actionMsg.Action = &pa
}
pstree, _ := m.pstree.Update(m.actionMsg) pstree, _ := m.pstree.Update(m.actionMsg)
dialog, _ := m.dialog.Update(m.actionMsg) dialog, _ := m.dialog.Update(m.actionMsg)
m.dialog = dialog.(*Dialog) m.dialog = dialog.(*Dialog)
...@@ -414,7 +485,6 @@ func (m *ModelMain) handleKeySpace() tea.Cmd { ...@@ -414,7 +485,6 @@ func (m *ModelMain) handleKeySpace() tea.Cmd {
m.ProcessInfo = m1.(*ModelProcessInfo) m.ProcessInfo = m1.(*ModelProcessInfo)
return cmd1 return cmd1
case VMTree: case VMTree:
// todo
m1, cmd1 := m.pstree.Update(m.actionMsg) m1, cmd1 := m.pstree.Update(m.actionMsg)
m.pstree = m1.(*ModelPsTree) m.pstree = m1.(*ModelPsTree)
return cmd1 return cmd1
......
...@@ -33,11 +33,14 @@ type ModelProcessDetail struct { ...@@ -33,11 +33,14 @@ type ModelProcessDetail struct {
h, w [2]int // h[0]代表上边两个表的高度、h[1]代表下边两个表的高度,w[0]表示左边两个表的宽度,w[1]表示右边两个表的宽度 h, w [2]int // h[0]代表上边两个表的高度、h[1]代表下边两个表的高度,w[0]表示左边两个表的宽度,w[1]表示右边两个表的宽度
lines [5]string // 5条横线 lines [5]string // 5条横线
DCUMemTotal, MemTotal utils.MemorySize // 内存总量 DCUMemTotal, MemTotal utils.MemorySize // 内存总量
DCUMemMax, MemMax utils.MemorySize // 内存使用最大值 MemMax utils.MemorySize // 内存使用最大值
DCUMemUsed utils.MemorySize DCUMemUsed utils.MemorySize
CPUPercent, MemPercent float64 CPUPercent, MemPercent float64
t string DCUPercent, DCUMemPercent float64
t string
color1, color2 []lipgloss.Color // 分别给上方和下方两个图表的渐变颜色
} }
func NewModelProcessDetail(width, height int, pid int32) *ModelProcessDetail { func NewModelProcessDetail(width, height int, pid int32) *ModelProcessDetail {
...@@ -87,10 +90,14 @@ func NewModelProcessDetail(width, height int, pid int32) *ModelProcessDetail { ...@@ -87,10 +90,14 @@ func NewModelProcessDetail(width, height int, pid int32) *ModelProcessDetail {
sb.WriteString(result.lines[1]) sb.WriteString(result.lines[1])
sb.WriteByte('\n') sb.WriteByte('\n')
result.Header = sb.String() result.Header = sb.String()
result.CPU = NewTimeChart(result.w[0], result.h[0], 0, 100, []lipgloss.Color{lipgloss.Color("#00fffbff")})
result.Mem = NewTimeChart(result.w[0], result.h[1], 0, 100, []lipgloss.Color{lipgloss.Color("#8800ffff")}) result.color1 = GenGradientColor(lipgloss.Color("#ff0000"), lipgloss.Color("#00ff00ff"), result.h[0])
result.DCU = NewTimeChart(result.w[1], result.h[1], 0, 100, []lipgloss.Color{lipgloss.Color("#0dff00ff")}) result.color2 = GenGradientColor(lipgloss.Color("#ff0000"), lipgloss.Color("#00ff00ff"), result.h[1])
result.DCUMem = NewTimeChart(result.w[1], result.h[0], 0, 100, []lipgloss.Color{lipgloss.Color("#ff1e00ff")})
result.CPU = NewTimeChart(result.w[0], result.h[0], 0, 100, []lipgloss.Color{lipgloss.Color("#00ff00ff")})
result.Mem = NewTimeChart(result.w[0], result.h[1], 0, 100, result.color2)
result.DCU = NewTimeChart(result.w[1], result.h[1], 0, 100, result.color2)
result.DCUMem = NewTimeChart(result.w[1], result.h[0], 0, 100, result.color1)
result.cpuPointsNum = result.w[0]*2 + 1 result.cpuPointsNum = result.w[0]*2 + 1
for k := range result.maxVal { for k := range result.maxVal {
...@@ -156,14 +163,18 @@ func (m *ModelProcessDetail) handleModelMsg(msg *ModelMsg) { ...@@ -156,14 +163,18 @@ func (m *ModelProcessDetail) handleModelMsg(msg *ModelMsg) {
if !have { if !have {
dcu = 0 dcu = 0
dcumem = 0 dcumem = 0
m.DCUPercent = 0
m.DCUMemPercent = 0
} else { } else {
dcumem = float64(dcuInfo.MemUsedPerent) dcumem = float64(dcuInfo.MemUsedPerent)
dcu = float64(dcuInfo.DCUUTil) dcu = float64(dcuInfo.DCUUTil)
m.DCUPercent = dcu
m.DCUMemPercent = dcumem
} }
m.DCUMemMax = utils.MemorySize{Unit: utils.Byte, Num: dcuInfo.MemTotal} m.DCUMemTotal = utils.MemorySize{Unit: utils.Byte, Num: dcuInfo.MemTotal}
m.DCUMemUsed = utils.MemorySize{Unit: utils.Byte, Num: dcuInfo.MemUsed} m.DCUMemUsed = utils.MemorySize{Unit: utils.Byte, Num: dcuInfo.MemUsed}
lock.Unlock() lock.Unlock()
m.MemMax = utils.MemorySize{Unit: utils.Byte, Num: msg.systemInfo.MemTotal} m.MemTotal = utils.MemorySize{Unit: utils.Byte, Num: msg.systemInfo.MemTotal}
m.maxVal[0] = max(m.maxVal[0], cpu) m.maxVal[0] = max(m.maxVal[0], cpu)
m.maxVal[1] = max(m.maxVal[1], mem) m.maxVal[1] = max(m.maxVal[1], mem)
...@@ -185,7 +196,7 @@ func (m *ModelProcessDetail) handleModelMsg(msg *ModelMsg) { ...@@ -185,7 +196,7 @@ func (m *ModelProcessDetail) handleModelMsg(msg *ModelMsg) {
} else { } else {
m.maxValThreshold[0] = float64(int(math.Ceil(cpu))/50)*50 + 50 m.maxValThreshold[0] = float64(int(math.Ceil(cpu))/50)*50 + 50
} }
m.CPU = NewTimeChart(m.w[0], m.h[0], 0, m.maxValThreshold[0], []lipgloss.Color{lipgloss.Color("#00fffbff")}) m.CPU = NewTimeChart(m.w[0], m.h[0], 0, m.maxValThreshold[0], []lipgloss.Color{lipgloss.Color("#00ff00ff")})
m.CPU.Update(MyTimeChartMsg{Reset: false, Points: m.cpuPoints.Values()}) m.CPU.Update(MyTimeChartMsg{Reset: false, Points: m.cpuPoints.Values()})
} else { } else {
m.CPU.Update(MyTimeChartMsg{Reset: false, Points: []tchart.TimePoint{{Time: msg.t, Value: cpu}}}) m.CPU.Update(MyTimeChartMsg{Reset: false, Points: []tchart.TimePoint{{Time: msg.t, Value: cpu}}})
...@@ -221,11 +232,25 @@ func (m *ModelProcessDetail) View() string { ...@@ -221,11 +232,25 @@ func (m *ModelProcessDetail) View() string {
sb.WriteString(myBorder.Left) sb.WriteString(myBorder.Left)
sb.WriteByte('\n') sb.WriteByte('\n')
sb.WriteString(m.lines[2]) sb.WriteString(m.lines[2])
sb.WriteByte('\n')
style := lipgloss.NewStyle() style := lipgloss.NewStyle()
CPU := style.Border(lipgloss.NormalBorder(), false, true, false).Render(m.CPU.View())
DCUM := style.Border(lipgloss.NormalBorder(), false, true, false, false).Render(m.DCUMem.View()) cpuTitle := fmt.Sprintf(" Max CPU: %.1f%%\n CPU: %.1f%%", m.maxVal[0], m.CPUPercent)
Mem := style.Border(lipgloss.NormalBorder(), false, true, false).Render(m.Mem.View()) memUsed := utils.MemorySize{Unit: utils.Byte, Num: (uint64(m.MemPercent*10000) * m.MemTotal.Num) / 1000000}
DCU := style.Border(lipgloss.NormalBorder(), false, true, false, false).Render(m.DCU.View()) memMax := utils.MemorySize{Unit: utils.Byte, Num: (uint64(m.maxVal[1]*10000) * m.MemTotal.Num) / 1000000}
memTitle := fmt.Sprintf(" Host-Mem: %s (%.1f%%)\n Max Host-Mem: %s (%.1f%%) / %s", memUsed.HumanReadStr(1), m.MemPercent, memMax.HumanReadStr(1), m.maxVal[1], m.MemTotal.HumanReadStr(1))
dcuTitle := fmt.Sprintf(" DCU: %.1f%%\n Max DCU: %.1f%%", m.DCUPercent, m.maxVal[2])
dcuMemMax := utils.MemorySize{Unit: utils.Byte, Num: (uint64(m.maxVal[3]*100) * m.DCUMemTotal.Num / 10000)}
dcuMemTitle := fmt.Sprintf(" Max DCU-Mem: %s (%.1f%%) / %s\n DCU-Mem: %s (%.1f%%)", dcuMemMax.HumanReadStr(1), m.maxVal[3], m.DCUMemTotal.HumanReadStr(1), m.DCUMemUsed.HumanReadStr(1), m.DCUMemPercent)
CPU := style.Border(lipgloss.NormalBorder(), false, true, false).Render(StackPosition(cpuTitle, m.CPU.View(), lipgloss.Top, lipgloss.Left))
CPU = StackPosition(fmt.Sprintf("├%s", LowLeightStyle.Render(fmt.Sprintf("%d%%", int(m.maxValThreshold[0]/2)))), CPU, lipgloss.Center, lipgloss.Left)
DCUM := style.Border(lipgloss.NormalBorder(), false, true, false, false).Render(StackPosition(dcuMemTitle, m.DCUMem.View(), lipgloss.Top, lipgloss.Left))
Mem := style.Border(lipgloss.NormalBorder(), false, true, false).Render(StackPosition(memTitle, m.Mem.View(), lipgloss.Bottom, lipgloss.Left))
DCU := style.Border(lipgloss.NormalBorder(), false, true, false, false).Render(StackPosition(dcuTitle, m.DCU.View(), lipgloss.Bottom, lipgloss.Left))
sb.WriteString(lipgloss.JoinVertical(lipgloss.Left, lipgloss.JoinHorizontal(lipgloss.Top, CPU, DCUM), m.lines[3], lipgloss.JoinHorizontal(lipgloss.Top, Mem, DCU), m.lines[4])) sb.WriteString(lipgloss.JoinVertical(lipgloss.Left, lipgloss.JoinHorizontal(lipgloss.Top, CPU, DCUM), m.lines[3], lipgloss.JoinHorizontal(lipgloss.Top, Mem, DCU), m.lines[4]))
return sb.String() return sb.String()
} }
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/x/ansi" "github.com/charmbracelet/x/ansi"
"github.com/lucasb-eyer/go-colorful" "github.com/lucasb-eyer/go-colorful"
"github.com/muesli/gamut"
) )
func absInt(a int) int { func absInt(a int) int {
...@@ -165,3 +166,8 @@ func ConvertColor(color []color.Color) []lipgloss.Color { ...@@ -165,3 +166,8 @@ func ConvertColor(color []color.Color) []lipgloss.Color {
} }
return result return result
} }
// GenGradientColor 生成渐变色
func GenGradientColor(from, to lipgloss.Color, num int) []lipgloss.Color {
return ConvertColor(gamut.Blends(from, to, num))
}
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"os" "os"
"regexp" "regexp"
"strconv" "strconv"
"syscall"
"time" "time"
"github.com/shirou/gopsutil/v4/process" "github.com/shirou/gopsutil/v4/process"
...@@ -198,35 +199,18 @@ func GetPsTree2(pids []int32) map[int32]*ProcessInfo { ...@@ -198,35 +199,18 @@ func GetPsTree2(pids []int32) map[int32]*ProcessInfo {
return findedProcess return findedProcess
} }
func addChilds(p *process.Process, ctx map[int32]*ProcessInfo) map[int32]*ProcessInfo { func SendSignal(pids []int32, sig syscall.Signal) {
if ctx == nil { if len(pids) == 0 {
ctx = make(map[int32]*ProcessInfo) return
}
if p == nil {
return ctx
}
start := time.Now()
childs, err := p.Children()
d := time.Since(start)
log.Printf("children %d ms", d.Milliseconds())
if err != nil {
return ctx
}
info, have := ctx[p.Pid]
if !have {
pp := NewProcessInfo(p)
info = pp
ctx[p.Pid] = pp
} }
for _, v := range pids {
for _, child := range childs { if v == 1 {
c, have := ctx[child.Pid] continue
if !have { }
c = NewProcessInfo(child) p, err := process.NewProcess(1)
ctx[child.Pid] = c if err != nil {
continue
} }
info.Child[child.Pid] = c _ = p.SendSignal(sig)
addChilds(child, ctx)
} }
return ctx
} }
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