| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549 |
- package process
- import (
- "context"
- "encoding/json"
- "errors"
- "runtime"
- "sort"
- "sync"
- "syscall"
- "time"
- "github.com/shirou/gopsutil/cpu"
- "github.com/shirou/gopsutil/internal/common"
- "github.com/shirou/gopsutil/mem"
- "github.com/shirou/gopsutil/net"
- )
- var (
- invoke common.Invoker = common.Invoke{}
- ErrorNoChildren = errors.New("process does not have children")
- ErrorProcessNotRunning = errors.New("process does not exist")
- )
- type Process struct {
- Pid int32 `json:"pid"`
- name string
- status string
- parent int32
- parentMutex sync.RWMutex // for windows ppid cache
- numCtxSwitches *NumCtxSwitchesStat
- uids []int32
- gids []int32
- groups []int32
- numThreads int32
- memInfo *MemoryInfoStat
- sigInfo *SignalInfoStat
- createTime int64
- lastCPUTimes *cpu.TimesStat
- lastCPUTime time.Time
- tgid int32
- }
- type OpenFilesStat struct {
- Path string `json:"path"`
- Fd uint64 `json:"fd"`
- }
- type MemoryInfoStat struct {
- RSS uint64 `json:"rss"` // bytes
- VMS uint64 `json:"vms"` // bytes
- HWM uint64 `json:"hwm"` // bytes
- Data uint64 `json:"data"` // bytes
- Stack uint64 `json:"stack"` // bytes
- Locked uint64 `json:"locked"` // bytes
- Swap uint64 `json:"swap"` // bytes
- }
- type SignalInfoStat struct {
- PendingProcess uint64 `json:"pending_process"`
- PendingThread uint64 `json:"pending_thread"`
- Blocked uint64 `json:"blocked"`
- Ignored uint64 `json:"ignored"`
- Caught uint64 `json:"caught"`
- }
- type RlimitStat struct {
- Resource int32 `json:"resource"`
- Soft int32 `json:"soft"` //TODO too small. needs to be uint64
- Hard int32 `json:"hard"` //TODO too small. needs to be uint64
- Used uint64 `json:"used"`
- }
- type IOCountersStat struct {
- ReadCount uint64 `json:"readCount"`
- WriteCount uint64 `json:"writeCount"`
- ReadBytes uint64 `json:"readBytes"`
- WriteBytes uint64 `json:"writeBytes"`
- }
- type NumCtxSwitchesStat struct {
- Voluntary int64 `json:"voluntary"`
- Involuntary int64 `json:"involuntary"`
- }
- type PageFaultsStat struct {
- MinorFaults uint64 `json:"minorFaults"`
- MajorFaults uint64 `json:"majorFaults"`
- ChildMinorFaults uint64 `json:"childMinorFaults"`
- ChildMajorFaults uint64 `json:"childMajorFaults"`
- }
- // Resource limit constants are from /usr/include/x86_64-linux-gnu/bits/resource.h
- // from libc6-dev package in Ubuntu 16.10
- const (
- RLIMIT_CPU int32 = 0
- RLIMIT_FSIZE int32 = 1
- RLIMIT_DATA int32 = 2
- RLIMIT_STACK int32 = 3
- RLIMIT_CORE int32 = 4
- RLIMIT_RSS int32 = 5
- RLIMIT_NPROC int32 = 6
- RLIMIT_NOFILE int32 = 7
- RLIMIT_MEMLOCK int32 = 8
- RLIMIT_AS int32 = 9
- RLIMIT_LOCKS int32 = 10
- RLIMIT_SIGPENDING int32 = 11
- RLIMIT_MSGQUEUE int32 = 12
- RLIMIT_NICE int32 = 13
- RLIMIT_RTPRIO int32 = 14
- RLIMIT_RTTIME int32 = 15
- )
- func (p Process) String() string {
- s, _ := json.Marshal(p)
- return string(s)
- }
- func (o OpenFilesStat) String() string {
- s, _ := json.Marshal(o)
- return string(s)
- }
- func (m MemoryInfoStat) String() string {
- s, _ := json.Marshal(m)
- return string(s)
- }
- func (r RlimitStat) String() string {
- s, _ := json.Marshal(r)
- return string(s)
- }
- func (i IOCountersStat) String() string {
- s, _ := json.Marshal(i)
- return string(s)
- }
- func (p NumCtxSwitchesStat) String() string {
- s, _ := json.Marshal(p)
- return string(s)
- }
- // Pids returns a slice of process ID list which are running now.
- func Pids() ([]int32, error) {
- return PidsWithContext(context.Background())
- }
- func PidsWithContext(ctx context.Context) ([]int32, error) {
- pids, err := pidsWithContext(ctx)
- sort.Slice(pids, func(i, j int) bool { return pids[i] < pids[j] })
- return pids, err
- }
- // Processes returns a slice of pointers to Process structs for all
- // currently running processes.
- func Processes() ([]*Process, error) {
- return ProcessesWithContext(context.Background())
- }
- // NewProcess creates a new Process instance, it only stores the pid and
- // checks that the process exists. Other method on Process can be used
- // to get more information about the process. An error will be returned
- // if the process does not exist.
- func NewProcess(pid int32) (*Process, error) {
- return NewProcessWithContext(context.Background(), pid)
- }
- func NewProcessWithContext(ctx context.Context, pid int32) (*Process, error) {
- p := &Process{
- Pid: pid,
- }
- exists, err := PidExistsWithContext(ctx, pid)
- if err != nil {
- return p, err
- }
- if !exists {
- return p, ErrorProcessNotRunning
- }
- p.CreateTimeWithContext(ctx)
- return p, nil
- }
- func PidExists(pid int32) (bool, error) {
- return PidExistsWithContext(context.Background(), pid)
- }
- // Background returns true if the process is in background, false otherwise.
- func (p *Process) Background() (bool, error) {
- return p.BackgroundWithContext(context.Background())
- }
- func (p *Process) BackgroundWithContext(ctx context.Context) (bool, error) {
- fg, err := p.ForegroundWithContext(ctx)
- if err != nil {
- return false, err
- }
- return !fg, err
- }
- // If interval is 0, return difference from last call(non-blocking).
- // If interval > 0, wait interval sec and return diffrence between start and end.
- func (p *Process) Percent(interval time.Duration) (float64, error) {
- return p.PercentWithContext(context.Background(), interval)
- }
- func (p *Process) PercentWithContext(ctx context.Context, interval time.Duration) (float64, error) {
- cpuTimes, err := p.TimesWithContext(ctx)
- if err != nil {
- return 0, err
- }
- now := time.Now()
- if interval > 0 {
- p.lastCPUTimes = cpuTimes
- p.lastCPUTime = now
- if err := common.Sleep(ctx, interval); err != nil {
- return 0, err
- }
- cpuTimes, err = p.TimesWithContext(ctx)
- now = time.Now()
- if err != nil {
- return 0, err
- }
- } else {
- if p.lastCPUTimes == nil {
- // invoked first time
- p.lastCPUTimes = cpuTimes
- p.lastCPUTime = now
- return 0, nil
- }
- }
- numcpu := runtime.NumCPU()
- delta := (now.Sub(p.lastCPUTime).Seconds()) * float64(numcpu)
- ret := calculatePercent(p.lastCPUTimes, cpuTimes, delta, numcpu)
- p.lastCPUTimes = cpuTimes
- p.lastCPUTime = now
- return ret, nil
- }
- // IsRunning returns whether the process is still running or not.
- func (p *Process) IsRunning() (bool, error) {
- return p.IsRunningWithContext(context.Background())
- }
- func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
- createTime, err := p.CreateTimeWithContext(ctx)
- if err != nil {
- return false, err
- }
- p2, err := NewProcessWithContext(ctx, p.Pid)
- if err == ErrorProcessNotRunning {
- return false, nil
- }
- createTime2, err := p2.CreateTimeWithContext(ctx)
- if err != nil {
- return false, err
- }
- return createTime == createTime2, nil
- }
- // CreateTime returns created time of the process in milliseconds since the epoch, in UTC.
- func (p *Process) CreateTime() (int64, error) {
- return p.CreateTimeWithContext(context.Background())
- }
- func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
- if p.createTime != 0 {
- return p.createTime, nil
- }
- createTime, err := p.createTimeWithContext(ctx)
- p.createTime = createTime
- return p.createTime, err
- }
- func calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 {
- if delta == 0 {
- return 0
- }
- delta_proc := t2.Total() - t1.Total()
- overall_percent := ((delta_proc / delta) * 100) * float64(numcpu)
- return overall_percent
- }
- // MemoryPercent returns how many percent of the total RAM this process uses
- func (p *Process) MemoryPercent() (float32, error) {
- return p.MemoryPercentWithContext(context.Background())
- }
- func (p *Process) MemoryPercentWithContext(ctx context.Context) (float32, error) {
- machineMemory, err := mem.VirtualMemoryWithContext(ctx)
- if err != nil {
- return 0, err
- }
- total := machineMemory.Total
- processMemory, err := p.MemoryInfoWithContext(ctx)
- if err != nil {
- return 0, err
- }
- used := processMemory.RSS
- return (100 * float32(used) / float32(total)), nil
- }
- // CPU_Percent returns how many percent of the CPU time this process uses
- func (p *Process) CPUPercent() (float64, error) {
- return p.CPUPercentWithContext(context.Background())
- }
- func (p *Process) CPUPercentWithContext(ctx context.Context) (float64, error) {
- crt_time, err := p.createTimeWithContext(ctx)
- if err != nil {
- return 0, err
- }
- cput, err := p.TimesWithContext(ctx)
- if err != nil {
- return 0, err
- }
- created := time.Unix(0, crt_time*int64(time.Millisecond))
- totalTime := time.Since(created).Seconds()
- if totalTime <= 0 {
- return 0, nil
- }
- return 100 * cput.Total() / totalTime, nil
- }
- // Groups returns all group IDs(include supplementary groups) of the process as a slice of the int
- func (p *Process) Groups() ([]int32, error) {
- return p.GroupsWithContext(context.Background())
- }
- // Ppid returns Parent Process ID of the process.
- func (p *Process) Ppid() (int32, error) {
- return p.PpidWithContext(context.Background())
- }
- // Name returns name of the process.
- func (p *Process) Name() (string, error) {
- return p.NameWithContext(context.Background())
- }
- // Exe returns executable path of the process.
- func (p *Process) Exe() (string, error) {
- return p.ExeWithContext(context.Background())
- }
- // Cmdline returns the command line arguments of the process as a string with
- // each argument separated by 0x20 ascii character.
- func (p *Process) Cmdline() (string, error) {
- return p.CmdlineWithContext(context.Background())
- }
- // CmdlineSlice returns the command line arguments of the process as a slice with each
- // element being an argument.
- func (p *Process) CmdlineSlice() ([]string, error) {
- return p.CmdlineSliceWithContext(context.Background())
- }
- // Cwd returns current working directory of the process.
- func (p *Process) Cwd() (string, error) {
- return p.CwdWithContext(context.Background())
- }
- // Parent returns parent Process of the process.
- func (p *Process) Parent() (*Process, error) {
- return p.ParentWithContext(context.Background())
- }
- // Status returns the process status.
- // Return value could be one of these.
- // R: Running S: Sleep T: Stop I: Idle
- // Z: Zombie W: Wait L: Lock
- // The character is same within all supported platforms.
- func (p *Process) Status() (string, error) {
- return p.StatusWithContext(context.Background())
- }
- // Foreground returns true if the process is in foreground, false otherwise.
- func (p *Process) Foreground() (bool, error) {
- return p.ForegroundWithContext(context.Background())
- }
- // Uids returns user ids of the process as a slice of the int
- func (p *Process) Uids() ([]int32, error) {
- return p.UidsWithContext(context.Background())
- }
- // Gids returns group ids of the process as a slice of the int
- func (p *Process) Gids() ([]int32, error) {
- return p.GidsWithContext(context.Background())
- }
- // Terminal returns a terminal which is associated with the process.
- func (p *Process) Terminal() (string, error) {
- return p.TerminalWithContext(context.Background())
- }
- // Nice returns a nice value (priority).
- func (p *Process) Nice() (int32, error) {
- return p.NiceWithContext(context.Background())
- }
- // IOnice returns process I/O nice value (priority).
- func (p *Process) IOnice() (int32, error) {
- return p.IOniceWithContext(context.Background())
- }
- // Rlimit returns Resource Limits.
- func (p *Process) Rlimit() ([]RlimitStat, error) {
- return p.RlimitWithContext(context.Background())
- }
- // RlimitUsage returns Resource Limits.
- // If gatherUsed is true, the currently used value will be gathered and added
- // to the resulting RlimitStat.
- func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
- return p.RlimitUsageWithContext(context.Background(), gatherUsed)
- }
- // IOCounters returns IO Counters.
- func (p *Process) IOCounters() (*IOCountersStat, error) {
- return p.IOCountersWithContext(context.Background())
- }
- // NumCtxSwitches returns the number of the context switches of the process.
- func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
- return p.NumCtxSwitchesWithContext(context.Background())
- }
- // NumFDs returns the number of File Descriptors used by the process.
- func (p *Process) NumFDs() (int32, error) {
- return p.NumFDsWithContext(context.Background())
- }
- // NumThreads returns the number of threads used by the process.
- func (p *Process) NumThreads() (int32, error) {
- return p.NumThreadsWithContext(context.Background())
- }
- func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
- return p.ThreadsWithContext(context.Background())
- }
- // Times returns CPU times of the process.
- func (p *Process) Times() (*cpu.TimesStat, error) {
- return p.TimesWithContext(context.Background())
- }
- // CPUAffinity returns CPU affinity of the process.
- func (p *Process) CPUAffinity() ([]int32, error) {
- return p.CPUAffinityWithContext(context.Background())
- }
- // MemoryInfo returns generic process memory information,
- // such as RSS and VMS.
- func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
- return p.MemoryInfoWithContext(context.Background())
- }
- // MemoryInfoEx returns platform-specific process memory information.
- func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
- return p.MemoryInfoExWithContext(context.Background())
- }
- // PageFaultsInfo returns the process's page fault counters.
- func (p *Process) PageFaults() (*PageFaultsStat, error) {
- return p.PageFaultsWithContext(context.Background())
- }
- // Children returns the children of the process represented as a slice
- // of pointers to Process type.
- func (p *Process) Children() ([]*Process, error) {
- return p.ChildrenWithContext(context.Background())
- }
- // OpenFiles returns a slice of OpenFilesStat opend by the process.
- // OpenFilesStat includes a file path and file descriptor.
- func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
- return p.OpenFilesWithContext(context.Background())
- }
- // Connections returns a slice of net.ConnectionStat used by the process.
- // This returns all kind of the connection. This means TCP, UDP or UNIX.
- func (p *Process) Connections() ([]net.ConnectionStat, error) {
- return p.ConnectionsWithContext(context.Background())
- }
- // Connections returns a slice of net.ConnectionStat used by the process at most `max`.
- func (p *Process) ConnectionsMax(max int) ([]net.ConnectionStat, error) {
- return p.ConnectionsMaxWithContext(context.Background(), max)
- }
- // NetIOCounters returns NetIOCounters of the process.
- func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
- return p.NetIOCountersWithContext(context.Background(), pernic)
- }
- // MemoryMaps get memory maps from /proc/(pid)/smaps
- func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
- return p.MemoryMapsWithContext(context.Background(), grouped)
- }
- // Tgid returns thread group id of the process.
- func (p *Process) Tgid() (int32, error) {
- return p.TgidWithContext(context.Background())
- }
- // SendSignal sends a unix.Signal to the process.
- func (p *Process) SendSignal(sig syscall.Signal) error {
- return p.SendSignalWithContext(context.Background(), sig)
- }
- // Suspend sends SIGSTOP to the process.
- func (p *Process) Suspend() error {
- return p.SuspendWithContext(context.Background())
- }
- // Resume sends SIGCONT to the process.
- func (p *Process) Resume() error {
- return p.ResumeWithContext(context.Background())
- }
- // Terminate sends SIGTERM to the process.
- func (p *Process) Terminate() error {
- return p.TerminateWithContext(context.Background())
- }
- // Kill sends SIGKILL to the process.
- func (p *Process) Kill() error {
- return p.KillWithContext(context.Background())
- }
- // Username returns a username of the process.
- func (p *Process) Username() (string, error) {
- return p.UsernameWithContext(context.Background())
- }
- // Environ returns the environment variables of the process.
- func (p *Process) Environ() ([]string, error) {
- return p.EnvironWithContext(context.Background())
- }
|