diff --git a/gops/gops.go b/gops/gops.go new file mode 100644 index 0000000..ae459ae --- /dev/null +++ b/gops/gops.go @@ -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 +} diff --git a/gops/gops_test.go b/gops/gops_test.go new file mode 100644 index 0000000..1929c40 --- /dev/null +++ b/gops/gops_test.go @@ -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) +} diff --git a/res/js/settings.js b/res/js/settings.js index da9c392..b8efafd 100644 --- a/res/js/settings.js +++ b/res/js/settings.js @@ -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(); diff --git a/web.go b/web.go index 5524415..aed9f23 100644 --- a/web.go +++ b/web.go @@ -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 {