process.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. package process
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "runtime"
  7. "sort"
  8. "sync"
  9. "syscall"
  10. "time"
  11. "github.com/shirou/gopsutil/cpu"
  12. "github.com/shirou/gopsutil/internal/common"
  13. "github.com/shirou/gopsutil/mem"
  14. "github.com/shirou/gopsutil/net"
  15. )
  16. var (
  17. invoke common.Invoker = common.Invoke{}
  18. ErrorNoChildren = errors.New("process does not have children")
  19. ErrorProcessNotRunning = errors.New("process does not exist")
  20. )
  21. type Process struct {
  22. Pid int32 `json:"pid"`
  23. name string
  24. status string
  25. parent int32
  26. parentMutex sync.RWMutex // for windows ppid cache
  27. numCtxSwitches *NumCtxSwitchesStat
  28. uids []int32
  29. gids []int32
  30. groups []int32
  31. numThreads int32
  32. memInfo *MemoryInfoStat
  33. sigInfo *SignalInfoStat
  34. createTime int64
  35. lastCPUTimes *cpu.TimesStat
  36. lastCPUTime time.Time
  37. tgid int32
  38. }
  39. type OpenFilesStat struct {
  40. Path string `json:"path"`
  41. Fd uint64 `json:"fd"`
  42. }
  43. type MemoryInfoStat struct {
  44. RSS uint64 `json:"rss"` // bytes
  45. VMS uint64 `json:"vms"` // bytes
  46. HWM uint64 `json:"hwm"` // bytes
  47. Data uint64 `json:"data"` // bytes
  48. Stack uint64 `json:"stack"` // bytes
  49. Locked uint64 `json:"locked"` // bytes
  50. Swap uint64 `json:"swap"` // bytes
  51. }
  52. type 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. type RlimitStat struct {
  60. Resource int32 `json:"resource"`
  61. Soft int32 `json:"soft"` //TODO too small. needs to be uint64
  62. Hard int32 `json:"hard"` //TODO too small. needs to be uint64
  63. Used uint64 `json:"used"`
  64. }
  65. type IOCountersStat struct {
  66. ReadCount uint64 `json:"readCount"`
  67. WriteCount uint64 `json:"writeCount"`
  68. ReadBytes uint64 `json:"readBytes"`
  69. WriteBytes uint64 `json:"writeBytes"`
  70. }
  71. type NumCtxSwitchesStat struct {
  72. Voluntary int64 `json:"voluntary"`
  73. Involuntary int64 `json:"involuntary"`
  74. }
  75. type PageFaultsStat struct {
  76. MinorFaults uint64 `json:"minorFaults"`
  77. MajorFaults uint64 `json:"majorFaults"`
  78. ChildMinorFaults uint64 `json:"childMinorFaults"`
  79. ChildMajorFaults uint64 `json:"childMajorFaults"`
  80. }
  81. // Resource limit constants are from /usr/include/x86_64-linux-gnu/bits/resource.h
  82. // from libc6-dev package in Ubuntu 16.10
  83. const (
  84. RLIMIT_CPU int32 = 0
  85. RLIMIT_FSIZE int32 = 1
  86. RLIMIT_DATA int32 = 2
  87. RLIMIT_STACK int32 = 3
  88. RLIMIT_CORE int32 = 4
  89. RLIMIT_RSS int32 = 5
  90. RLIMIT_NPROC int32 = 6
  91. RLIMIT_NOFILE int32 = 7
  92. RLIMIT_MEMLOCK int32 = 8
  93. RLIMIT_AS int32 = 9
  94. RLIMIT_LOCKS int32 = 10
  95. RLIMIT_SIGPENDING int32 = 11
  96. RLIMIT_MSGQUEUE int32 = 12
  97. RLIMIT_NICE int32 = 13
  98. RLIMIT_RTPRIO int32 = 14
  99. RLIMIT_RTTIME int32 = 15
  100. )
  101. func (p Process) String() string {
  102. s, _ := json.Marshal(p)
  103. return string(s)
  104. }
  105. func (o OpenFilesStat) String() string {
  106. s, _ := json.Marshal(o)
  107. return string(s)
  108. }
  109. func (m MemoryInfoStat) String() string {
  110. s, _ := json.Marshal(m)
  111. return string(s)
  112. }
  113. func (r RlimitStat) String() string {
  114. s, _ := json.Marshal(r)
  115. return string(s)
  116. }
  117. func (i IOCountersStat) String() string {
  118. s, _ := json.Marshal(i)
  119. return string(s)
  120. }
  121. func (p NumCtxSwitchesStat) String() string {
  122. s, _ := json.Marshal(p)
  123. return string(s)
  124. }
  125. // Pids returns a slice of process ID list which are running now.
  126. func Pids() ([]int32, error) {
  127. return PidsWithContext(context.Background())
  128. }
  129. func PidsWithContext(ctx context.Context) ([]int32, error) {
  130. pids, err := pidsWithContext(ctx)
  131. sort.Slice(pids, func(i, j int) bool { return pids[i] < pids[j] })
  132. return pids, err
  133. }
  134. // Processes returns a slice of pointers to Process structs for all
  135. // currently running processes.
  136. func Processes() ([]*Process, error) {
  137. return ProcessesWithContext(context.Background())
  138. }
  139. // NewProcess creates a new Process instance, it only stores the pid and
  140. // checks that the process exists. Other method on Process can be used
  141. // to get more information about the process. An error will be returned
  142. // if the process does not exist.
  143. func NewProcess(pid int32) (*Process, error) {
  144. return NewProcessWithContext(context.Background(), pid)
  145. }
  146. func NewProcessWithContext(ctx context.Context, pid int32) (*Process, error) {
  147. p := &Process{
  148. Pid: pid,
  149. }
  150. exists, err := PidExistsWithContext(ctx, pid)
  151. if err != nil {
  152. return p, err
  153. }
  154. if !exists {
  155. return p, ErrorProcessNotRunning
  156. }
  157. p.CreateTimeWithContext(ctx)
  158. return p, nil
  159. }
  160. func PidExists(pid int32) (bool, error) {
  161. return PidExistsWithContext(context.Background(), pid)
  162. }
  163. // Background returns true if the process is in background, false otherwise.
  164. func (p *Process) Background() (bool, error) {
  165. return p.BackgroundWithContext(context.Background())
  166. }
  167. func (p *Process) BackgroundWithContext(ctx context.Context) (bool, error) {
  168. fg, err := p.ForegroundWithContext(ctx)
  169. if err != nil {
  170. return false, err
  171. }
  172. return !fg, err
  173. }
  174. // If interval is 0, return difference from last call(non-blocking).
  175. // If interval > 0, wait interval sec and return diffrence between start and end.
  176. func (p *Process) Percent(interval time.Duration) (float64, error) {
  177. return p.PercentWithContext(context.Background(), interval)
  178. }
  179. func (p *Process) PercentWithContext(ctx context.Context, interval time.Duration) (float64, error) {
  180. cpuTimes, err := p.TimesWithContext(ctx)
  181. if err != nil {
  182. return 0, err
  183. }
  184. now := time.Now()
  185. if interval > 0 {
  186. p.lastCPUTimes = cpuTimes
  187. p.lastCPUTime = now
  188. if err := common.Sleep(ctx, interval); err != nil {
  189. return 0, err
  190. }
  191. cpuTimes, err = p.TimesWithContext(ctx)
  192. now = time.Now()
  193. if err != nil {
  194. return 0, err
  195. }
  196. } else {
  197. if p.lastCPUTimes == nil {
  198. // invoked first time
  199. p.lastCPUTimes = cpuTimes
  200. p.lastCPUTime = now
  201. return 0, nil
  202. }
  203. }
  204. numcpu := runtime.NumCPU()
  205. delta := (now.Sub(p.lastCPUTime).Seconds()) * float64(numcpu)
  206. ret := calculatePercent(p.lastCPUTimes, cpuTimes, delta, numcpu)
  207. p.lastCPUTimes = cpuTimes
  208. p.lastCPUTime = now
  209. return ret, nil
  210. }
  211. // IsRunning returns whether the process is still running or not.
  212. func (p *Process) IsRunning() (bool, error) {
  213. return p.IsRunningWithContext(context.Background())
  214. }
  215. func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
  216. createTime, err := p.CreateTimeWithContext(ctx)
  217. if err != nil {
  218. return false, err
  219. }
  220. p2, err := NewProcessWithContext(ctx, p.Pid)
  221. if err == ErrorProcessNotRunning {
  222. return false, nil
  223. }
  224. createTime2, err := p2.CreateTimeWithContext(ctx)
  225. if err != nil {
  226. return false, err
  227. }
  228. return createTime == createTime2, nil
  229. }
  230. // CreateTime returns created time of the process in milliseconds since the epoch, in UTC.
  231. func (p *Process) CreateTime() (int64, error) {
  232. return p.CreateTimeWithContext(context.Background())
  233. }
  234. func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
  235. if p.createTime != 0 {
  236. return p.createTime, nil
  237. }
  238. createTime, err := p.createTimeWithContext(ctx)
  239. p.createTime = createTime
  240. return p.createTime, err
  241. }
  242. func calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 {
  243. if delta == 0 {
  244. return 0
  245. }
  246. delta_proc := t2.Total() - t1.Total()
  247. overall_percent := ((delta_proc / delta) * 100) * float64(numcpu)
  248. return overall_percent
  249. }
  250. // MemoryPercent returns how many percent of the total RAM this process uses
  251. func (p *Process) MemoryPercent() (float32, error) {
  252. return p.MemoryPercentWithContext(context.Background())
  253. }
  254. func (p *Process) MemoryPercentWithContext(ctx context.Context) (float32, error) {
  255. machineMemory, err := mem.VirtualMemoryWithContext(ctx)
  256. if err != nil {
  257. return 0, err
  258. }
  259. total := machineMemory.Total
  260. processMemory, err := p.MemoryInfoWithContext(ctx)
  261. if err != nil {
  262. return 0, err
  263. }
  264. used := processMemory.RSS
  265. return (100 * float32(used) / float32(total)), nil
  266. }
  267. // CPU_Percent returns how many percent of the CPU time this process uses
  268. func (p *Process) CPUPercent() (float64, error) {
  269. return p.CPUPercentWithContext(context.Background())
  270. }
  271. func (p *Process) CPUPercentWithContext(ctx context.Context) (float64, error) {
  272. crt_time, err := p.createTimeWithContext(ctx)
  273. if err != nil {
  274. return 0, err
  275. }
  276. cput, err := p.TimesWithContext(ctx)
  277. if err != nil {
  278. return 0, err
  279. }
  280. created := time.Unix(0, crt_time*int64(time.Millisecond))
  281. totalTime := time.Since(created).Seconds()
  282. if totalTime <= 0 {
  283. return 0, nil
  284. }
  285. return 100 * cput.Total() / totalTime, nil
  286. }
  287. // Groups returns all group IDs(include supplementary groups) of the process as a slice of the int
  288. func (p *Process) Groups() ([]int32, error) {
  289. return p.GroupsWithContext(context.Background())
  290. }
  291. // Ppid returns Parent Process ID of the process.
  292. func (p *Process) Ppid() (int32, error) {
  293. return p.PpidWithContext(context.Background())
  294. }
  295. // Name returns name of the process.
  296. func (p *Process) Name() (string, error) {
  297. return p.NameWithContext(context.Background())
  298. }
  299. // Exe returns executable path of the process.
  300. func (p *Process) Exe() (string, error) {
  301. return p.ExeWithContext(context.Background())
  302. }
  303. // Cmdline returns the command line arguments of the process as a string with
  304. // each argument separated by 0x20 ascii character.
  305. func (p *Process) Cmdline() (string, error) {
  306. return p.CmdlineWithContext(context.Background())
  307. }
  308. // CmdlineSlice returns the command line arguments of the process as a slice with each
  309. // element being an argument.
  310. func (p *Process) CmdlineSlice() ([]string, error) {
  311. return p.CmdlineSliceWithContext(context.Background())
  312. }
  313. // Cwd returns current working directory of the process.
  314. func (p *Process) Cwd() (string, error) {
  315. return p.CwdWithContext(context.Background())
  316. }
  317. // Parent returns parent Process of the process.
  318. func (p *Process) Parent() (*Process, error) {
  319. return p.ParentWithContext(context.Background())
  320. }
  321. // Status returns the process status.
  322. // Return value could be one of these.
  323. // R: Running S: Sleep T: Stop I: Idle
  324. // Z: Zombie W: Wait L: Lock
  325. // The character is same within all supported platforms.
  326. func (p *Process) Status() (string, error) {
  327. return p.StatusWithContext(context.Background())
  328. }
  329. // Foreground returns true if the process is in foreground, false otherwise.
  330. func (p *Process) Foreground() (bool, error) {
  331. return p.ForegroundWithContext(context.Background())
  332. }
  333. // Uids returns user ids of the process as a slice of the int
  334. func (p *Process) Uids() ([]int32, error) {
  335. return p.UidsWithContext(context.Background())
  336. }
  337. // Gids returns group ids of the process as a slice of the int
  338. func (p *Process) Gids() ([]int32, error) {
  339. return p.GidsWithContext(context.Background())
  340. }
  341. // Terminal returns a terminal which is associated with the process.
  342. func (p *Process) Terminal() (string, error) {
  343. return p.TerminalWithContext(context.Background())
  344. }
  345. // Nice returns a nice value (priority).
  346. func (p *Process) Nice() (int32, error) {
  347. return p.NiceWithContext(context.Background())
  348. }
  349. // IOnice returns process I/O nice value (priority).
  350. func (p *Process) IOnice() (int32, error) {
  351. return p.IOniceWithContext(context.Background())
  352. }
  353. // Rlimit returns Resource Limits.
  354. func (p *Process) Rlimit() ([]RlimitStat, error) {
  355. return p.RlimitWithContext(context.Background())
  356. }
  357. // RlimitUsage returns Resource Limits.
  358. // If gatherUsed is true, the currently used value will be gathered and added
  359. // to the resulting RlimitStat.
  360. func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
  361. return p.RlimitUsageWithContext(context.Background(), gatherUsed)
  362. }
  363. // IOCounters returns IO Counters.
  364. func (p *Process) IOCounters() (*IOCountersStat, error) {
  365. return p.IOCountersWithContext(context.Background())
  366. }
  367. // NumCtxSwitches returns the number of the context switches of the process.
  368. func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
  369. return p.NumCtxSwitchesWithContext(context.Background())
  370. }
  371. // NumFDs returns the number of File Descriptors used by the process.
  372. func (p *Process) NumFDs() (int32, error) {
  373. return p.NumFDsWithContext(context.Background())
  374. }
  375. // NumThreads returns the number of threads used by the process.
  376. func (p *Process) NumThreads() (int32, error) {
  377. return p.NumThreadsWithContext(context.Background())
  378. }
  379. func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
  380. return p.ThreadsWithContext(context.Background())
  381. }
  382. // Times returns CPU times of the process.
  383. func (p *Process) Times() (*cpu.TimesStat, error) {
  384. return p.TimesWithContext(context.Background())
  385. }
  386. // CPUAffinity returns CPU affinity of the process.
  387. func (p *Process) CPUAffinity() ([]int32, error) {
  388. return p.CPUAffinityWithContext(context.Background())
  389. }
  390. // MemoryInfo returns generic process memory information,
  391. // such as RSS and VMS.
  392. func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
  393. return p.MemoryInfoWithContext(context.Background())
  394. }
  395. // MemoryInfoEx returns platform-specific process memory information.
  396. func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
  397. return p.MemoryInfoExWithContext(context.Background())
  398. }
  399. // PageFaultsInfo returns the process's page fault counters.
  400. func (p *Process) PageFaults() (*PageFaultsStat, error) {
  401. return p.PageFaultsWithContext(context.Background())
  402. }
  403. // Children returns the children of the process represented as a slice
  404. // of pointers to Process type.
  405. func (p *Process) Children() ([]*Process, error) {
  406. return p.ChildrenWithContext(context.Background())
  407. }
  408. // OpenFiles returns a slice of OpenFilesStat opend by the process.
  409. // OpenFilesStat includes a file path and file descriptor.
  410. func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
  411. return p.OpenFilesWithContext(context.Background())
  412. }
  413. // Connections returns a slice of net.ConnectionStat used by the process.
  414. // This returns all kind of the connection. This means TCP, UDP or UNIX.
  415. func (p *Process) Connections() ([]net.ConnectionStat, error) {
  416. return p.ConnectionsWithContext(context.Background())
  417. }
  418. // Connections returns a slice of net.ConnectionStat used by the process at most `max`.
  419. func (p *Process) ConnectionsMax(max int) ([]net.ConnectionStat, error) {
  420. return p.ConnectionsMaxWithContext(context.Background(), max)
  421. }
  422. // NetIOCounters returns NetIOCounters of the process.
  423. func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
  424. return p.NetIOCountersWithContext(context.Background(), pernic)
  425. }
  426. // MemoryMaps get memory maps from /proc/(pid)/smaps
  427. func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
  428. return p.MemoryMapsWithContext(context.Background(), grouped)
  429. }
  430. // Tgid returns thread group id of the process.
  431. func (p *Process) Tgid() (int32, error) {
  432. return p.TgidWithContext(context.Background())
  433. }
  434. // SendSignal sends a unix.Signal to the process.
  435. func (p *Process) SendSignal(sig syscall.Signal) error {
  436. return p.SendSignalWithContext(context.Background(), sig)
  437. }
  438. // Suspend sends SIGSTOP to the process.
  439. func (p *Process) Suspend() error {
  440. return p.SuspendWithContext(context.Background())
  441. }
  442. // Resume sends SIGCONT to the process.
  443. func (p *Process) Resume() error {
  444. return p.ResumeWithContext(context.Background())
  445. }
  446. // Terminate sends SIGTERM to the process.
  447. func (p *Process) Terminate() error {
  448. return p.TerminateWithContext(context.Background())
  449. }
  450. // Kill sends SIGKILL to the process.
  451. func (p *Process) Kill() error {
  452. return p.KillWithContext(context.Background())
  453. }
  454. // Username returns a username of the process.
  455. func (p *Process) Username() (string, error) {
  456. return p.UsernameWithContext(context.Background())
  457. }
  458. // Environ returns the environment variables of the process.
  459. func (p *Process) Environ() ([]string, error) {
  460. return p.EnvironWithContext(context.Background())
  461. }