Compare commits

...

10 Commits

Author SHA1 Message Date
Dan Ballard 0b9266ba83 make writes to shared global hashmap threadsafe 2018-11-21 13:42:58 -08:00
David 大伟 f39c7cf5e2 Merge pull request #5 from xNevo/master
Fixed english typos
2017-07-17 09:56:50 +08:00
xNevo 8d5783c9c4 FIxed typos 2017-07-15 00:53:09 +02:00
David 大伟 beb3d83057 Merge pull request #4 from struCoder/dev
feat(dev): fix proc type when there is no pid
2017-04-10 18:01:52 +08:00
strucoder 5e29cda97c feat(dev): fix proc type when there is no pid 2017-04-10 18:00:49 +08:00
David 大伟 8b46c6a37a Merge pull request #3 from struCoder/dev
feat(dev): add error and update readme
2017-04-10 17:49:41 +08:00
strucoder 7803be576c feat(dev): add error and update readme 2017-04-10 17:48:47 +08:00
David 大伟 d654f15dd0 Merge pull request #2 from struCoder/dev
docs(dev): update readme.md
2017-04-07 23:11:26 +08:00
strucoder 0ea98db742 docs(dev): update readme.md 2017-04-07 23:10:33 +08:00
David 大伟 f84800df51 Merge pull request #1 from struCoder/dev
feat(dev): support os sys except windows
2017-04-07 22:57:43 +08:00
3 changed files with 32 additions and 16 deletions

View File

@ -3,16 +3,19 @@ Cross-platform process cpu % and memory usage of a PID for golang
Ideas from https://github.com/soyuka/pidusage but just use Golang
[![Go Report Card](https://goreportcard.com/badge/github.com/struCoder/pidusage)](https://goreportcard.com/report/github.com/struCoder/pidusage)
[![GoDoc](https://godoc.org/github.com/struCoder/pidusage?status.svg)](https://godoc.org/github.com/struCoder/pidusage)
## API
```golang
import (
"os"
"github.com/struCoder/pmgo/lib/utils"
"github.com/struCoder/pidusage"
)
func printStat() {
sysInfo := pidusage.GetStat(os.Process.Pid)
sysInfo, err := pidusage.GetStat(os.Process.Pid)
}
```
@ -21,14 +24,14 @@ func printStat() {
A check on the `runtime.GOOS` is done to determine the method to use.
### Linux
We use `/proc/{pid}/stat` in addition to the the `PAGE_SIZE` and the `CLK_TCK` direclty from `getconf()` command. Uptime comes from `proc/uptime` file because it's more accurate than the nodejs `os.uptime()`.
We use `/proc/{pid}/stat` in addition to the the `PAGE_SIZE` and the `CLK_TCK` direclty from `getconf()` command. Uptime comes from `proc/uptime`
Cpu usage is computed by following [those instructions](http://stackoverflow.com/questions/16726779/how-do-i-get-the-total-cpu-usage-of-an-application-from-proc-pid-stat/16736599#16736599). It keeps an history of the current processor time for the given pid so that the computed value gets more and more accurate. Don't forget to do `unmonitor(pid)` so that history gets cleared.
Cpu usage does not check the child process tree!
Memory result is representing the RSS (resident set size) only by doing `rss*pagesize`, where `pagesize` is the result of `getconf PAGE_SIZE`.
### On darwin, freebsd, solaris (tested on 10/11)
### On darwin, freebsd, solaris
We use a fallback with the `ps -o pcpu,rss -p PID` command to get the same informations.
Memory usage will also display the RSS only, process cpu usage might differ from a distribution to another. Please check the correspoding `man ps` for more insights on the subject.

View File

@ -1,6 +1,7 @@
package pidusage
import (
"errors"
"io/ioutil"
"math"
"os/exec"
@ -8,6 +9,7 @@ import (
"runtime"
"strconv"
"strings"
"sync"
)
// SysInfo will record cpu and memory data
@ -16,7 +18,7 @@ type SysInfo struct {
Memory float64
}
// Stat will store CUP time struct
// Stat will store CPU time struct
type Stat struct {
utime float64
stime float64
@ -27,22 +29,22 @@ type Stat struct {
uptime float64
}
type fn func(int) *SysInfo
type fn func(int) (*SysInfo, error)
var fnMap map[string]fn
var platform string
var history map[int]Stat
var historyLock sync.Mutex
var eol string
func wrapper(statType string) func(pid int) *SysInfo {
return func(pid int) *SysInfo {
func wrapper(statType string) func(pid int) (*SysInfo, error) {
return func(pid int) (*SysInfo, error) {
return stat(pid, statType)
}
}
func init() {
platform = runtime.GOOS
eol = "\n"
if strings.Index(platform, "win") == 0 {
if eol = "\n"; strings.Index(platform, "win") == 0 {
platform = "win"
eol = "\r\n"
}
@ -67,7 +69,7 @@ func parseFloat(val string) float64 {
return floatVal
}
func stat(pid int, statType string) *SysInfo {
func stat(pid int, statType string) (*SysInfo, error) {
sysInfo := &SysInfo{}
_history := history[pid]
if statType == "ps" {
@ -77,6 +79,9 @@ func stat(pid int, statType string) *SysInfo {
}
stdout, _ := exec.Command("ps", args, strconv.Itoa(pid)).Output()
ret := formatStdOut(stdout, 1)
if len(ret) == 0 {
return sysInfo, errors.New("Can't find process with this PID: " + strconv.Itoa(pid))
}
sysInfo.CPU = parseFloat(ret[0])
sysInfo.Memory = parseFloat(ret[1]) * 1024
} else if statType == "proc" {
@ -98,7 +103,12 @@ func stat(pid int, statType string) *SysInfo {
}
procStatFileBytes, err := ioutil.ReadFile(path.Join("/proc", strconv.Itoa(pid), "stat"))
infos := strings.Split(strings.SplitAfter(string(procStatFileBytes), ")")[1], " ")
splitAfter := strings.SplitAfter(string(procStatFileBytes), ")")
if len(splitAfter) == 0 || len(splitAfter) == 1 {
return sysInfo, errors.New("Can't find process with this PID: " + strconv.Itoa(pid))
}
infos := strings.Split(splitAfter[1], " ")
stat := &Stat{
utime: parseFloat(infos[12]),
stime: parseFloat(infos[13]),
@ -131,16 +141,18 @@ func stat(pid int, statType string) *SysInfo {
seconds = 1
}
historyLock.Lock()
history[pid] = *stat
historyLock.Unlock()
sysInfo.CPU = (total / seconds) * 100
sysInfo.Memory = stat.rss * pageSize
}
return sysInfo
return sysInfo, nil
}
// GetStat will return current system CPU and memory data
func GetStat(pid int) *SysInfo {
sysInfo := fnMap[platform](pid)
return sysInfo
func GetStat(pid int) (*SysInfo, error) {
sysInfo, err := fnMap[platform](pid)
return sysInfo, err
}

View File

@ -0,0 +1 @@
package pidusage