1package process 2 3import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "runtime" 8 "time" 9 10 "github.com/shirou/gopsutil/cpu" 11 "github.com/shirou/gopsutil/internal/common" 12 "github.com/shirou/gopsutil/mem" 13) 14 15var ( 16 invoke common.Invoker = common.Invoke{} 17 ErrorNoChildren = errors.New("process does not have children") 18) 19 20type Process struct { 21 Pid int32 `json:"pid"` 22 name string 23 status string 24 parent int32 25 numCtxSwitches *NumCtxSwitchesStat 26 uids []int32 27 gids []int32 28 numThreads int32 29 memInfo *MemoryInfoStat 30 sigInfo *SignalInfoStat 31 32 lastCPUTimes *cpu.TimesStat 33 lastCPUTime time.Time 34 35 tgid int32 36} 37 38type OpenFilesStat struct { 39 Path string `json:"path"` 40 Fd uint64 `json:"fd"` 41} 42 43type MemoryInfoStat struct { 44 RSS uint64 `json:"rss"` // bytes 45 VMS uint64 `json:"vms"` // bytes 46 Data uint64 `json:"data"` // bytes 47 Stack uint64 `json:"stack"` // bytes 48 Locked uint64 `json:"locked"` // bytes 49 Swap uint64 `json:"swap"` // bytes 50} 51 52type SignalInfoStat struct { 53 PendingProcess uint64 `json:"pending_process"` 54 PendingThread uint64 `json:"pending_thread"` 55 Blocked uint64 `json:"blocked"` 56 Ignored uint64 `json:"ignored"` 57 Caught uint64 `json:"caught"` 58} 59 60type RlimitStat struct { 61 Resource int32 `json:"resource"` 62 Soft int32 `json:"soft"` //TODO too small. needs to be uint64 63 Hard int32 `json:"hard"` //TODO too small. needs to be uint64 64 Used uint64 `json:"used"` 65} 66 67type IOCountersStat struct { 68 ReadCount uint64 `json:"readCount"` 69 WriteCount uint64 `json:"writeCount"` 70 ReadBytes uint64 `json:"readBytes"` 71 WriteBytes uint64 `json:"writeBytes"` 72} 73 74type NumCtxSwitchesStat struct { 75 Voluntary int64 `json:"voluntary"` 76 Involuntary int64 `json:"involuntary"` 77} 78 79// Resource limit constants are from /usr/include/x86_64-linux-gnu/bits/resource.h 80// from libc6-dev package in Ubuntu 16.10 81const ( 82 RLIMIT_CPU int32 = 0 83 RLIMIT_FSIZE int32 = 1 84 RLIMIT_DATA int32 = 2 85 RLIMIT_STACK int32 = 3 86 RLIMIT_CORE int32 = 4 87 RLIMIT_RSS int32 = 5 88 RLIMIT_NPROC int32 = 6 89 RLIMIT_NOFILE int32 = 7 90 RLIMIT_MEMLOCK int32 = 8 91 RLIMIT_AS int32 = 9 92 RLIMIT_LOCKS int32 = 10 93 RLIMIT_SIGPENDING int32 = 11 94 RLIMIT_MSGQUEUE int32 = 12 95 RLIMIT_NICE int32 = 13 96 RLIMIT_RTPRIO int32 = 14 97 RLIMIT_RTTIME int32 = 15 98) 99 100func (p Process) String() string { 101 s, _ := json.Marshal(p) 102 return string(s) 103} 104 105func (o OpenFilesStat) String() string { 106 s, _ := json.Marshal(o) 107 return string(s) 108} 109 110func (m MemoryInfoStat) String() string { 111 s, _ := json.Marshal(m) 112 return string(s) 113} 114 115func (r RlimitStat) String() string { 116 s, _ := json.Marshal(r) 117 return string(s) 118} 119 120func (i IOCountersStat) String() string { 121 s, _ := json.Marshal(i) 122 return string(s) 123} 124 125func (p NumCtxSwitchesStat) String() string { 126 s, _ := json.Marshal(p) 127 return string(s) 128} 129 130func PidExists(pid int32) (bool, error) { 131 return PidExistsWithContext(context.Background(), pid) 132} 133 134func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) { 135 pids, err := Pids() 136 if err != nil { 137 return false, err 138 } 139 140 for _, i := range pids { 141 if i == pid { 142 return true, err 143 } 144 } 145 146 return false, err 147} 148 149// If interval is 0, return difference from last call(non-blocking). 150// If interval > 0, wait interval sec and return diffrence between start and end. 151func (p *Process) Percent(interval time.Duration) (float64, error) { 152 return p.PercentWithContext(context.Background(), interval) 153} 154 155func (p *Process) PercentWithContext(ctx context.Context, interval time.Duration) (float64, error) { 156 cpuTimes, err := p.Times() 157 if err != nil { 158 return 0, err 159 } 160 now := time.Now() 161 162 if interval > 0 { 163 p.lastCPUTimes = cpuTimes 164 p.lastCPUTime = now 165 time.Sleep(interval) 166 cpuTimes, err = p.Times() 167 now = time.Now() 168 if err != nil { 169 return 0, err 170 } 171 } else { 172 if p.lastCPUTimes == nil { 173 // invoked first time 174 p.lastCPUTimes = cpuTimes 175 p.lastCPUTime = now 176 return 0, nil 177 } 178 } 179 180 numcpu := runtime.NumCPU() 181 delta := (now.Sub(p.lastCPUTime).Seconds()) * float64(numcpu) 182 ret := calculatePercent(p.lastCPUTimes, cpuTimes, delta, numcpu) 183 p.lastCPUTimes = cpuTimes 184 p.lastCPUTime = now 185 return ret, nil 186} 187 188func calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 { 189 if delta == 0 { 190 return 0 191 } 192 delta_proc := t2.Total() - t1.Total() 193 overall_percent := ((delta_proc / delta) * 100) * float64(numcpu) 194 return overall_percent 195} 196 197// MemoryPercent returns how many percent of the total RAM this process uses 198func (p *Process) MemoryPercent() (float32, error) { 199 return p.MemoryPercentWithContext(context.Background()) 200} 201 202func (p *Process) MemoryPercentWithContext(ctx context.Context) (float32, error) { 203 machineMemory, err := mem.VirtualMemory() 204 if err != nil { 205 return 0, err 206 } 207 total := machineMemory.Total 208 209 processMemory, err := p.MemoryInfo() 210 if err != nil { 211 return 0, err 212 } 213 used := processMemory.RSS 214 215 return (100 * float32(used) / float32(total)), nil 216} 217 218// CPU_Percent returns how many percent of the CPU time this process uses 219func (p *Process) CPUPercent() (float64, error) { 220 return p.CPUPercentWithContext(context.Background()) 221} 222 223func (p *Process) CPUPercentWithContext(ctx context.Context) (float64, error) { 224 crt_time, err := p.CreateTime() 225 if err != nil { 226 return 0, err 227 } 228 229 cput, err := p.Times() 230 if err != nil { 231 return 0, err 232 } 233 234 created := time.Unix(0, crt_time*int64(time.Millisecond)) 235 totalTime := time.Since(created).Seconds() 236 if totalTime <= 0 { 237 return 0, nil 238 } 239 240 return 100 * cput.Total() / totalTime, nil 241} 242