Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
liming6
dcu-process-montor
Commits
ed4a196f
Commit
ed4a196f
authored
Nov 22, 2025
by
liming6
Browse files
feature 优化取数据流程,优化启动性能
parent
d5f04510
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
234 additions
and
115 deletions
+234
-115
cmd/hytop/backend/dcu.go
cmd/hytop/backend/dcu.go
+39
-1
cmd/hytop/tui/dcuinfo.go
cmd/hytop/tui/dcuinfo.go
+49
-35
cmd/hytop/tui/header.go
cmd/hytop/tui/header.go
+2
-5
cmd/hytop/tui/main.go
cmd/hytop/tui/main.go
+36
-11
cmd/hytop/tui/process.go
cmd/hytop/tui/process.go
+13
-4
cmd/hytop/tui/sysload.go
cmd/hytop/tui/sysload.go
+47
-21
cmd/hytop/tui/tui_test.go
cmd/hytop/tui/tui_test.go
+25
-2
go.mod
go.mod
+5
-3
utils/system.go
utils/system.go
+10
-28
utils/system_test.go
utils/system_test.go
+3
-3
utils/sysuser.go
utils/sysuser.go
+1
-1
utils/unit.go
utils/unit.go
+3
-0
utils/utils_test.go
utils/utils_test.go
+1
-1
No files found.
cmd/hytop/backend/dcu.go
View file @
ed4a196f
...
...
@@ -14,7 +14,7 @@ import (
"sync/atomic"
"time"
"github.com/shirou/gopsutil/v
4
/process"
"github.com/shirou/gopsutil/v
3
/process"
)
var
(
...
...
@@ -352,6 +352,44 @@ func (m *DCUInfoMap) GetDCUProcessInfo() map[int][]DCUProcessInfo {
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的格式
func
durationStr
(
d
time
.
Duration
)
string
{
h
:=
int
(
math
.
Floor
(
d
.
Hours
()))
...
...
cmd/hytop/tui/dcuinfo.go
View file @
ed4a196f
...
...
@@ -2,8 +2,7 @@ package tui
import
(
"fmt"
"get-container/cmd/hytop/backend"
"maps"
"get-container/utils"
"regexp"
"strconv"
"strings"
...
...
@@ -15,10 +14,10 @@ import (
)
type
ModelDCUInfo
struct
{
p
arent
*
ModelMain
info
map
[
int
]
backend
.
DCUInfo
// dcu相关信息
pro
progress
.
Model
// 进度条
proWidth
int
// 进度条宽度
p
ro
progress
.
Model
// 进度条
proWidth
int
// 进度条宽度
modMsg
*
ModelMsg
width
,
height
int
}
const
(
...
...
@@ -35,20 +34,17 @@ var (
ReDCUName
=
regexp
.
MustCompile
(
`(?i)^[A-Z0-9-_]*`
)
)
func
NewModelDCUInfo
(
m
*
ModelMain
)
*
ModelDCUInfo
{
return
&
ModelDCUInfo
{
parent
:
m
,
info
:
make
(
map
[
int
]
backend
.
DCUInfo
),
}
func
NewModelDCUInfo
(
w
,
h
int
)
*
ModelDCUInfo
{
return
&
ModelDCUInfo
{
width
:
w
,
height
:
h
}
}
func
(
m
*
ModelDCUInfo
)
Init
()
tea
.
Cmd
{
if
m
.
parent
.
width
<
StaticWidth
+
ProgressMinWidth
+
OtherWidth
{
if
m
.
width
<
StaticWidth
+
ProgressMinWidth
+
OtherWidth
{
return
tea
.
Quit
}
m
.
proWidth
=
ProgressMinWidth
if
m
.
parent
.
width
>
StaticWidth
+
ProgressMinWidth
+
OtherWidth
{
m
.
proWidth
=
m
.
parent
.
width
-
OtherWidth
-
StaticWidth
if
m
.
width
>
StaticWidth
+
ProgressMinWidth
+
OtherWidth
{
m
.
proWidth
=
m
.
width
-
OtherWidth
-
StaticWidth
}
m
.
pro
=
progress
.
New
(
progress
.
WithColorProfile
(
termenv
.
TrueColor
),
progress
.
WithGradient
(
"#0000ffff"
,
"#ff0000ff"
),
progress
.
WithWidth
(
m
.
proWidth
))
return
nil
...
...
@@ -57,43 +53,61 @@ func (m *ModelDCUInfo) Init() 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
)
m
.
modMsg
=
msg
return
m
,
nil
case
tea
.
WindowSizeMsg
:
m
.
height
=
msg
.
Height
m
.
width
=
msg
.
Width
return
m
,
nil
}
return
m
,
nil
}
func
(
m
*
ModelDCUInfo
)
View
()
string
{
if
m
.
modMsg
==
nil
{
return
""
}
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
{}
infos
:=
make
([]
string
,
l
)
for
i
:=
range
l
{
ii
:=
m
.
info
[
i
]
infos
:=
make
([]
string
,
0
)
for
i
:=
range
128
{
qinfo
,
haveq
:=
qmap
[
i
]
sinfo
,
haves
:=
smap
[
i
]
if
!
(
haveq
||
haves
)
{
conTime
++
if
conTime
>
8
{
break
}
continue
}
strBuilder
.
WriteString
(
myBorder
.
Left
)
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
.
WriteString
(
FormatStr
(
ReDCUName
.
FindString
(
ii
.
Name
),
8
,
lipgloss
.
Left
))
strBuilder
.
WriteString
(
FormatStr
(
ReDCUName
.
FindString
(
qinfo
.
Name
),
8
,
lipgloss
.
Left
))
strBuilder
.
WriteByte
(
' '
)
strBuilder
.
WriteString
(
FormatStr
(
ii
.
PerformanceLevel
,
15
,
lipgloss
.
Right
))
strBuilder
.
WriteString
(
FormatStr
(
qinfo
.
PerformanceLevel
,
15
,
lipgloss
.
Right
))
strBuilder
.
WriteByte
(
' '
)
strBuilder
.
WriteString
(
myBorder
.
Left
)
strBuilder
.
WriteByte
(
' '
)
strBuilder
.
WriteString
(
FormatStr
(
ii
.
BusId
,
13
,
lipgloss
.
Left
))
strBuilder
.
WriteString
(
FormatStr
(
qinfo
.
BusId
,
13
,
lipgloss
.
Left
))
strBuilder
.
WriteByte
(
' '
)
strBuilder
.
WriteString
(
FormatStr
(
"Off"
,
6
,
lipgloss
.
Right
))
strBuilder
.
WriteByte
(
' '
)
strBuilder
.
WriteString
(
myBorder
.
Left
)
strBuilder
.
WriteByte
(
' '
)
if
ii
.
Mig
{
if
sinfo
.
Mig
.
Load
()
{
strBuilder
.
WriteString
(
FormatStr
(
"On"
,
16
,
lipgloss
.
Left
))
}
else
{
strBuilder
.
WriteString
(
FormatStr
(
"Off"
,
16
,
lipgloss
.
Left
))
}
strBuilder
.
WriteByte
(
' '
)
if
ii
.
Ecc
{
if
sinfo
.
Ecc
.
Load
()
{
strBuilder
.
WriteString
(
FormatStr
(
"On"
,
3
,
lipgloss
.
Right
))
}
else
{
strBuilder
.
WriteString
(
FormatStr
(
"Off"
,
3
,
lipgloss
.
Right
))
...
...
@@ -101,36 +115,36 @@ func (m *ModelDCUInfo) View() string {
strBuilder
.
WriteByte
(
' '
)
strBuilder
.
WriteString
(
myBorder
.
Left
)
strBuilder
.
WriteString
(
" DCU: "
)
strBuilder
.
WriteString
(
m
.
pro
.
ViewAs
(
float64
(
ii
.
DCUUTil
)
/
100
))
strBuilder
.
WriteString
(
m
.
pro
.
ViewAs
(
float64
(
qinfo
.
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
.
WriteString
(
FormatStr
(
qinfo
.
Fan
,
4
,
lipgloss
.
Left
))
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
(
' '
)
// 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
.
WriteString
(
myBorder
.
Left
)
strBuilder
.
WriteByte
(
' '
)
// 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
.
WriteString
(
myBorder
.
Left
)
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
.
WriteString
(
FormatStr
(
ii
.
PwrMode
,
13
,
lipgloss
.
Right
))
strBuilder
.
WriteString
(
FormatStr
(
sinfo
.
PwrMode
.
Load
()
.
(
string
)
,
13
,
lipgloss
.
Right
))
strBuilder
.
WriteByte
(
' '
)
strBuilder
.
WriteString
(
myBorder
.
Left
)
strBuilder
.
WriteString
(
" Mem: "
)
strBuilder
.
WriteString
(
m
.
pro
.
ViewAs
(
float64
(
ii
.
MemUsed
Perent
)
/
100
))
strBuilder
.
WriteString
(
m
.
pro
.
ViewAs
(
float64
(
qinfo
.
MemUsed
)
/
float64
(
qinfo
.
MemTotal
)
))
strBuilder
.
WriteByte
(
' '
)
strBuilder
.
WriteString
(
myBorder
.
Left
)
infos
[
i
]
=
strBuilder
.
String
()
infos
=
append
(
infos
,
strBuilder
.
String
()
)
strBuilder
.
Reset
()
}
if
len
(
infos
)
>
0
{
...
...
cmd/hytop/tui/header.go
View file @
ed4a196f
...
...
@@ -10,17 +10,14 @@ import (
)
type
ModelHeader
struct
{
parent
*
ModelMain
t
time
.
Time
DCUTopVersion
string
SMIVersion
string
DriverVersion
string
}
func
NewModelHeader
(
m
*
ModelMain
)
*
ModelHeader
{
return
&
ModelHeader
{
parent
:
m
,
}
func
NewModelHeader
()
*
ModelHeader
{
return
&
ModelHeader
{}
}
func
(
mh
*
ModelHeader
)
Init
()
tea
.
Cmd
{
...
...
cmd/hytop/tui/main.go
View file @
ed4a196f
...
...
@@ -40,8 +40,8 @@ func NewModelMain(width, height int) ModelMain {
result
:=
ModelMain
{}
result
.
width
=
width
result
.
height
=
height
result
.
Header
=
NewModelHeader
(
&
result
)
result
.
DCUInfo
=
NewModelDCUInfo
(
&
resul
t
)
result
.
Header
=
NewModelHeader
()
result
.
DCUInfo
=
NewModelDCUInfo
(
width
,
heigh
t
)
result
.
SysLoad
=
NewModelSysLoad
(
width
)
result
.
ProcessInfo
=
NewModelProcessInfo
(
width
)
return
result
...
...
@@ -112,8 +112,16 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
m
.
SysLoad
=
sysLoad
.
(
*
ModelSysLoad
)
m
.
ProcessInfo
=
pidinfo
.
(
*
ModelProcessInfo
)
return
m
,
nil
case
tea
.
WindowSizeMsg
:
case
tea
.
WindowSizeMsg
:
// 窗口尺寸变化
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
...
...
@@ -142,21 +150,38 @@ var myBorder = lipgloss.Border{
func
initModelInfo
(
model
*
ModelMsg
)
error
{
model
.
t
=
time
.
Now
()
model
.
MyVersion
=
DCUTopVersion
if
ver
,
err
:=
gpu
.
GetHYVersionInfo
();
err
!=
nil
{
return
err
}
else
{
model
.
Version
=
ver
}
return
err
model
.
DCUInfo
=
backend
.
DCUSInfoMap
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 更新模型信息
func
updateModelInfo
(
modelMsg
*
ModelMsg
,
t
time
.
Time
)
{
func
updateModelInfo
(
modelMsg
*
ModelMsg
,
t
time
.
Time
)
error
{
modelMsg
.
t
=
t
modelMsg
.
DCUInfo
=
backend
.
GetDCUInfo
()
modelMsg
.
systemInfo
,
_
=
utils
.
GetSysInfo
()
modelMsg
.
DCUPidInfo
=
backend
.
GetDCUProcessInfo
()
if
sinfo
,
err
:=
utils
.
GetSysInfo
();
err
!=
nil
{
return
err
}
else
{
modelMsg
.
systemInfo
=
sinfo
}
modelMsg
.
DCUPidInfo
=
modelMsg
.
DCUInfo
.
GetDCUProcessInfo2
()
if
err
:=
modelMsg
.
DCUInfo
.
UpdateQuickInfo
();
err
!=
nil
{
return
err
}
return
nil
}
cmd/hytop/tui/process.go
View file @
ed4a196f
...
...
@@ -19,11 +19,12 @@ type ModelProcessInfo struct {
Cache
map
[
int
][]
backend
.
DCUProcessInfo
width
int
style
lipgloss
.
Style
modMsg
*
ModelMsg
}
const
(
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"
)
...
...
@@ -72,9 +73,9 @@ func (m *ModelProcessInfo) View() string {
sb
.
WriteString
(
myBorder
.
Left
)
sb
.
WriteString
(
FormatStr
(
fmt
.
Sprintf
(
"%d"
,
process
.
DCU
),
4
,
lipgloss
.
Right
))
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
.
WriteString
(
FormatStr
(
process
.
Info
.
User
,
9
,
lipgloss
.
Right
))
sb
.
WriteString
(
FormatStr
(
process
.
Info
.
User
,
8
,
lipgloss
.
Right
))
sb
.
WriteByte
(
' '
)
sb
.
WriteString
(
FormatStr
(
process
.
DCUMem
,
8
,
lipgloss
.
Right
))
sb
.
WriteByte
(
' '
)
...
...
@@ -85,7 +86,13 @@ func (m *ModelProcessInfo) View() string {
sb
.
WriteString
(
FormatStr
(
fmt
.
Sprintf
(
"%.1f"
,
process
.
Info
.
Mem
),
5
,
lipgloss
.
Right
))
sb
.
WriteByte
(
' '
)
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
tw
:=
lipgloss
.
Width
(
process
.
Info
.
Cmd
)
if
w
>=
tw
{
...
...
@@ -122,6 +129,8 @@ func (m *ModelProcessInfo) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
case
*
ModelMsg
:
clear
(
m
.
Cache
)
maps
.
Copy
(
m
.
Cache
,
msg
.
DCUPidInfo
)
m
.
modMsg
=
msg
return
m
,
nil
}
return
m
,
nil
}
cmd/hytop/tui/sysload.go
View file @
ed4a196f
...
...
@@ -2,11 +2,9 @@ package tui
import
(
"fmt"
"get-container/cmd/hytop/backend"
"get-container/cmd/hytop/tchart"
"get-container/utils"
"image/color"
"maps"
"strings"
"sync"
"time"
...
...
@@ -31,7 +29,6 @@ type ModelSysLoad struct {
SysCPU
*
MyTimeChart
DCU
*
MyTimeChart
DCUMem
*
MyTimeChart
Cache
map
[
int
]
backend
.
DCUInfo
SysInfo
*
linkedhashmap
.
Map
[
time
.
Time
,
SysLoadInfo
]
Keys
*
binaryheap
.
Heap
[
time
.
Time
]
current
*
SysLoadInfo
...
...
@@ -58,7 +55,6 @@ type SysLoadInfo struct {
func
NewModelSysLoad
(
width
int
)
*
ModelSysLoad
{
result
:=
ModelSysLoad
{}
result
.
width
=
width
result
.
Cache
=
make
(
map
[
int
]
backend
.
DCUInfo
)
result
.
SysInfo
=
linkedhashmap
.
New
[
time
.
Time
,
SysLoadInfo
]()
result
.
Keys
=
binaryheap
.
NewWith
(
func
(
a
,
b
time
.
Time
)
int
{
if
a
.
After
(
b
)
{
...
...
@@ -96,9 +92,6 @@ func (m *ModelSysLoad) Init() tea.Cmd {
if
c
:=
m
.
SysCPU
.
Init
();
c
!=
nil
{
result
=
append
(
result
,
c
)
}
if
len
(
result
)
>
0
{
return
tea
.
Batch
(
result
...
)
}
sysInfo
,
_
:=
utils
.
GetSysInfo
()
s
:=
SysLoadInfo
{}
s
.
Load1
=
sysInfo
.
LoadAverage1
...
...
@@ -115,15 +108,44 @@ func (m *ModelSysLoad) Init() tea.Cmd {
s
.
DCUUsageAvg
=
0
s
.
DCUMemUsageAvg
=
0
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
)
{
switch
msg
:=
inputMsg
.
(
type
)
{
case
*
ModelMsg
:
clear
(
m
.
Cache
)
maps
.
Copy
(
m
.
Cache
,
msg
.
DCUInfo
)
m
.
updateInfo
(
msg
.
t
)
m
.
updateInfo
(
msg
)
return
m
,
nil
}
return
m
,
nil
...
...
@@ -155,7 +177,7 @@ func (m *ModelSysLoad) View() string {
}
// updateInfo
func
(
m
*
ModelSysLoad
)
updateInfo
(
t
time
.
Time
)
{
func
(
m
*
ModelSysLoad
)
updateInfo
(
t
*
ModelMsg
)
{
sysInfo
,
_
:=
utils
.
GetSysInfo
()
s
:=
SysLoadInfo
{}
s
.
Load1
=
sysInfo
.
LoadAverage1
...
...
@@ -167,18 +189,22 @@ func (m *ModelSysLoad) updateInfo(t time.Time) {
s
.
SwapUsed
=
sysInfo
.
SwapUsage
s
.
MemUsedPercent
=
sysInfo
.
MemUsagePercent
s
.
SwapUsedPercent
=
sysInfo
.
SwapUsagePercent
s
.
T
=
t
s
.
T
=
t
.
t
s
.
CPUPercent
=
sysInfo
.
CPUPercent
s
.
DCUUsage
=
make
(
map
[
int
]
float32
)
s
.
DCUMemUsage
=
make
(
map
[
int
]
float32
)
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
.
DCUMemUsage
[
k
]
=
v
.
MemUsedPerent
s
.
DCUUsageAvg
+=
v
.
DCUUTil
s
.
DCUUsage
[
k
]
=
v
.
DCUUTil
}
l
:=
len
(
m
.
Cache
)
l
:=
len
(
qinfo
)
s
.
DCUMemUsageAvg
/=
float32
(
l
)
s
.
DCUUsageAvg
/=
float32
(
l
)
m
.
current
=
&
s
...
...
@@ -186,27 +212,27 @@ func (m *ModelSysLoad) updateInfo(t time.Time) {
wg
.
Add
(
4
)
go
func
()
{
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
)
}()
go
func
()
{
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
)
}()
go
func
()
{
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
)
}()
go
func
()
{
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
.
SysInfo
.
Put
(
t
,
s
)
m
.
Keys
.
Push
(
t
)
m
.
SysInfo
.
Put
(
t
.
t
,
s
)
m
.
Keys
.
Push
(
t
.
t
)
if
m
.
Keys
.
Size
()
>
SysLoadCap
{
delKey
,
have
:=
m
.
Keys
.
Pop
()
if
have
{
...
...
cmd/hytop/tui/tui_test.go
View file @
ed4a196f
...
...
@@ -2,6 +2,7 @@ package tui
import
(
"fmt"
"get-container/cmd/hytop/backend"
"get-container/cmd/hytop/tchart"
"testing"
"time"
...
...
@@ -71,6 +72,28 @@ func TestMyTimeChart(t *testing.T) {
}
func
TestBinaryHeap
(
t
*
testing
.
T
)
{
t
.
Log
(
ReDCUName
.
FindString
(
"BW200, U"
))
t
.
Log
(
ReDCUName
.
FindString
(
"K100_Ai, U"
))
err
:=
backend
.
Init
()
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
())
}
}
go.mod
View file @
ed4a196f
...
...
@@ -5,16 +5,18 @@ go 1.24.2
require (
github.com/charmbracelet/bubbletea
v1.3.10
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/moby/moby/api
v1.52.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
)
require (
github.com/emirpasic/gods/v2
v2.0.0-alpha // indirect
github.com/muesli/clusters
v0.0.0-20200529215643-2700303c1762 // 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
)
...
...
@@ -43,7 +45,7 @@ require (
github.com/go-logr/logr
v1.4.2 // indirect
github.com/go-logr/stdr
v1.2.2 // 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/mattn/go-isatty
v0.0.20 // indirect
github.com/mattn/go-localereader
v0.0.1 // indirect
...
...
@@ -53,7 +55,7 @@ require (
github.com/muesli/ansi
v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader
v0.2.2 // indirect
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/image-spec
v1.1.1 // indirect
github.com/power-devops/perfstat
v0.0.0-20240221224432-82ca36839d55 // indirect
...
...
utils/system.go
View file @
ed4a196f
...
...
@@ -4,9 +4,6 @@ import (
"github.com/shirou/gopsutil/v4/cpu"
"github.com/shirou/gopsutil/v4/load"
"github.com/shirou/gopsutil/v4/mem"
"os"
"strconv"
"time"
)
/*
...
...
@@ -14,28 +11,20 @@ import (
*/
type
SysInfo
struct
{
Hostname
string
// 主机名
CPUPercent
float64
// CPU使用率
LoadAverage1
float64
// 1分钟内平均负载
LoadAverage5
float64
// 5分钟平均负载
LoadAverage15
float64
// 15分钟平均负载
MemTotal
uint64
// 总内存
SwapTotal
uint64
// 总swap
MemUsage
uint64
// 已使用内存
SwapUsage
uint64
// 已使用swap
MemUsagePercent
float64
// 已使用内存百分比
SwapUsagePercent
float64
// 已使用swap百分比
DateTime
time
.
Time
// 系统时间
SysUser
string
// 当前用户
CPUPercent
float64
// CPU使用率
LoadAverage1
float64
// 1分钟内平均负载
LoadAverage5
float64
// 5分钟平均负载
LoadAverage15
float64
// 15分钟平均负载
MemTotal
uint64
// 总内存
SwapTotal
uint64
// 总swap
MemUsage
uint64
// 已使用内存
SwapUsage
uint64
// 已使用swap
MemUsagePercent
float64
// 已使用内存百分比
SwapUsagePercent
float64
// 已使用swap百分比
}
func
GetSysInfo
()
(
*
SysInfo
,
error
)
{
hn
,
err
:=
os
.
Hostname
()
if
err
!=
nil
{
return
nil
,
err
}
result
:=
SysInfo
{}
result
.
Hostname
=
hn
l
,
err
:=
load
.
Avg
()
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -62,12 +51,5 @@ func GetSysInfo() (*SysInfo, error) {
result
.
MemTotal
=
vm
.
Total
result
.
MemUsage
=
vm
.
Used
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
}
utils/system_test.go
View file @
ed4a196f
...
...
@@ -17,13 +17,13 @@ func TestGetSysUsers(t *testing.T) {
}
func
TestGetSysInfo
(
t
*
testing
.
T
)
{
start
:=
time
.
Now
start
:=
time
.
Now
()
info
,
err
:=
GetSysInfo
()
d
:=
time
.
Since
(
start
()
)
d
:=
time
.
Since
(
start
)
if
err
!=
nil
{
t
.
Error
(
err
)
}
t
.
Logf
(
"%d: %+v"
,
d
.
Nan
oseconds
(),
*
info
)
t
.
Logf
(
"%d: %+v"
,
d
.
Micr
oseconds
(),
*
info
)
}
func
BenchmarkGetSysInfo
(
b
*
testing
.
B
)
{
...
...
utils/sysuser.go
View file @
ed4a196f
...
...
@@ -23,7 +23,7 @@ var SysUserInfo = sync.Map{}
// detectNis 探测系统是否为Nis的客户端,即解析是否存在ypbind命令,且ypbind命令在运行
func
detectNis
()
(
bool
,
error
)
{
haveCmd
,
_
:=
DetectCmd
(
NISClient
)
if
haveCmd
==
false
{
if
!
haveCmd
{
return
false
,
nil
}
ps
,
err
:=
GetProcessByName
(
NISClient
)
...
...
utils/unit.go
View file @
ed4a196f
...
...
@@ -65,6 +65,9 @@ type MemorySize struct {
// HumanReadStr 显示人类可读性的字符串,参数i表示精度
func
(
s
MemorySize
)
HumanReadStr
(
i
int
)
string
{
if
s
.
Num
==
0
{
return
fmt
.
Sprintf
(
"0%s"
,
s
.
Unit
)
}
total
:=
s
.
Num
*
uint64
(
s
.
Unit
)
units
:=
[]
StorageCapacityUnit
{
Byte
,
KiB
,
MiB
,
GiB
,
TiB
,
PiB
}
var
target
StorageCapacityUnit
...
...
utils/utils_test.go
View file @
ed4a196f
...
...
@@ -56,7 +56,7 @@ func TestParseMemorySize(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
))
ms
.
Num
=
1025
ms
.
Unit
=
PiB
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment