diff --git a/README.rst b/README.rst index 63f5f69..73a79ea 100644 --- a/README.rst +++ b/README.rst @@ -241,6 +241,7 @@ parent x x x x children x x x x x connections x x x is_running +page_faults x ================ ===== ======= ======= ====== ======= Original Metrics diff --git a/process/process_darwin.go b/process/process_darwin.go index ca0f187..0e83030 100644 --- a/process/process_darwin.go +++ b/process/process_darwin.go @@ -481,6 +481,14 @@ func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExSta return nil, common.ErrNotImplementedError } +func (p *Process) PageFaults() (*PageFaultsStat, error) { + return p.PageFaultsWithContext(context.Background()) +} + +func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { + return nil, common.ErrNotImplementedError +} + func (p *Process) Children() ([]*Process, error) { return p.ChildrenWithContext(context.Background()) } diff --git a/process/process_fallback.go b/process/process_fallback.go index 8772440..f95eca6 100644 --- a/process/process_fallback.go +++ b/process/process_fallback.go @@ -233,6 +233,12 @@ func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) { func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) { return nil, common.ErrNotImplementedError } +func (p *Process) PageFaults() (*PageFaultsStat, error) { + return p.PageFaultsWithContext(context.Background()) +} +func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { + return nil, common.ErrNotImplementedError +} func (p *Process) Children() ([]*Process, error) { return p.ChildrenWithContext(context.Background()) } diff --git a/process/process_freebsd.go b/process/process_freebsd.go index fd98a8c..e807e35 100644 --- a/process/process_freebsd.go +++ b/process/process_freebsd.go @@ -371,6 +371,14 @@ func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExSta return nil, common.ErrNotImplementedError } +func (p *Process) PageFaults() (*PageFaultsStat, error) { + return p.PageFaultsWithContext(context.Background()) +} + +func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { + return nil, common.ErrNotImplementedError +} + func (p *Process) Children() ([]*Process, error) { return p.ChildrenWithContext(context.Background()) } diff --git a/process/process_linux.go b/process/process_linux.go index 9e77500..8f6ae4b 100644 --- a/process/process_linux.go +++ b/process/process_linux.go @@ -60,6 +60,13 @@ type MemoryMapsStat struct { Swap uint64 `json:"swap"` } +type PageFaultsStat struct { + MinorFaults uint64 `json:"minorFaults"` + MajorFaults uint64 `json:"majorFaults"` + ChildMinorFaults uint64 `json:"childMinorFaults"` + ChildMajorFaults uint64 `json:"childMajorFaults"` +} + // String returns JSON value of the process. func (m MemoryMapsStat) String() string { s, _ := json.Marshal(m) @@ -85,7 +92,7 @@ func (p *Process) Ppid() (int32, error) { } func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { - _, ppid, _, _, _, _, err := p.fillFromStat() + _, ppid, _, _, _, _, _, err := p.fillFromStat() if err != nil { return -1, err } @@ -151,7 +158,7 @@ func (p *Process) CreateTime() (int64, error) { } func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) { - _, _, _, createTime, _, _, err := p.fillFromStat() + _, _, _, createTime, _, _, _, err := p.fillFromStat() if err != nil { return 0, err } @@ -254,7 +261,7 @@ func (p *Process) Terminal() (string, error) { } func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { - t, _, _, _, _, _, err := p.fillFromStat() + t, _, _, _, _, _, _, err := p.fillFromStat() if err != nil { return "", err } @@ -273,7 +280,7 @@ func (p *Process) Nice() (int32, error) { } func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { - _, _, _, _, _, nice, err := p.fillFromStat() + _, _, _, _, _, nice, _, err := p.fillFromStat() if err != nil { return 0, err } @@ -311,7 +318,7 @@ func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ( return rlimits, err } - _, _, _, _, rtprio, nice, err := p.fillFromStat() + _, _, _, _, rtprio, nice, _, err := p.fillFromStat() if err != nil { return nil, err } @@ -419,7 +426,7 @@ func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesS } for _, tid := range tids { - _, _, cpuTimes, _, _, _, err := p.fillFromTIDStat(tid) + _, _, cpuTimes, _, _, _, _, err := p.fillFromTIDStat(tid) if err != nil { return nil, err } @@ -435,7 +442,7 @@ func (p *Process) Times() (*cpu.TimesStat, error) { } func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { - _, _, cpuTimes, _, _, _, err := p.fillFromStat() + _, _, cpuTimes, _, _, _, _, err := p.fillFromStat() if err != nil { return nil, err } @@ -479,6 +486,20 @@ func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExSta return memInfoEx, nil } +// PageFaultsInfo returns the process's page fault counters +func (p *Process) PageFaults() (*PageFaultsStat, error) { + return p.PageFaultsWithContext(context.Background()) +} + +func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { + _, _, _, _, _, _, pageFaults, err := p.fillFromStat() + if err != nil { + return nil, err + } + return pageFaults, nil + +} + // Children returns a slice of Process of the process. func (p *Process) Children() ([]*Process, error) { return p.ChildrenWithContext(context.Background()) @@ -1148,11 +1169,11 @@ func (p *Process) fillFromStatusWithContext(ctx context.Context) error { return nil } -func (p *Process) fillFromTIDStat(tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, error) { +func (p *Process) fillFromTIDStat(tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) { return p.fillFromTIDStatWithContext(context.Background(), tid) } -func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, error) { +func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) { pid := p.Pid var statPath string @@ -1164,7 +1185,7 @@ func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (ui contents, err := ioutil.ReadFile(statPath) if err != nil { - return 0, 0, nil, 0, 0, 0, err + return 0, 0, nil, 0, 0, 0, nil, err } fields := strings.Fields(string(contents)) @@ -1175,21 +1196,21 @@ func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (ui terminal, err := strconv.ParseUint(fields[i+5], 10, 64) if err != nil { - return 0, 0, nil, 0, 0, 0, err + return 0, 0, nil, 0, 0, 0, nil, err } ppid, err := strconv.ParseInt(fields[i+2], 10, 32) if err != nil { - return 0, 0, nil, 0, 0, 0, err + return 0, 0, nil, 0, 0, 0, nil, err } utime, err := strconv.ParseFloat(fields[i+12], 64) if err != nil { - return 0, 0, nil, 0, 0, 0, err + return 0, 0, nil, 0, 0, 0, nil, err } stime, err := strconv.ParseFloat(fields[i+13], 64) if err != nil { - return 0, 0, nil, 0, 0, 0, err + return 0, 0, nil, 0, 0, 0, nil, err } cpuTimes := &cpu.TimesStat{ @@ -1201,14 +1222,14 @@ func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (ui bootTime, _ := host.BootTime() t, err := strconv.ParseUint(fields[i+20], 10, 64) if err != nil { - return 0, 0, nil, 0, 0, 0, err + return 0, 0, nil, 0, 0, 0, nil, err } ctime := (t / uint64(ClockTicks)) + uint64(bootTime) createTime := int64(ctime * 1000) rtpriority, err := strconv.ParseInt(fields[i+16], 10, 32) if err != nil { - return 0, 0, nil, 0, 0, 0, err + return 0, 0, nil, 0, 0, 0, nil, err } if rtpriority < 0 { rtpriority = rtpriority*-1 - 1 @@ -1221,14 +1242,38 @@ func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (ui snice, _ := unix.Getpriority(PrioProcess, int(pid)) nice := int32(snice) // FIXME: is this true? - return terminal, int32(ppid), cpuTimes, createTime, uint32(rtpriority), nice, nil + minFault, err := strconv.ParseUint(fields[i+8], 10, 64) + if err != nil { + return 0, 0, nil, 0, 0, 0, nil, err + } + cMinFault, err := strconv.ParseUint(fields[i+9], 10, 64) + if err != nil { + return 0, 0, nil, 0, 0, 0, nil, err + } + majFault, err := strconv.ParseUint(fields[i+10], 10, 64) + if err != nil { + return 0, 0, nil, 0, 0, 0, nil, err + } + cMajFault, err := strconv.ParseUint(fields[i+11], 10, 64) + if err != nil { + return 0, 0, nil, 0, 0, 0, nil, err + } + + faults := &PageFaultsStat{ + MinorFaults: minFault, + MajorFaults: majFault, + ChildMinorFaults: cMinFault, + ChildMajorFaults: cMajFault, + } + + return terminal, int32(ppid), cpuTimes, createTime, uint32(rtpriority), nice, faults, nil } -func (p *Process) fillFromStat() (uint64, int32, *cpu.TimesStat, int64, uint32, int32, error) { +func (p *Process) fillFromStat() (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) { return p.fillFromStatWithContext(context.Background()) } -func (p *Process) fillFromStatWithContext(ctx context.Context) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, error) { +func (p *Process) fillFromStatWithContext(ctx context.Context) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) { return p.fillFromTIDStat(-1) } diff --git a/process/process_openbsd.go b/process/process_openbsd.go index 155ed6e..9e01ea7 100644 --- a/process/process_openbsd.go +++ b/process/process_openbsd.go @@ -359,6 +359,14 @@ func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExSta return nil, common.ErrNotImplementedError } +func (p *Process) PageFaults() (*PageFaultsStat, error) { + return p.PageFaultsWithContext(context.Background()) +} + +func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { + return nil, common.ErrNotImplementedError +} + func (p *Process) Children() ([]*Process, error) { return p.ChildrenWithContext(context.Background()) } diff --git a/process/process_windows.go b/process/process_windows.go index 48a1213..52bec7b 100644 --- a/process/process_windows.go +++ b/process/process_windows.go @@ -530,6 +530,14 @@ func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExSta return nil, common.ErrNotImplementedError } +func (p *Process) PageFaults() (*PageFaultsStat, error) { + return p.PageFaultsWithContext(context.Background()) +} + +func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { + return nil, common.ErrNotImplementedError +} + func (p *Process) Children() ([]*Process, error) { return p.ChildrenWithContext(context.Background()) }