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
/*
#cgo CFLAGS: -I.
#cgo LDFLAGS: -L/opt/hyhal/lib/ -lrocm_smi64
#cgo LDFLAGS: -L/opt/hyhal/lib -lamd_smi
#include <stdlib.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 (
"get-container/gpu"
"get-container/utils"
"slices"
"syscall"
"time"
tea "github.com/charmbracelet/bubbletea"
......@@ -64,6 +65,7 @@ const (
VMTree ViewMode = 1
VMOneProcess ViewMode = 2
VMProcessEnv ViewMode = 3
VMHelp ViewMode = 4
)
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 动作消息
type ActionMsg struct {
VM ViewMode // 所在视图,默认为0,即主视图
......@@ -166,8 +181,11 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := inputMsg.(type) {
case tea.KeyMsg: // 键盘事件
switch msg.String() {
case "ctrl+c", "q":
case "q":
return m, tea.Quit
case "ctrl+c":
cmd := m.handleCtrlC()
return m, cmd
case "up":
cmd := m.handleKeyUp()
return m, cmd
......@@ -237,15 +255,64 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
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 {
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
}
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
if m.actionMsg.Action != nil {
target := make([]int32, 0, 8)
if len(m.actionMsg.SelectPids) > 0 {
for k := range m.actionMsg.SelectPids {
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
}
......@@ -315,12 +382,12 @@ func (m *ModelMain) handleKeyK() tea.Cmd {
if m.actionMsg.Action != nil {
return nil
}
var pa ProcessAction = PANone
if m.actionMsg.Action == nil {
m.actionMsg.Action = &pa
}
switch m.actionMsg.VM {
case VMMain:
var pa ProcessAction = PANone
if m.actionMsg.Action == nil {
m.actionMsg.Action = &pa
}
header, _ := m.Header.Update(m.actionMsg)
dcuInfo, _ := m.DCUInfo.Update(m.actionMsg)
sysLoad, _ := m.SysLoad.Update(m.actionMsg)
......@@ -333,6 +400,10 @@ func (m *ModelMain) handleKeyK() tea.Cmd {
m.dialog = dialog.(*Dialog)
return nil
case VMTree:
var pa ProcessAction = PAKill
if m.actionMsg.Action == nil {
m.actionMsg.Action = &pa
}
pstree, _ := m.pstree.Update(m.actionMsg)
dialog, _ := m.dialog.Update(m.actionMsg)
m.dialog = dialog.(*Dialog)
......@@ -414,7 +485,6 @@ func (m *ModelMain) handleKeySpace() tea.Cmd {
m.ProcessInfo = m1.(*ModelProcessInfo)
return cmd1
case VMTree:
// todo
m1, cmd1 := m.pstree.Update(m.actionMsg)
m.pstree = m1.(*ModelPsTree)
return cmd1
......
......@@ -33,11 +33,14 @@ type ModelProcessDetail struct {
h, w [2]int // h[0]代表上边两个表的高度、h[1]代表下边两个表的高度,w[0]表示左边两个表的宽度,w[1]表示右边两个表的宽度
lines [5]string // 5条横线
DCUMemTotal, MemTotal utils.MemorySize // 内存总量
DCUMemMax, MemMax utils.MemorySize // 内存使用最大值
MemMax utils.MemorySize // 内存使用最大值
DCUMemUsed utils.MemorySize
CPUPercent, MemPercent float64
t string
DCUMemUsed utils.MemorySize
CPUPercent, MemPercent float64
DCUPercent, DCUMemPercent float64
t string
color1, color2 []lipgloss.Color // 分别给上方和下方两个图表的渐变颜色
}
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.WriteByte('\n')
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.DCU = NewTimeChart(result.w[1], result.h[1], 0, 100, []lipgloss.Color{lipgloss.Color("#0dff00ff")})
result.DCUMem = NewTimeChart(result.w[1], result.h[0], 0, 100, []lipgloss.Color{lipgloss.Color("#ff1e00ff")})
result.color1 = GenGradientColor(lipgloss.Color("#ff0000"), lipgloss.Color("#00ff00ff"), result.h[0])
result.color2 = GenGradientColor(lipgloss.Color("#ff0000"), lipgloss.Color("#00ff00ff"), result.h[1])
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
for k := range result.maxVal {
......@@ -156,14 +163,18 @@ func (m *ModelProcessDetail) handleModelMsg(msg *ModelMsg) {
if !have {
dcu = 0
dcumem = 0
m.DCUPercent = 0
m.DCUMemPercent = 0
} else {
dcumem = float64(dcuInfo.MemUsedPerent)
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}
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[1] = max(m.maxVal[1], mem)
......@@ -185,7 +196,7 @@ func (m *ModelProcessDetail) handleModelMsg(msg *ModelMsg) {
} else {
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()})
} else {
m.CPU.Update(MyTimeChartMsg{Reset: false, Points: []tchart.TimePoint{{Time: msg.t, Value: cpu}}})
......@@ -221,11 +232,25 @@ func (m *ModelProcessDetail) View() string {
sb.WriteString(myBorder.Left)
sb.WriteByte('\n')
sb.WriteString(m.lines[2])
sb.WriteByte('\n')
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())
Mem := style.Border(lipgloss.NormalBorder(), false, true, false).Render(m.Mem.View())
DCU := style.Border(lipgloss.NormalBorder(), false, true, false, false).Render(m.DCU.View())
cpuTitle := fmt.Sprintf(" Max CPU: %.1f%%\n CPU: %.1f%%", m.maxVal[0], m.CPUPercent)
memUsed := utils.MemorySize{Unit: utils.Byte, Num: (uint64(m.MemPercent*10000) * m.MemTotal.Num) / 1000000}
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]))
return sb.String()
}
......@@ -7,6 +7,7 @@ import (
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/x/ansi"
"github.com/lucasb-eyer/go-colorful"
"github.com/muesli/gamut"
)
func absInt(a int) int {
......@@ -165,3 +166,8 @@ func ConvertColor(color []color.Color) []lipgloss.Color {
}
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 (
"os"
"regexp"
"strconv"
"syscall"
"time"
"github.com/shirou/gopsutil/v4/process"
......@@ -198,35 +199,18 @@ func GetPsTree2(pids []int32) map[int32]*ProcessInfo {
return findedProcess
}
func addChilds(p *process.Process, ctx map[int32]*ProcessInfo) map[int32]*ProcessInfo {
if ctx == nil {
ctx = make(map[int32]*ProcessInfo)
}
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
func SendSignal(pids []int32, sig syscall.Signal) {
if len(pids) == 0 {
return
}
for _, child := range childs {
c, have := ctx[child.Pid]
if !have {
c = NewProcessInfo(child)
ctx[child.Pid] = c
for _, v := range pids {
if v == 1 {
continue
}
p, err := process.NewProcess(1)
if err != nil {
continue
}
info.Child[child.Pid] = c
addChilds(child, ctx)
_ = p.SendSignal(sig)
}
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