Merge branch 'master' into refactor/parentwithcontext-ppidwithcontext

pull/1235/head
shirou 3 years ago committed by GitHub
commit 50cad0760c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -3,11 +3,11 @@ module github.com/shirou/gopsutil/v3
go 1.15 go 1.15
require ( require (
github.com/google/go-cmp v0.5.6 github.com/google/go-cmp v0.5.7
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/tklauser/go-sysconf v0.3.9 github.com/tklauser/go-sysconf v0.3.9
github.com/yusufpapurcu/wmi v1.2.2 github.com/yusufpapurcu/wmi v1.2.2
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c golang.org/x/sys v0.0.0-20220111092808-5a964db01320
) )

@ -2,12 +2,11 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -26,8 +25,8 @@ github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8= golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

@ -283,7 +283,7 @@ func PlatformInformationWithContext(ctx context.Context) (platform string, famil
family = "debian" family = "debian"
case "fedora": case "fedora":
family = "fedora" family = "fedora"
case "oracle", "centos", "redhat", "scientific", "enterpriseenterprise", "amazon", "xenserver", "cloudlinux", "ibm_powerkvm", "rocky": case "oracle", "centos", "redhat", "scientific", "enterpriseenterprise", "amazon", "xenserver", "cloudlinux", "ibm_powerkvm", "rocky", "almalinux":
family = "rhel" family = "rhel"
case "suse", "opensuse", "opensuse-leap", "opensuse-tumbleweed", "opensuse-tumbleweed-kubic", "sles", "sled", "caasp": case "suse", "opensuse", "opensuse-leap", "opensuse-tumbleweed", "opensuse-tumbleweed-kubic", "sles", "sled", "caasp":
family = "suse" family = "suse"

@ -10,9 +10,7 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/internal/common"
"github.com/shirou/gopsutil/v3/net" "github.com/shirou/gopsutil/v3/net"
"github.com/tklauser/go-sysconf" "github.com/tklauser/go-sysconf"
@ -46,34 +44,25 @@ type _Ctype_struct___0 struct {
func pidsWithContext(ctx context.Context) ([]int32, error) { func pidsWithContext(ctx context.Context) ([]int32, error) {
var ret []int32 var ret []int32
pids, err := callPsWithContext(ctx, "pid", 0, false, false) kprocs, err := unix.SysctlKinfoProcSlice("kern.proc.all")
if err != nil { if err != nil {
return ret, err return ret, err
} }
for _, pid := range pids { for _, proc := range kprocs {
v, err := strconv.Atoi(pid[0]) ret = append(ret, int32(proc.Proc.P_pid))
if err != nil {
return ret, err
}
ret = append(ret, int32(v))
} }
return ret, nil return ret, nil
} }
func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
r, err := callPsWithContext(ctx, "ppid", p.Pid, false, false) k, err := p.getKProc()
if err != nil {
return 0, err
}
v, err := strconv.Atoi(r[0][0])
if err != nil { if err != nil {
return 0, err return 0, err
} }
return int32(v), err return k.Eproc.Ppid, nil
} }
func (p *Process) NameWithContext(ctx context.Context) (string, error) { func (p *Process) NameWithContext(ctx context.Context) (string, error) {
@ -81,7 +70,8 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
name := common.IntToString(k.Proc.P_comm[:])
name := common.ByteToString(k.Proc.P_comm[:])
if len(name) >= 15 { if len(name) >= 15 {
cmdName, err := p.cmdNameWithContext(ctx) cmdName, err := p.cmdNameWithContext(ctx)
@ -89,11 +79,11 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) {
return "", err return "", err
} }
if len(cmdName) > 0 { if len(cmdName) > 0 {
extendedName := filepath.Base(cmdName[0]) extendedName := filepath.Base(cmdName)
if strings.HasPrefix(extendedName, p.name) { if strings.HasPrefix(extendedName, p.name) {
name = extendedName name = extendedName
} else { } else {
name = cmdName[0] name = cmdName
} }
} }
} }
@ -101,44 +91,13 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) {
return name, nil return name, nil
} }
// cmdNameWithContext returns the command name (including spaces) without any arguments
func (p *Process) cmdNameWithContext(ctx context.Context) ([]string, error) {
r, err := callPsWithContext(ctx, "command", p.Pid, false, true)
if err != nil {
return nil, err
}
return r[0], err
}
func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
r, err := callPsWithContext(ctx, "etime", p.Pid, false, false) k, err := p.getKProc()
if err != nil {
return 0, err
}
elapsedSegments := strings.Split(strings.Replace(r[0][0], "-", ":", 1), ":")
var elapsedDurations []time.Duration
for i := len(elapsedSegments) - 1; i >= 0; i-- {
p, err := strconv.ParseInt(elapsedSegments[i], 10, 0)
if err != nil { if err != nil {
return 0, err return 0, err
} }
elapsedDurations = append(elapsedDurations, time.Duration(p))
}
elapsed := time.Duration(elapsedDurations[0]) * time.Second return k.Proc.P_starttime.Sec*1000 + int64(k.Proc.P_starttime.Usec)/1000, nil
if len(elapsedDurations) > 1 {
elapsed += time.Duration(elapsedDurations[1]) * time.Minute
}
if len(elapsedDurations) > 2 {
elapsed += time.Duration(elapsedDurations[2]) * time.Hour
}
if len(elapsedDurations) > 3 {
elapsed += time.Duration(elapsedDurations[3]) * time.Hour * 24
}
start := time.Now().Add(-elapsed)
return start.Unix() * 1000, nil
} }
func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) { func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {
@ -171,7 +130,7 @@ func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
} }
// See: http://unix.superglobalmegacorp.com/Net2/newsrc/sys/ucred.h.html // See: http://unix.superglobalmegacorp.com/Net2/newsrc/sys/ucred.h.html
userEffectiveUID := int32(k.Eproc.Ucred.UID) userEffectiveUID := int32(k.Eproc.Ucred.Uid)
return []int32{userEffectiveUID}, nil return []int32{userEffectiveUID}, nil
} }
@ -183,7 +142,7 @@ func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
} }
gids := make([]int32, 0, 3) gids := make([]int32, 0, 3)
gids = append(gids, int32(k.Eproc.Pcred.P_rgid), int32(k.Eproc.Ucred.Ngroups), int32(k.Eproc.Pcred.P_svgid)) gids = append(gids, int32(k.Eproc.Pcred.P_rgid), int32(k.Eproc.Pcred.P_rgid), int32(k.Eproc.Pcred.P_svgid))
return gids, nil return gids, nil
} }
@ -233,14 +192,6 @@ func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, e
return nil, common.ErrNotImplementedError return nil, common.ErrNotImplementedError
} }
func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
r, err := callPsWithContext(ctx, "utime,stime", p.Pid, true, false)
if err != nil {
return 0, err
}
return int32(len(r)), nil
}
func convertCPUTimes(s string) (ret float64, err error) { func convertCPUTimes(s string) (ret float64, err error) {
var t int var t int
var _tmp string var _tmp string
@ -287,56 +238,6 @@ func convertCPUTimes(s string) (ret float64, err error) {
return float64(t) / float64(clockTicks), nil return float64(t) / float64(clockTicks), nil
} }
func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
r, err := callPsWithContext(ctx, "utime,stime", p.Pid, false, false)
if err != nil {
return nil, err
}
utime, err := convertCPUTimes(r[0][0])
if err != nil {
return nil, err
}
stime, err := convertCPUTimes(r[0][1])
if err != nil {
return nil, err
}
ret := &cpu.TimesStat{
CPU: "cpu",
User: utime,
System: stime,
}
return ret, nil
}
func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
r, err := callPsWithContext(ctx, "rss,vsize,pagein", p.Pid, false, false)
if err != nil {
return nil, err
}
rss, err := strconv.Atoi(r[0][0])
if err != nil {
return nil, err
}
vms, err := strconv.Atoi(r[0][1])
if err != nil {
return nil, err
}
pagein, err := strconv.Atoi(r[0][2])
if err != nil {
return nil, err
}
ret := &MemoryInfoStat{
RSS: uint64(rss) * 1024,
VMS: uint64(vms) * 1024,
Swap: uint64(pagein),
}
return ret, nil
}
func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid) pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid)
if err != nil { if err != nil {
@ -382,17 +283,8 @@ func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
// Returns a proc as defined here: // Returns a proc as defined here:
// http://unix.superglobalmegacorp.com/Net2/newsrc/sys/kinfo_proc.h.html // http://unix.superglobalmegacorp.com/Net2/newsrc/sys/kinfo_proc.h.html
func (p *Process) getKProc() (*KinfoProc, error) { func (p *Process) getKProc() (*unix.KinfoProc, error) {
buf, err := unix.SysctlRaw("kern.proc.pid", int(p.Pid)) return unix.SysctlKinfoProc("kern.proc.pid", int(p.Pid))
if err != nil {
return nil, err
}
k, err := parseKinfoProc(buf)
if err != nil {
return nil, err
}
return &k, nil
} }
// call ps command. // call ps command.

@ -9,6 +9,7 @@ package process
// #include <sys/errno.h> // #include <sys/errno.h>
// #include <sys/proc_info.h> // #include <sys/proc_info.h>
// #include <sys/sysctl.h> // #include <sys/sysctl.h>
// #include <mach/mach_time.h>
import "C" import "C"
import ( import (
@ -18,12 +19,18 @@ import (
"strings" "strings"
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/shirou/gopsutil/v3/cpu"
) )
var argMax int var (
argMax int
timescaleToNanoSeconds float64
)
func init() { func init() {
argMax = getArgMax() argMax = getArgMax()
timescaleToNanoSeconds = getTimeScaleToNanoSeconds()
} }
func getArgMax() int { func getArgMax() int {
@ -39,6 +46,14 @@ func getArgMax() int {
return 0 return 0
} }
func getTimeScaleToNanoSeconds() float64 {
var timeBaseInfo C.struct_mach_timebase_info
C.mach_timebase_info(&timeBaseInfo)
return float64(timeBaseInfo.numer) / float64(timeBaseInfo.denom)
}
func (p *Process) ExeWithContext(ctx context.Context) (string, error) { func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
var c C.char // need a var for unsafe.Sizeof need a var var c C.char // need a var for unsafe.Sizeof need a var
const bufsize = C.PROC_PIDPATHINFO_MAXSIZE * unsafe.Sizeof(c) const bufsize = C.PROC_PIDPATHINFO_MAXSIZE * unsafe.Sizeof(c)
@ -82,7 +97,7 @@ func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
return C.GoString(&vpi.pvi_cdir.vip_path[0]), err return C.GoString(&vpi.pvi_cdir.vip_path[0]), err
} }
func procArgs(pid int32) (*[]byte, int, error) { func procArgs(pid int32) ([]byte, int, error) {
var ( var (
mib = [...]C.int{C.CTL_KERN, C.KERN_PROCARGS2, C.int(pid)} mib = [...]C.int{C.CTL_KERN, C.KERN_PROCARGS2, C.int(pid)}
size C.size_t = C.ulong(argMax) size C.size_t = C.ulong(argMax)
@ -91,23 +106,27 @@ func procArgs(pid int32) (*[]byte, int, error) {
) )
procargs := (*C.char)(C.malloc(C.ulong(argMax))) procargs := (*C.char)(C.malloc(C.ulong(argMax)))
defer C.free(unsafe.Pointer(procargs)) defer C.free(unsafe.Pointer(procargs))
retval := C.sysctl(&mib[0], 3, unsafe.Pointer(procargs), &size, C.NULL, 0) retval, err := C.sysctl(&mib[0], 3, unsafe.Pointer(procargs), &size, C.NULL, 0)
if retval == 0 { if retval == 0 {
C.memcpy(unsafe.Pointer(&nargs), unsafe.Pointer(procargs), C.sizeof_int) C.memcpy(unsafe.Pointer(&nargs), unsafe.Pointer(procargs), C.sizeof_int)
result = C.GoBytes(unsafe.Pointer(procargs), C.int(size)) result = C.GoBytes(unsafe.Pointer(procargs), C.int(size))
// fmt.Printf("size: %d %d\n%s\n", size, nargs, hex.Dump(result)) // fmt.Printf("size: %d %d\n%s\n", size, nargs, hex.Dump(result))
return &result, int(nargs), nil return result, int(nargs), nil
} }
return nil, 0, fmt.Errorf("error: %d", retval) return nil, 0, err
} }
func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
return p.cmdlineSliceWithContext(ctx, true)
}
func (p *Process) cmdlineSliceWithContext(ctx context.Context, fallback bool) ([]string, error) {
pargs, nargs, err := procArgs(p.Pid) pargs, nargs, err := procArgs(p.Pid)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// The first bytes hold the nargs int, skip it. // The first bytes hold the nargs int, skip it.
args := bytes.Split((*pargs)[C.sizeof_int:], []byte{0}) args := bytes.Split((pargs)[C.sizeof_int:], []byte{0})
var argStr string var argStr string
// The first element is the actual binary/command path. // The first element is the actual binary/command path.
// command := args[0] // command := args[0]
@ -131,6 +150,20 @@ func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error)
return argSlice, err return argSlice, err
} }
// cmdNameWithContext returns the command name (including spaces) without any arguments
func (p *Process) cmdNameWithContext(ctx context.Context) (string, error) {
r, err := p.cmdlineSliceWithContext(ctx, false)
if err != nil {
return "", err
}
if len(r) == 0 {
return "", nil
}
return r[0], err
}
func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
r, err := p.CmdlineSliceWithContext(ctx) r, err := p.CmdlineSliceWithContext(ctx)
if err != nil { if err != nil {
@ -138,3 +171,49 @@ func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
} }
return strings.Join(r, " "), err return strings.Join(r, " "), err
} }
func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
const tiSize = C.sizeof_struct_proc_taskinfo
ti := (*C.struct_proc_taskinfo)(C.malloc(tiSize))
_, err := C.proc_pidinfo(C.int(p.Pid), C.PROC_PIDTASKINFO, 0, unsafe.Pointer(ti), tiSize)
if err != nil {
return 0, err
}
return int32(ti.pti_threadnum), nil
}
func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
const tiSize = C.sizeof_struct_proc_taskinfo
ti := (*C.struct_proc_taskinfo)(C.malloc(tiSize))
_, err := C.proc_pidinfo(C.int(p.Pid), C.PROC_PIDTASKINFO, 0, unsafe.Pointer(ti), tiSize)
if err != nil {
return nil, err
}
ret := &cpu.TimesStat{
CPU: "cpu",
User: float64(ti.pti_total_user) * timescaleToNanoSeconds / 1e9,
System: float64(ti.pti_total_system) * timescaleToNanoSeconds / 1e9,
}
return ret, nil
}
func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
const tiSize = C.sizeof_struct_proc_taskinfo
ti := (*C.struct_proc_taskinfo)(C.malloc(tiSize))
_, err := C.proc_pidinfo(C.int(p.Pid), C.PROC_PIDTASKINFO, 0, unsafe.Pointer(ti), tiSize)
if err != nil {
return nil, err
}
ret := &MemoryInfoStat{
RSS: uint64(ti.pti_resident_size),
VMS: uint64(ti.pti_virtual_size),
Swap: uint64(ti.pti_pageins),
}
return ret, nil
}

@ -10,6 +10,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/internal/common"
) )
@ -47,6 +48,18 @@ func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
return strings.Join(r[0], " "), err return strings.Join(r[0], " "), err
} }
func (p *Process) cmdNameWithContext(ctx context.Context) (string, error) {
r, err := callPsWithContext(ctx, "command", p.Pid, false, true)
if err != nil {
return "", err
}
if len(r) > 0 && len(r[0]) > 0 {
return r[0][0], err
}
return "", err
}
// CmdlineSliceWithContext returns the command line arguments of the process as a slice with each // CmdlineSliceWithContext returns the command line arguments of the process as a slice with each
// element being an argument. Because of current deficiencies in the way that the command // element being an argument. Because of current deficiencies in the way that the command
// line arguments are found, single arguments that have spaces in the will actually be // line arguments are found, single arguments that have spaces in the will actually be
@ -59,3 +72,61 @@ func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error)
} }
return r[0], err return r[0], err
} }
func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
r, err := callPsWithContext(ctx, "utime,stime", p.Pid, true, false)
if err != nil {
return 0, err
}
return int32(len(r)), nil
}
func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
r, err := callPsWithContext(ctx, "utime,stime", p.Pid, false, false)
if err != nil {
return nil, err
}
utime, err := convertCPUTimes(r[0][0])
if err != nil {
return nil, err
}
stime, err := convertCPUTimes(r[0][1])
if err != nil {
return nil, err
}
ret := &cpu.TimesStat{
CPU: "cpu",
User: utime,
System: stime,
}
return ret, nil
}
func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
r, err := callPsWithContext(ctx, "rss,vsize,pagein", p.Pid, false, false)
if err != nil {
return nil, err
}
rss, err := strconv.Atoi(r[0][0])
if err != nil {
return nil, err
}
vms, err := strconv.Atoi(r[0][1])
if err != nil {
return nil, err
}
pagein, err := strconv.Atoi(r[0][2])
if err != nil {
return nil, err
}
ret := &MemoryInfoStat{
RSS: uint64(rss) * 1024,
VMS: uint64(vms) * 1024,
Swap: uint64(pagein),
}
return ret, nil
}

