Skip to content

Commit 3a1b9fe

Browse files
authored
perf: Simplify process data handling and improve performance (#11236)
* refactor: Simplify process data handling and improve performance - Replaced goroutine-based processing with a direct loop for handling process data. - Introduced context support for process and connection retrieval. - Enhanced error handling and data structuring for process information. - Improved SSH session retrieval by mapping users by host for better efficiency. * chore: go fmt
1 parent 8119ba7 commit 3a1b9fe

File tree

1 file changed

+68
-78
lines changed

1 file changed

+68
-78
lines changed

agent/utils/websocket/process_data.go

Lines changed: 68 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
package websocket
22

33
import (
4+
"context"
45
"encoding/json"
56
"fmt"
6-
"sort"
77
"strings"
8-
"sync"
98
"time"
109

1110
"github.com/1Panel-dev/1Panel/agent/utils/common"
12-
1311
"github.com/1Panel-dev/1Panel/agent/global"
1412
"github.com/1Panel-dev/1Panel/agent/utils/files"
1513
"github.com/shirou/gopsutil/v4/host"
@@ -156,93 +154,85 @@ func getDownloadProcess(progress DownloadProgress) (res []byte, err error) {
156154
return
157155
}
158156

157+
func handleProcessData(proc *process.Process, processConfig *PsProcessConfig, pidConnections map[int32][]net.ConnectionStat) *PsProcessData {
158+
if processConfig.Pid > 0 && processConfig.Pid != proc.Pid {
159+
return nil
160+
}
161+
procData := PsProcessData{
162+
PID: proc.Pid,
163+
}
164+
if procName, err := proc.Name(); err == nil {
165+
procData.Name = procName
166+
} else {
167+
procData.Name = "<UNKNOWN>"
168+
}
169+
if processConfig.Name != "" && !strings.Contains(procData.Name, processConfig.Name) {
170+
return nil
171+
}
172+
if username, err := proc.Username(); err == nil {
173+
procData.Username = username
174+
}
175+
if processConfig.Username != "" && !strings.Contains(procData.Username, processConfig.Username) {
176+
return nil
177+
}
178+
procData.PPID, _ = proc.Ppid()
179+
statusArray, _ := proc.Status()
180+
if len(statusArray) > 0 {
181+
procData.Status = strings.Join(statusArray, ",")
182+
}
183+
createTime, procErr := proc.CreateTime()
184+
if procErr == nil {
185+
t := time.Unix(createTime/1000, 0)
186+
procData.StartTime = t.Format("2006-1-2 15:04:05")
187+
}
188+
procData.NumThreads, _ = proc.NumThreads()
189+
procData.CpuValue, _ = proc.CPUPercent()
190+
procData.CpuPercent = fmt.Sprintf("%.2f%%", procData.CpuValue)
191+
192+
if memInfo, err := proc.MemoryInfo(); err == nil {
193+
procData.RssValue = memInfo.RSS
194+
procData.Rss = common.FormatBytes(memInfo.RSS)
195+
} else {
196+
procData.RssValue = 0
197+
}
198+
199+
if connections, ok := pidConnections[proc.Pid]; ok {
200+
procData.NumConnections = len(connections)
201+
}
202+
203+
return &procData
204+
}
205+
159206
func getProcessData(processConfig PsProcessConfig) (res []byte, err error) {
160-
var processes []*process.Process
161-
processes, err = process.Processes()
207+
ctx := context.Background()
208+
209+
processes, err := process.ProcessesWithContext(ctx)
162210
if err != nil {
163211
return
164212
}
165213

166-
var (
167-
result []PsProcessData
168-
resultMutex sync.Mutex
169-
wg sync.WaitGroup
170-
numWorkers = 4
171-
)
172-
173-
handleData := func(proc *process.Process) {
174-
procData := PsProcessData{
175-
PID: proc.Pid,
176-
}
177-
if processConfig.Pid > 0 && processConfig.Pid != proc.Pid {
178-
return
179-
}
180-
if procName, err := proc.Name(); err == nil {
181-
procData.Name = procName
182-
} else {
183-
procData.Name = "<UNKNOWN>"
184-
}
185-
if processConfig.Name != "" && !strings.Contains(procData.Name, processConfig.Name) {
186-
return
187-
}
188-
if username, err := proc.Username(); err == nil {
189-
procData.Username = username
190-
}
191-
if processConfig.Username != "" && !strings.Contains(procData.Username, processConfig.Username) {
192-
return
193-
}
194-
procData.PPID, _ = proc.Ppid()
195-
statusArray, _ := proc.Status()
196-
if len(statusArray) > 0 {
197-
procData.Status = strings.Join(statusArray, ",")
198-
}
199-
createTime, procErr := proc.CreateTime()
200-
if procErr == nil {
201-
t := time.Unix(createTime/1000, 0)
202-
procData.StartTime = t.Format("2006-1-2 15:04:05")
203-
}
204-
procData.NumThreads, _ = proc.NumThreads()
205-
procData.CpuValue, _ = proc.CPUPercent()
206-
procData.CpuPercent = fmt.Sprintf("%.2f", procData.CpuValue) + "%"
207-
208-
if memInfo, err := proc.MemoryInfo(); err == nil {
209-
procData.RssValue = memInfo.RSS
210-
procData.Rss = common.FormatBytes(memInfo.RSS)
211-
} else {
212-
procData.RssValue = 0
213-
}
214+
connections, err := net.ConnectionsMaxWithContext(ctx, "all", 32768)
215+
if err != nil {
216+
return
217+
}
214218

215-
if connections, err := proc.Connections(); err == nil {
216-
procData.NumConnections = len(connections)
219+
pidConnections := make(map[int32][]net.ConnectionStat, len(processes))
220+
for _, conn := range connections {
221+
if conn.Pid == 0 {
222+
continue
217223
}
218-
219-
resultMutex.Lock()
220-
result = append(result, procData)
221-
resultMutex.Unlock()
224+
pidConnections[conn.Pid] = append(pidConnections[conn.Pid], conn)
222225
}
223226

224-
chunkSize := (len(processes) + numWorkers - 1) / numWorkers
225-
for i := 0; i < numWorkers; i++ {
226-
wg.Add(1)
227-
start := i * chunkSize
228-
end := (i + 1) * chunkSize
229-
if end > len(processes) {
230-
end = len(processes)
231-
}
227+
result := make([]PsProcessData, 0, len(processes))
232228

233-
go func(start, end int) {
234-
defer wg.Done()
235-
for j := start; j < end; j++ {
236-
handleData(processes[j])
237-
}
238-
}(start, end)
229+
for _, proc := range processes {
230+
procData := handleProcessData(proc, &processConfig, pidConnections)
231+
if procData != nil {
232+
result = append(result, *procData)
233+
}
239234
}
240235

241-
wg.Wait()
242-
243-
sort.Slice(result, func(i, j int) bool {
244-
return result[i].PID < result[j].PID
245-
})
246236
res, err = json.Marshal(result)
247237
return
248238
}

0 commit comments

Comments
 (0)