From 463519cae235bb0276bb0a2aa1d951339b0a540c Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Wed, 19 Feb 2020 13:05:52 -0600 Subject: Fixes #50. Replace forked ps with builtin gopsutil which should save some CPU cycles --- go.mod | 2 +- go.sum | 2 +- widgets/proc.go | 32 ++++++++++++++++++++++++ widgets/proc_freebsd.go | 66 ------------------------------------------------- widgets/proc_linux.go | 45 --------------------------------- widgets/proc_other.go | 57 ------------------------------------------ widgets/proc_windows.go | 44 --------------------------------- 7 files changed, 34 insertions(+), 214 deletions(-) delete mode 100644 widgets/proc_freebsd.go delete mode 100644 widgets/proc_linux.go delete mode 100644 widgets/proc_other.go delete mode 100644 widgets/proc_windows.go diff --git a/go.mod b/go.mod index 6058002..8db3fab 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/go-ole/go-ole v1.2.1 // indirect github.com/mattn/go-runewidth v0.0.4 github.com/mitchellh/go-wordwrap v1.0.0 // indirect - github.com/prometheus/client_golang v1.4.1 + github.com/prometheus/client_golang v1.4.1 // indirect github.com/shirou/gopsutil v2.18.11+incompatible github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect github.com/stretchr/testify v1.4.0 diff --git a/go.sum b/go.sum index aaabcf8..7d42d4c 100644 --- a/go.sum +++ b/go.sum @@ -100,7 +100,6 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/shirou/gopsutil v2.18.11+incompatible h1:PMFTKnFTr/YTRW5rbLK4vWALV3a+IGXse5nvhSjztmg= github.com/shirou/gopsutil v2.18.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v2.20.1+incompatible h1:oIq9Cq4i84Hk8uQAUOG3eNdI/29hBawGrD5YRl6JRDY= -github.com/shirou/gopsutil v2.20.1+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -137,6 +136,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= diff --git a/widgets/proc.go b/widgets/proc.go index 9fed067..6e29db7 100644 --- a/widgets/proc.go +++ b/widgets/proc.go @@ -12,6 +12,7 @@ import ( psCPU "github.com/shirou/gopsutil/cpu" tui "github.com/gizak/termui/v3" + "github.com/shirou/gopsutil/process" ui "github.com/xxxserxxx/gotop/termui" "github.com/xxxserxxx/gotop/utils" ) @@ -329,3 +330,34 @@ func (self SortProcsByMem) Swap(i, j int) { func (self SortProcsByMem) Less(i, j int) bool { return self[i].Mem < self[j].Mem } + +func getProcs() ([]Proc, error) { + procs, err := process.Processes() + if err != nil { + return nil, err + } + rv := make([]Proc, len(procs)) + for i, p := range procs { + cmdLine, err := p.Cmdline() + if err != nil { + return nil, err + } + cmd, err := p.Name() + if err != nil { + return nil, err + } + cpu, err := p.CPUPercent() + if err != nil { + return nil, err + } + mem, err := p.MemoryPercent() + rv[i] = Proc{ + Pid: int(p.Pid), + CommandName: cmd, + FullCommand: cmdLine, + Cpu: cpu, + Mem: float64(mem), + } + } + return rv, nil +} diff --git a/widgets/proc_freebsd.go b/widgets/proc_freebsd.go deleted file mode 100644 index ac3e73f..0000000 --- a/widgets/proc_freebsd.go +++ /dev/null @@ -1,66 +0,0 @@ -package widgets - -import ( - "encoding/json" - "fmt" - "log" - "os/exec" - "strconv" - "strings" - - "github.com/xxxserxxx/gotop/utils" -) - -type processList struct { - ProcessInformation struct { - Process []struct { - Pid string `json:"pid"` - Comm string `json:"command"` - Cpu string `json:"percent-cpu" ` - Mem string `json:"percent-memory" ` - Args string `json:"arguments" ` - } `json:"process"` - } `json:"process-information"` -} - -func getProcs() ([]Proc, error) { - output, err := exec.Command("ps", "-axo pid,comm,%cpu,%mem,args", "--libxo", "json").Output() - if err != nil { - return nil, fmt.Errorf("failed to execute 'ps' command: %v", err) - } - - list := processList{} - err = json.Unmarshal(output, &list) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal json. %s", err) - } - procs := []Proc{} - - for _, process := range list.ProcessInformation.Process { - if process.Comm == "idle" { - continue - } - pid, err := strconv.Atoi(strings.TrimSpace(process.Pid)) - if err != nil { - log.Printf("failed to convert first field to int: %v. split: %v", err, process) - } - cpu, err := strconv.ParseFloat(utils.ConvertLocalizedString(process.Cpu), 32) - if err != nil { - log.Printf("failed to convert third field to float: %v. split: %v", err, process) - } - mem, err := strconv.ParseFloat(utils.ConvertLocalizedString(process.Mem), 32) - if err != nil { - log.Printf("failed to convert fourth field to float: %v. split: %v", err, process) - } - proc := Proc{ - Pid: pid, - CommandName: process.Comm, - Cpu: cpu, - Mem: mem, - FullCommand: process.Args, - } - procs = append(procs, proc) - } - - return procs, nil -} diff --git a/widgets/proc_linux.go b/widgets/proc_linux.go deleted file mode 100644 index 0045234..0000000 --- a/widgets/proc_linux.go +++ /dev/null @@ -1,45 +0,0 @@ -package widgets - -import ( - "fmt" - "log" - "os/exec" - "strconv" - "strings" -) - -func getProcs() ([]Proc, error) { - output, err := exec.Command("ps", "-axo", "pid:10,comm:50,pcpu:5,pmem:5,args").Output() - if err != nil { - return nil, fmt.Errorf("failed to execute 'ps' command: %v", err) - } - - // converts to []string, removing trailing newline and header - linesOfProcStrings := strings.Split(strings.TrimSuffix(string(output), "\n"), "\n")[1:] - - procs := []Proc{} - for _, line := range linesOfProcStrings { - pid, err := strconv.Atoi(strings.TrimSpace(line[0:10])) - if err != nil { - log.Printf("failed to convert PID to int: %v. line: %v", err, line) - } - cpu, err := strconv.ParseFloat(strings.TrimSpace(line[63:68]), 64) - if err != nil { - log.Printf("failed to convert CPU usage to float: %v. line: %v", err, line) - } - mem, err := strconv.ParseFloat(strings.TrimSpace(line[69:74]), 64) - if err != nil { - log.Printf("failed to convert Mem usage to float: %v. line: %v", err, line) - } - proc := Proc{ - Pid: pid, - CommandName: strings.TrimSpace(line[11:61]), - FullCommand: line[74:], - Cpu: cpu, - Mem: mem, - } - procs = append(procs, proc) - } - - return procs, nil -} diff --git a/widgets/proc_other.go b/widgets/proc_other.go deleted file mode 100644 index 09aac28..0000000 --- a/widgets/proc_other.go +++ /dev/null @@ -1,57 +0,0 @@ -// +build darwin openbsd - -package widgets - -import ( - "fmt" - "log" - "os/exec" - "strconv" - "strings" - - "github.com/xxxserxxx/gotop/utils" -) - -const ( - // Define column widths for ps output used in Procs() - five = "12345" - ten = five + five - fifty = ten + ten + ten + ten + ten -) - -func getProcs() ([]Proc, error) { - keywords := fmt.Sprintf("pid=%s,comm=%s,pcpu=%s,pmem=%s,args", ten, fifty, five, five) - output, err := exec.Command("ps", "-caxo", keywords).Output() - if err != nil { - return nil, fmt.Errorf("failed to execute 'ps' command: %v", err) - } - - // converts to []string and removes the header - linesOfProcStrings := strings.Split(strings.TrimSpace(string(output)), "\n")[1:] - - procs := []Proc{} - for _, line := range linesOfProcStrings { - pid, err := strconv.Atoi(strings.TrimSpace(line[0:10])) - if err != nil { - log.Printf("failed to convert first field to int: %v. split: %v", err, line) - } - cpu, err := strconv.ParseFloat(utils.ConvertLocalizedString(strings.TrimSpace(line[63:68])), 64) - if err != nil { - log.Printf("failed to convert third field to float: %v. split: %v", err, line) - } - mem, err := strconv.ParseFloat(utils.ConvertLocalizedString(strings.TrimSpace(line[69:74])), 64) - if err != nil { - log.Printf("failed to convert fourth field to float: %v. split: %v", err, line) - } - proc := Proc{ - Pid: pid, - CommandName: strings.TrimSpace(line[11:61]), - Cpu: cpu, - Mem: mem, - FullCommand: line[74:], - } - procs = append(procs, proc) - } - - return procs, nil -} diff --git a/widgets/proc_windows.go b/widgets/proc_windows.go deleted file mode 100644 index adc49e9..0000000 --- a/widgets/proc_windows.go +++ /dev/null @@ -1,44 +0,0 @@ -package widgets - -import ( - "fmt" - "log" - - psProc "github.com/shirou/gopsutil/process" -) - -func getProcs() ([]Proc, error) { - psProcs, err := psProc.Processes() - if err != nil { - return nil, fmt.Errorf("failed to get processes from gopsutil: %v", err) - } - - procs := make([]Proc, len(psProcs)) - for i, psProc := range psProcs { - pid := psProc.Pid - command, err := psProc.Name() - if err != nil { - log.Printf("failed to get process command from gopsutil: %v. psProc: %v. i: %v. pid: %v", err, psProc, i, pid) - } - cpu, err := psProc.CPUPercent() - if err != nil { - log.Printf("failed to get process cpu usage from gopsutil: %v. psProc: %v. i: %v. pid: %v", err, psProc, i, pid) - } - mem, err := psProc.MemoryPercent() - if err != nil { - log.Printf("failed to get process memeory usage from gopsutil: %v. psProc: %v. i: %v. pid: %v", err, psProc, i, pid) - } - - procs[i] = Proc{ - Pid: int(pid), - CommandName: command, - Cpu: cpu, - Mem: float64(mem), - // getting command args using gopsutil's Cmdline and CmdlineSlice wasn't - // working the last time I tried it, so we're just reusing 'command' - FullCommand: command, - } - } - - return procs, nil -} -- cgit v1.2.3