mirror of
https://github.com/shirou/gopsutil.git
synced 2025-04-29 13:49:21 +08:00
Merge pull request #346 from phemmer/rlimit-current
add current values to rlimit retrieval
This commit is contained in:
commit
a452de7c73
@ -26,6 +26,7 @@ type Process struct {
|
|||||||
gids []int32
|
gids []int32
|
||||||
numThreads int32
|
numThreads int32
|
||||||
memInfo *MemoryInfoStat
|
memInfo *MemoryInfoStat
|
||||||
|
sigInfo *SignalInfoStat
|
||||||
|
|
||||||
lastCPUTimes *cpu.TimesStat
|
lastCPUTimes *cpu.TimesStat
|
||||||
lastCPUTime time.Time
|
lastCPUTime time.Time
|
||||||
@ -39,13 +40,25 @@ type OpenFilesStat struct {
|
|||||||
type MemoryInfoStat struct {
|
type MemoryInfoStat struct {
|
||||||
RSS uint64 `json:"rss"` // bytes
|
RSS uint64 `json:"rss"` // bytes
|
||||||
VMS uint64 `json:"vms"` // bytes
|
VMS uint64 `json:"vms"` // bytes
|
||||||
|
Data uint64 `json:"data"` // bytes
|
||||||
|
Stack uint64 `json:"stack"` // bytes
|
||||||
|
Locked uint64 `json:"locked"` // bytes
|
||||||
Swap uint64 `json:"swap"` // 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 {
|
type RlimitStat struct {
|
||||||
Resource int32 `json:"resource"`
|
Resource int32 `json:"resource"`
|
||||||
Soft int32 `json:"soft"`
|
Soft int32 `json:"soft"` //TODO too small. needs to be uint64
|
||||||
Hard int32 `json:"hard"`
|
Hard int32 `json:"hard"` //TODO too small. needs to be uint64
|
||||||
|
Used uint64 `json:"used"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type IOCountersStat struct {
|
type IOCountersStat struct {
|
||||||
|
@ -248,6 +248,10 @@ func (p *Process) Rlimit() ([]RlimitStat, error) {
|
|||||||
var rlimit []RlimitStat
|
var rlimit []RlimitStat
|
||||||
return rlimit, common.ErrNotImplementedError
|
return rlimit, common.ErrNotImplementedError
|
||||||
}
|
}
|
||||||
|
func (p *Process) RlimitUsage(_ bool) ([]RlimitStat, error) {
|
||||||
|
var rlimit []RlimitStat
|
||||||
|
return rlimit, common.ErrNotImplementedError
|
||||||
|
}
|
||||||
func (p *Process) IOCounters() (*IOCountersStat, error) {
|
func (p *Process) IOCounters() (*IOCountersStat, error) {
|
||||||
return nil, common.ErrNotImplementedError
|
return nil, common.ErrNotImplementedError
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,9 @@ func (p *Process) IOnice() (int32, error) {
|
|||||||
func (p *Process) Rlimit() ([]RlimitStat, error) {
|
func (p *Process) Rlimit() ([]RlimitStat, error) {
|
||||||
return nil, common.ErrNotImplementedError
|
return nil, common.ErrNotImplementedError
|
||||||
}
|
}
|
||||||
|
func (p *Process) RlimitUsage(_ bool) ([]RlimitStat, error) {
|
||||||
|
return nil, common.ErrNotImplementedError
|
||||||
|
}
|
||||||
func (p *Process) IOCounters() (*IOCountersStat, error) {
|
func (p *Process) IOCounters() (*IOCountersStat, error) {
|
||||||
return nil, common.ErrNotImplementedError
|
return nil, common.ErrNotImplementedError
|
||||||
}
|
}
|
||||||
|
@ -176,6 +176,10 @@ func (p *Process) Rlimit() ([]RlimitStat, error) {
|
|||||||
var rlimit []RlimitStat
|
var rlimit []RlimitStat
|
||||||
return rlimit, common.ErrNotImplementedError
|
return rlimit, common.ErrNotImplementedError
|
||||||
}
|
}
|
||||||
|
func (p *Process) RlimitUsage(_ bool) ([]RlimitStat, error) {
|
||||||
|
var rlimit []RlimitStat
|
||||||
|
return rlimit, common.ErrNotImplementedError
|
||||||
|
}
|
||||||
func (p *Process) IOCounters() (*IOCountersStat, error) {
|
func (p *Process) IOCounters() (*IOCountersStat, error) {
|
||||||
k, err := p.getKProc()
|
k, err := p.getKProc()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -83,7 +83,7 @@ func NewProcess(pid int32) (*Process, error) {
|
|||||||
|
|
||||||
// Ppid returns Parent Process ID of the process.
|
// Ppid returns Parent Process ID of the process.
|
||||||
func (p *Process) Ppid() (int32, error) {
|
func (p *Process) Ppid() (int32, error) {
|
||||||
_, ppid, _, _, _, err := p.fillFromStat()
|
_, ppid, _, _, _, _, err := p.fillFromStat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@ -119,7 +119,7 @@ func (p *Process) CmdlineSlice() ([]string, error) {
|
|||||||
|
|
||||||
// CreateTime returns created time of the process in milliseconds since the epoch, in UTC.
|
// CreateTime returns created time of the process in milliseconds since the epoch, in UTC.
|
||||||
func (p *Process) CreateTime() (int64, error) {
|
func (p *Process) CreateTime() (int64, error) {
|
||||||
_, _, _, createTime, _, err := p.fillFromStat()
|
_, _, _, createTime, _, _, err := p.fillFromStat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -176,7 +176,7 @@ func (p *Process) Gids() ([]int32, error) {
|
|||||||
|
|
||||||
// Terminal returns a terminal which is associated with the process.
|
// Terminal returns a terminal which is associated with the process.
|
||||||
func (p *Process) Terminal() (string, error) {
|
func (p *Process) Terminal() (string, error) {
|
||||||
terminal, _, _, _, _, err := p.fillFromStat()
|
terminal, _, _, _, _, _, err := p.fillFromStat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -186,7 +186,7 @@ func (p *Process) Terminal() (string, error) {
|
|||||||
// Nice returns a nice value (priority).
|
// Nice returns a nice value (priority).
|
||||||
// Notice: gopsutil can not set nice value.
|
// Notice: gopsutil can not set nice value.
|
||||||
func (p *Process) Nice() (int32, error) {
|
func (p *Process) Nice() (int32, error) {
|
||||||
_, _, _, _, nice, err := p.fillFromStat()
|
_, _, _, _, _, nice, err := p.fillFromStat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -200,7 +200,65 @@ func (p *Process) IOnice() (int32, error) {
|
|||||||
|
|
||||||
// Rlimit returns Resource Limits.
|
// Rlimit returns Resource Limits.
|
||||||
func (p *Process) Rlimit() ([]RlimitStat, error) {
|
func (p *Process) Rlimit() ([]RlimitStat, error) {
|
||||||
return p.fillFromLimits()
|
return p.RlimitUsage(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
rlimits, err := p.fillFromLimits()
|
||||||
|
if !gatherUsed || err != nil {
|
||||||
|
return rlimits, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, _, _, rtprio, nice, err := p.fillFromStat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := p.fillFromStatus(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range rlimits {
|
||||||
|
rs := &rlimits[i]
|
||||||
|
switch rs.Resource {
|
||||||
|
case RLIMIT_CPU:
|
||||||
|
times, err := p.Times()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rs.Used = uint64(times.User + times.System)
|
||||||
|
case RLIMIT_DATA:
|
||||||
|
rs.Used = uint64(p.memInfo.Data)
|
||||||
|
case RLIMIT_STACK:
|
||||||
|
rs.Used = uint64(p.memInfo.Stack)
|
||||||
|
case RLIMIT_RSS:
|
||||||
|
rs.Used = uint64(p.memInfo.RSS)
|
||||||
|
case RLIMIT_NOFILE:
|
||||||
|
n, err := p.NumFDs()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rs.Used = uint64(n)
|
||||||
|
case RLIMIT_MEMLOCK:
|
||||||
|
rs.Used = uint64(p.memInfo.Locked)
|
||||||
|
case RLIMIT_AS:
|
||||||
|
rs.Used = uint64(p.memInfo.VMS)
|
||||||
|
case RLIMIT_LOCKS:
|
||||||
|
//TODO we can get the used value from /proc/$pid/locks. But linux doesn't enforce it, so not a high priority.
|
||||||
|
case RLIMIT_SIGPENDING:
|
||||||
|
rs.Used = p.sigInfo.PendingProcess
|
||||||
|
case RLIMIT_NICE:
|
||||||
|
// The rlimit for nice is a little unusual, in that 0 means the niceness cannot be decreased beyond the current value, but it can be increased.
|
||||||
|
// So effectively: if rs.Soft == 0 { rs.Soft = rs.Used }
|
||||||
|
rs.Used = uint64(nice)
|
||||||
|
case RLIMIT_RTPRIO:
|
||||||
|
rs.Used = uint64(rtprio)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rlimits, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// IOCounters returns IO Counters.
|
// IOCounters returns IO Counters.
|
||||||
@ -242,7 +300,7 @@ func (p *Process) Threads() (map[string]string, error) {
|
|||||||
|
|
||||||
// Times returns CPU times of the process.
|
// Times returns CPU times of the process.
|
||||||
func (p *Process) Times() (*cpu.TimesStat, error) {
|
func (p *Process) Times() (*cpu.TimesStat, error) {
|
||||||
_, _, cpuTimes, _, _, err := p.fillFromStat()
|
_, _, cpuTimes, _, _, _, err := p.fillFromStat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -720,6 +778,7 @@ func (p *Process) fillFromStatus() error {
|
|||||||
lines := strings.Split(string(contents), "\n")
|
lines := strings.Split(string(contents), "\n")
|
||||||
p.numCtxSwitches = &NumCtxSwitchesStat{}
|
p.numCtxSwitches = &NumCtxSwitchesStat{}
|
||||||
p.memInfo = &MemoryInfoStat{}
|
p.memInfo = &MemoryInfoStat{}
|
||||||
|
p.sigInfo = &SignalInfoStat{}
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
tabParts := strings.SplitN(line, "\t", 2)
|
tabParts := strings.SplitN(line, "\t", 2)
|
||||||
if len(tabParts) < 2 {
|
if len(tabParts) < 2 {
|
||||||
@ -806,18 +865,69 @@ func (p *Process) fillFromStatus() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.memInfo.Swap = v * 1024
|
p.memInfo.Swap = v * 1024
|
||||||
|
case "VmData":
|
||||||
|
value := strings.Trim(value, " kB") // remove last "kB"
|
||||||
|
v, err := strconv.ParseUint(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.memInfo.Data = v * 1024
|
||||||
|
case "VmStk":
|
||||||
|
value := strings.Trim(value, " kB") // remove last "kB"
|
||||||
|
v, err := strconv.ParseUint(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.memInfo.Stack = v * 1024
|
||||||
|
case "VmLck":
|
||||||
|
value := strings.Trim(value, " kB") // remove last "kB"
|
||||||
|
v, err := strconv.ParseUint(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.memInfo.Locked = v * 1024
|
||||||
|
case "SigPnd":
|
||||||
|
v, err := strconv.ParseUint(value, 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.sigInfo.PendingThread = v
|
||||||
|
case "ShdPnd":
|
||||||
|
v, err := strconv.ParseUint(value, 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.sigInfo.PendingProcess = v
|
||||||
|
case "SigBlk":
|
||||||
|
v, err := strconv.ParseUint(value, 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.sigInfo.Blocked = v
|
||||||
|
case "SigIgn":
|
||||||
|
v, err := strconv.ParseUint(value, 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.sigInfo.Ignored = v
|
||||||
|
case "SigCgt":
|
||||||
|
v, err := strconv.ParseUint(value, 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.sigInfo.Caught = v
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Process) fillFromStat() (string, int32, *cpu.TimesStat, int64, int32, error) {
|
func (p *Process) fillFromStat() (string, int32, *cpu.TimesStat, int64, uint32, int32, error) {
|
||||||
pid := p.Pid
|
pid := p.Pid
|
||||||
statPath := common.HostProc(strconv.Itoa(int(pid)), "stat")
|
statPath := common.HostProc(strconv.Itoa(int(pid)), "stat")
|
||||||
contents, err := ioutil.ReadFile(statPath)
|
contents, err := ioutil.ReadFile(statPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, nil, 0, 0, err
|
return "", 0, nil, 0, 0, 0, err
|
||||||
}
|
}
|
||||||
fields := strings.Fields(string(contents))
|
fields := strings.Fields(string(contents))
|
||||||
|
|
||||||
@ -831,23 +941,23 @@ func (p *Process) fillFromStat() (string, int32, *cpu.TimesStat, int64, int32, e
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t, err := strconv.ParseUint(fields[i+5], 10, 64)
|
t, err := strconv.ParseUint(fields[i+5], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, nil, 0, 0, err
|
return "", 0, nil, 0, 0, 0, err
|
||||||
}
|
}
|
||||||
terminal = termmap[t]
|
terminal = termmap[t]
|
||||||
}
|
}
|
||||||
|
|
||||||
ppid, err := strconv.ParseInt(fields[i+2], 10, 32)
|
ppid, err := strconv.ParseInt(fields[i+2], 10, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, nil, 0, 0, err
|
return "", 0, nil, 0, 0, 0, err
|
||||||
}
|
}
|
||||||
utime, err := strconv.ParseFloat(fields[i+12], 64)
|
utime, err := strconv.ParseFloat(fields[i+12], 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, nil, 0, 0, err
|
return "", 0, nil, 0, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
stime, err := strconv.ParseFloat(fields[i+13], 64)
|
stime, err := strconv.ParseFloat(fields[i+13], 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, nil, 0, 0, err
|
return "", 0, nil, 0, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cpuTimes := &cpu.TimesStat{
|
cpuTimes := &cpu.TimesStat{
|
||||||
@ -859,17 +969,24 @@ func (p *Process) fillFromStat() (string, int32, *cpu.TimesStat, int64, int32, e
|
|||||||
bootTime, _ := host.BootTime()
|
bootTime, _ := host.BootTime()
|
||||||
t, err := strconv.ParseUint(fields[i+20], 10, 64)
|
t, err := strconv.ParseUint(fields[i+20], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, nil, 0, 0, err
|
return "", 0, nil, 0, 0, 0, err
|
||||||
}
|
}
|
||||||
ctime := (t / uint64(ClockTicks)) + uint64(bootTime)
|
ctime := (t / uint64(ClockTicks)) + uint64(bootTime)
|
||||||
createTime := int64(ctime * 1000)
|
createTime := int64(ctime * 1000)
|
||||||
|
|
||||||
|
rtpriority, err := strconv.ParseInt(fields[i+16], 10, 32)
|
||||||
|
if rtpriority < 0 {
|
||||||
|
rtpriority = rtpriority*-1 - 1
|
||||||
|
} else {
|
||||||
|
rtpriority = 0
|
||||||
|
}
|
||||||
|
|
||||||
// p.Nice = mustParseInt32(fields[18])
|
// p.Nice = mustParseInt32(fields[18])
|
||||||
// use syscall instead of parse Stat file
|
// use syscall instead of parse Stat file
|
||||||
snice, _ := unix.Getpriority(PrioProcess, int(pid))
|
snice, _ := unix.Getpriority(PrioProcess, int(pid))
|
||||||
nice := int32(snice) // FIXME: is this true?
|
nice := int32(snice) // FIXME: is this true?
|
||||||
|
|
||||||
return terminal, int32(ppid), cpuTimes, createTime, nice, nil
|
return terminal, int32(ppid), cpuTimes, createTime, uint32(rtpriority), nice, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pids returns a slice of process ID list which are running now.
|
// Pids returns a slice of process ID list which are running now.
|
||||||
|
@ -170,6 +170,10 @@ func (p *Process) Rlimit() ([]RlimitStat, error) {
|
|||||||
var rlimit []RlimitStat
|
var rlimit []RlimitStat
|
||||||
return rlimit, common.ErrNotImplementedError
|
return rlimit, common.ErrNotImplementedError
|
||||||
}
|
}
|
||||||
|
func (p *Process) RlimitUsage(_ bool) ([]RlimitStat, error) {
|
||||||
|
var rlimit []RlimitStat
|
||||||
|
return rlimit, common.ErrNotImplementedError
|
||||||
|
}
|
||||||
func (p *Process) IOCounters() (*IOCountersStat, error) {
|
func (p *Process) IOCounters() (*IOCountersStat, error) {
|
||||||
k, err := p.getKProc()
|
k, err := p.getKProc()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -240,6 +240,11 @@ func (p *Process) Rlimit() ([]RlimitStat, error) {
|
|||||||
|
|
||||||
return rlimit, common.ErrNotImplementedError
|
return rlimit, common.ErrNotImplementedError
|
||||||
}
|
}
|
||||||
|
func (p *Process) RlimitUsage(_ bool) ([]RlimitStat, error) {
|
||||||
|
var rlimit []RlimitStat
|
||||||
|
|
||||||
|
return rlimit, common.ErrNotImplementedError
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Process) IOCounters() (*IOCountersStat, error) {
|
func (p *Process) IOCounters() (*IOCountersStat, error) {
|
||||||
dst, err := GetWin32Proc(p.Pid)
|
dst, err := GetWin32Proc(p.Pid)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user