This repository was archived by the owner on Nov 3, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpid_usage.go
159 lines (137 loc) · 3.65 KB
/
pid_usage.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package tester
// The file is originally copied from https://github.com/struCoder/pidusage/blob/master/pidusage.go
import (
"errors"
"io/ioutil"
"math"
"os/exec"
"path"
"runtime"
"strconv"
"strings"
"sync"
)
type SysInfo struct {
CPU float64
Memory float64
}
type Stat struct {
utime float64
stime float64
cutime float64
cstime float64
start float64
rss float64
uptime float64
}
type fn func(int) (*SysInfo, error)
var (
fnMap map[string]fn
platform string
history map[int]Stat
historyLock sync.Mutex
eol string
)
func wrapper(statType string) func(pid int) (*SysInfo, error) {
return func(pid int) (*SysInfo, error) {
return stat(pid, statType)
}
}
func init() {
platform = runtime.GOOS
if eol = "\n"; strings.Index(platform, "win") == 0 {
platform = "win"
eol = "\r\n"
}
history = make(map[int]Stat)
fnMap = make(map[string]fn)
fnMap["darwin"] = wrapper("ps")
fnMap["sunos"] = wrapper("ps")
fnMap["freebsd"] = wrapper("ps")
fnMap["aix"] = wrapper("ps")
fnMap["linux"] = wrapper("proc")
fnMap["netbsd"] = wrapper("proc")
//fnMap["win"] = wrapper("win")
}
func formatStdOut(stdout []byte, userfulIndex int) []string {
infoArr := strings.Split(string(stdout), eol)[userfulIndex]
ret := strings.Fields(infoArr)
return ret
}
func parseFloat(val string) float64 {
floatVal, _ := strconv.ParseFloat(val, 64)
return floatVal
}
func stat(pid int, statType string) (*SysInfo, error) {
sysInfo := &SysInfo{}
_history := history[pid]
if statType == "ps" {
args := "-o pcpu,rss -p"
if platform == "aix" {
args = "-o pcpu,rssize -p"
}
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" {
var clkTck float64 = 100
var pageSize float64 = 4096
uptimeFileBytes, err := ioutil.ReadFile(path.Join("/proc", "uptime"))
uptime := parseFloat(strings.Split(string(uptimeFileBytes), " ")[0])
clkTckStdout, err := exec.Command("getconf", "CLK_TCK").Output()
if err == nil {
clkTck = parseFloat(formatStdOut(clkTckStdout, 0)[0])
}
pageSizeStdout, err := exec.Command("getconf", "PAGESIZE").Output()
if err == nil {
pageSize = parseFloat(formatStdOut(pageSizeStdout, 0)[0])
}
procStatFileBytes, err := ioutil.ReadFile(path.Join("/proc", strconv.Itoa(pid), "stat"))
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]),
cutime: parseFloat(infos[14]),
cstime: parseFloat(infos[15]),
start: parseFloat(infos[20]) / clkTck,
rss: parseFloat(infos[22]),
uptime: uptime,
}
_stime := 0.0
_utime := 0.0
if _history.stime != 0 {
_stime = _history.stime
}
if _history.utime != 0 {
_utime = _history.utime
}
total := stat.stime - _stime + stat.utime - _utime
total = total / clkTck
seconds := stat.start - uptime
if _history.uptime != 0 {
seconds = uptime - _history.uptime
}
seconds = math.Abs(seconds)
if seconds == 0 {
seconds = 1
}
historyLock.Lock()
history[pid] = *stat
historyLock.Unlock()
sysInfo.CPU = (total / seconds) * 100
sysInfo.Memory = stat.rss * pageSize
}
return sysInfo, nil
}
func GetStat(pid int) (*SysInfo, error) {
sysInfo, err := fnMap[platform](pid)
return sysInfo, err
}