wrap ps command to get cpu and mem

master
codeskyblue 8 years ago
parent 6e3c782d75
commit a6d578d154

@ -0,0 +1,81 @@
package gops
import (
"errors"
"fmt"
"os/exec"
"strconv"
"strings"
sigar "github.com/cloudfoundry/gosigar"
mps "github.com/mitchellh/go-ps"
)
type Process struct {
mps.Process
}
func NewProcess(pid int) (p Process, err error) {
mp, err := mps.FindProcess(pid)
if err != nil {
return
}
return Process{
Process: mp,
}, nil
}
func (p *Process) Mem() (m sigar.ProcMem, err error) {
err = m.Get(p.Pid())
return
}
type ProcInfo struct {
Pid int
Rss int
PCpu float64
}
// CPU Percent * 100
// only linux and darwin works
func (p *Process) ProcInfo() (pi ProcInfo, err error) {
pi.Pid = p.Pid()
cmd := exec.Command("ps", "-o", "pcpu,rss", "-p", strconv.Itoa(p.Pid()))
output, err := cmd.Output()
if err != nil {
err = errors.New("ps err: " + err.Error())
return
}
fields := strings.SplitN(string(output), "\n", 2)
if len(fields) != 2 {
err = errors.New("parse ps command out format error")
return
}
_, err = fmt.Sscanf(fields[1], "%f %d", &pi.PCpu, &pi.Rss)
pi.Rss *= 1024
return
}
// Get all child process
func (p *Process) Children(recursive bool) (cps []Process) {
pses, err := mps.Processes()
if err != nil {
return
}
pidMap := make(map[int][]mps.Process, 0)
for _, p := range pses {
pidMap[p.PPid()] = append(pidMap[p.PPid()], p)
}
var travel func(int)
travel = func(pid int) {
for _, p := range pidMap[pid] {
cps = append(cps, Process{p})
if recursive {
travel(p.Pid())
}
}
}
travel(p.Pid())
return
}

@ -0,0 +1,15 @@
package gops
import "testing"
func TestProcInfo(t *testing.T) {
p, err := NewProcess(6464)
if err != nil {
t.Fatal(err)
}
pi, err := p.ProcInfo()
if err != nil {
t.Fatal(err)
}
t.Log(pi)
}

@ -17,9 +17,9 @@ var ws = newWebsocket('/ws/perfs/' + name, {
vm.pid = data.pid;
vm.subPids = data.sub_pids;
console.log("pid", data.pid, data); //evt.data.pid);
if (memData && data.mem && data.mem.rss) {
if (memData && data.mem && data.mem.Resident) {
memData.push({
value: [new Date(), data.mem.rss],
value: [new Date(), data.mem.Resident],
})
if (memData.length > 10) {
memData.shift();

@ -16,6 +16,7 @@ import (
"syscall"
"time"
sigar "github.com/cloudfoundry/gosigar"
"github.com/go-yaml/yaml"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
@ -477,22 +478,18 @@ func getAllSubPids(pid int) (subps []int, err error) {
return
}
func getTotalMem(pids []int) *process.MemoryInfoStat {
minfo := &process.MemoryInfoStat{}
func getTotalMem(pids []int) sigar.ProcMem {
mem := sigar.ProcMem{}
for _, pid := range pids {
p, err := process.NewProcess(int32(pid))
if err != nil {
continue
}
m, err := p.MemoryInfo()
if err != nil {
m := sigar.ProcMem{}
if err := m.Get(pid); err != nil {
continue
}
minfo.RSS += m.RSS
minfo.Swap += m.Swap
minfo.VMS += m.VMS
mem.Resident += m.Resident
mem.Size += m.Size
mem.Share += m.Share
}
return minfo
return mem
}
func getTotalCpu(pids []int) float64 {
@ -505,7 +502,6 @@ func getTotalCpu(pids []int) float64 {
// still need to fix here
// use gosigar instead
n, err := p.Percent(300 * time.Millisecond)
log.Println(p.Pid, n, err)
if err != nil {
continue
}
@ -531,6 +527,7 @@ func (s *Supervisor) wsPerf(w http.ResponseWriter, r *http.Request) {
return
}
for {
// c.SetWriteDeadline(time.Now().Add(3 * time.Second))
if proc.cmd == nil || proc.cmd.Process == nil {
log.Println("process not running")
return
@ -544,18 +541,13 @@ func (s *Supervisor) wsPerf(w http.ResponseWriter, r *http.Request) {
pids := append(spids, pid)
log.Println(pids)
mstat := getTotalMem(pids)
mem := getTotalMem(pids)
pcpu := getTotalCpu(pids)
// for _, spid := range spids {
// fmt.Println("spid:", spid)
// }
// mstat, _ := ps.MemoryInfo()
// pcpu, _ := ps.Percent(300 * time.Millisecond)
err = c.WriteJSON(map[string]interface{}{
"pid": pid,
"sub_pids": spids,
"mem": mstat,
"mem": mem,
"cpu": pcpu,
})
if err != nil {

Loading…
Cancel
Save