@ -340,11 +340,11 @@ func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, e
func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid) pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid)
if err != nil { if err != nil {
return nil, err
}
if len(pids) == 0 { if len(pids) == 0 {
return nil, ErrorNoChildren return nil, ErrorNoChildren
} }
return nil, err
}
ret := make([]*Process, 0, len(pids)) ret := make([]*Process, 0, len(pids))
for _, pid := range pids { for _, pid := range pids {
np, err := NewProcessWithContext(ctx, pid) np, err := NewProcessWithContext(ctx, pid)

@ -46,26 +46,6 @@ func Test_Pids(t *testing.T) {
} }
} }
func Test_Pids_Fail(t *testing.T) {
if runtime.GOOS != "darwin" {
t.Skip("darwin only")
}
mu.Lock()
defer mu.Unlock()
invoke = common.FakeInvoke{Suffix: "fail"}
ret, err := Pids()
skipIfNotImplementedErr(t, err)
invoke = common.Invoke{}
if err != nil {
t.Errorf("error %v", err)
}
if len(ret) != 9 {
t.Errorf("wrong getted pid nums: %v/%d", ret, len(ret))
}
}
func Test_Pid_exists(t *testing.T) { func Test_Pid_exists(t *testing.T) {
checkPid := os.Getpid() checkPid := os.Getpid()

@ -1,10 +0,0 @@
PID
245
247
248
249
254
262
264
265
267
Loading…
Cancel
Save