feat(dev): support os sys except windows
This commit is contained in:
parent
cb0fa46cfb
commit
0382e975d5
38
README.md
38
README.md
|
@ -1,2 +1,40 @@
|
||||||
# pidusage
|
# pidusage
|
||||||
Cross-platform process cpu % and memory usage of a PID for golang
|
Cross-platform process cpu % and memory usage of a PID for golang
|
||||||
|
|
||||||
|
Ideas from https://github.com/soyuka/pidusage but just use Golang
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
```golang
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"github.com/struCoder/pmgo/lib/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func printStat() {
|
||||||
|
sysInfo := pidusage.GetStat(os.Process.Pid)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
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()`.
|
||||||
|
|
||||||
|
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)
|
||||||
|
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.
|
||||||
|
|
||||||
|
### On AIX
|
||||||
|
AIX is tricky because I have no AIX test environement, at the moment we use: `ps -o pcpu,rssize -p PID` but `/proc` results should be more accurate! If you're familiar with the AIX environment and know how to get the same results as we've got with Linux systems.
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
Next version will support
|
||||||
|
|
64
pidusage.go
64
pidusage.go
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package pidusage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math"
|
"math"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -28,34 +27,37 @@ type Stat struct {
|
||||||
uptime float64
|
uptime float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// type fn func(int) *SysInfo
|
type fn func(int) *SysInfo
|
||||||
|
|
||||||
// var fnMap map[string]fn
|
var fnMap map[string]fn
|
||||||
var platform string
|
var platform string
|
||||||
var history map[int]Stat
|
var history map[int]Stat
|
||||||
|
var eol string
|
||||||
|
|
||||||
// func wrapper(statType string) func(pid int) *SysInfo {
|
func wrapper(statType string) func(pid int) *SysInfo {
|
||||||
// return func(pid int) *SysInfo {
|
return func(pid int) *SysInfo {
|
||||||
// return stat(pid, statType)
|
return stat(pid, statType)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
func init() {
|
func init() {
|
||||||
platform = runtime.GOOS
|
platform = runtime.GOOS
|
||||||
if strings.Contains(platform, "win") {
|
eol = "\n"
|
||||||
|
if strings.Index(platform, "win") == 0 {
|
||||||
platform = "win"
|
platform = "win"
|
||||||
|
eol = "\r\n"
|
||||||
}
|
}
|
||||||
history = make(map[int]Stat)
|
history = make(map[int]Stat)
|
||||||
// fnMap = make(map[string]fn)
|
fnMap = make(map[string]fn)
|
||||||
// fnMap["darwin"] = wrapper("ps")
|
fnMap["darwin"] = wrapper("ps")
|
||||||
// fnMap["sunos"] = wrapper("ps")
|
fnMap["sunos"] = wrapper("ps")
|
||||||
// fnMap["freebsd"] = wrapper("ps")
|
fnMap["freebsd"] = wrapper("ps")
|
||||||
// fnMap["aix"] = wrapper("ps")
|
fnMap["aix"] = wrapper("ps")
|
||||||
// fnMap["linux"] = wrapper("proc")
|
fnMap["linux"] = wrapper("proc")
|
||||||
// fnMap["netbsd"] = wrapper("proc")
|
fnMap["netbsd"] = wrapper("proc")
|
||||||
// fnMap["win"] = wrapper("win")
|
fnMap["win"] = wrapper("win")
|
||||||
}
|
}
|
||||||
func formatStdOut(stdout []byte, userfulIndex int) []string {
|
func formatStdOut(stdout []byte, userfulIndex int) []string {
|
||||||
infoArr := strings.Split(string(stdout), "\n")[userfulIndex]
|
infoArr := strings.Split(string(stdout), eol)[userfulIndex]
|
||||||
ret := strings.Fields(infoArr)
|
ret := strings.Fields(infoArr)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
@ -76,7 +78,7 @@ func stat(pid int, statType string) *SysInfo {
|
||||||
stdout, _ := exec.Command("ps", args, strconv.Itoa(pid)).Output()
|
stdout, _ := exec.Command("ps", args, strconv.Itoa(pid)).Output()
|
||||||
ret := formatStdOut(stdout, 1)
|
ret := formatStdOut(stdout, 1)
|
||||||
sysInfo.CPU = parseFloat(ret[0])
|
sysInfo.CPU = parseFloat(ret[0])
|
||||||
sysInfo.Memory = parseFloat(ret[1])
|
sysInfo.Memory = parseFloat(ret[1]) * 1024
|
||||||
} else if statType == "proc" {
|
} else if statType == "proc" {
|
||||||
// default clkTck and pageSize
|
// default clkTck and pageSize
|
||||||
var clkTck float64 = 100
|
var clkTck float64 = 100
|
||||||
|
@ -84,7 +86,6 @@ func stat(pid int, statType string) *SysInfo {
|
||||||
|
|
||||||
uptimeFileBytes, err := ioutil.ReadFile(path.Join("/proc", "uptime"))
|
uptimeFileBytes, err := ioutil.ReadFile(path.Join("/proc", "uptime"))
|
||||||
uptime := parseFloat(strings.Split(string(uptimeFileBytes), " ")[0])
|
uptime := parseFloat(strings.Split(string(uptimeFileBytes), " ")[0])
|
||||||
fmt.Println("uptime", uptime)
|
|
||||||
|
|
||||||
clkTckStdout, err := exec.Command("getconf", "CLK_TCK").Output()
|
clkTckStdout, err := exec.Command("getconf", "CLK_TCK").Output()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -96,8 +97,6 @@ func stat(pid int, statType string) *SysInfo {
|
||||||
pageSize = parseFloat(formatStdOut(pageSizeStdout, 0)[0])
|
pageSize = parseFloat(formatStdOut(pageSizeStdout, 0)[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(clkTck, pageSize)
|
|
||||||
fmt.Println(path.Join("/proc", strconv.Itoa(pid), "stat"))
|
|
||||||
procStatFileBytes, err := ioutil.ReadFile(path.Join("/proc", strconv.Itoa(pid), "stat"))
|
procStatFileBytes, err := ioutil.ReadFile(path.Join("/proc", strconv.Itoa(pid), "stat"))
|
||||||
infos := strings.Split(strings.SplitAfter(string(procStatFileBytes), ")")[1], " ")
|
infos := strings.Split(strings.SplitAfter(string(procStatFileBytes), ")")[1], " ")
|
||||||
stat := &Stat{
|
stat := &Stat{
|
||||||
|
@ -112,18 +111,18 @@ func stat(pid int, statType string) *SysInfo {
|
||||||
|
|
||||||
_stime := 0.0
|
_stime := 0.0
|
||||||
_utime := 0.0
|
_utime := 0.0
|
||||||
if _history.stime != 0.0 {
|
if _history.stime != 0 {
|
||||||
_stime = _history.stime
|
_stime = _history.stime
|
||||||
}
|
}
|
||||||
|
|
||||||
if _history.utime != 0.0 {
|
if _history.utime != 0 {
|
||||||
_utime = _history.utime
|
_utime = _history.utime
|
||||||
}
|
}
|
||||||
total := stat.stime - _stime + stat.utime - _utime
|
total := stat.stime - _stime + stat.utime - _utime
|
||||||
total = total / clkTck
|
total = total / clkTck
|
||||||
|
|
||||||
seconds := stat.start - uptime
|
seconds := stat.start - uptime
|
||||||
if _history.uptime != 0.0 {
|
if _history.uptime != 0 {
|
||||||
seconds = uptime - _history.uptime
|
seconds = uptime - _history.uptime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +132,6 @@ func stat(pid int, statType string) *SysInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
history[pid] = *stat
|
history[pid] = *stat
|
||||||
fmt.Println(total)
|
|
||||||
sysInfo.CPU = (total / seconds) * 100
|
sysInfo.CPU = (total / seconds) * 100
|
||||||
sysInfo.Memory = stat.rss * pageSize
|
sysInfo.Memory = stat.rss * pageSize
|
||||||
}
|
}
|
||||||
|
@ -141,12 +139,8 @@ func stat(pid int, statType string) *SysInfo {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stat will return current system CPU and memory data
|
// GetStat will return current system CPU and memory data
|
||||||
// func Stat(pid int) *SysInfo {
|
func GetStat(pid int) *SysInfo {
|
||||||
// sysInfo := fnMap[platform](pid)
|
sysInfo := fnMap[platform](pid)
|
||||||
// return sysInfo
|
return sysInfo
|
||||||
// }
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
stat(662, "proc")
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue