Merge branch 'master' of https://github.com/shirou/gopsutil into calc_cpu_percent

Conflicts:
	cpu/cpu.go
pull/205/head
Ben Aldrich 9 years ago
commit fcc1747d9f

@ -194,13 +194,13 @@ exe x x x
uids x x x
gids x x x
terminal x x x
io_counters x x
io_counters x x x
nice x x x x
num_fds x
num_ctx_switches x
num_threads x x x x
cpu_times x
memory_info x x x
memory_info x x x x
memory_info_ex x
memory_maps x
open_files x

@ -2,6 +2,7 @@ package cpu
import (
"encoding/json"
"github.com/shirou/gopsutil/internal/common"
"runtime"
"strconv"
"strings"
@ -46,8 +47,10 @@ type cpuPercent struct {
}
var lastCPUPercent cpuPercent
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
lastCPUPercent.Lock()
lastCPUPercent.lastCPUTimes, _ = Times(false)
lastCPUPercent.lastPerCPUTimes, _ = Times(true)

@ -36,7 +36,7 @@ func Info() ([]InfoStat, error) {
if err != nil {
return ret, err
}
out, err := exec.Command(sysctl, "machdep.cpu").Output()
out, err := invoke.Command(sysctl, "machdep.cpu")
if err != nil {
return ret, err
}
@ -90,7 +90,7 @@ func Info() ([]InfoStat, error) {
// Use the rated frequency of the CPU. This is a static value and does not
// account for low power or Turbo Boost modes.
out, err = exec.Command(sysctl, "hw.cpufrequency").Output()
out, err = invoke.Command(sysctl, "hw.cpufrequency")
if err != nil {
return ret, err
}

@ -29,7 +29,7 @@ func init() {
if err != nil {
return
}
out, err := exec.Command(getconf, "CLK_TCK").Output()
out, err := invoke.Command(getconf, "CLK_TCK")
// ignore errors
if err == nil {
i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)

@ -19,7 +19,7 @@ func init() {
if err != nil {
return
}
out, err := exec.Command(getconf, "CLK_TCK").Output()
out, err := invoke.Command(getconf, "CLK_TCK")
// ignore errors
if err == nil {
i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)

@ -2,8 +2,16 @@ package disk
import (
"encoding/json"
"github.com/shirou/gopsutil/internal/common"
)
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
}
type UsageStat struct {
Path string `json:"path"`
Fstype string `json:"fstype"`

@ -339,7 +339,7 @@ func GetDiskSerialNumber(name string) string {
return ""
}
out, err := exec.Command(udevadm, "info", "--query=property", n).Output()
out, err := invoke.Command(udevadm, "info", "--query=property", n)
// does not return error, just an empty string
if err != nil {

@ -1,10 +1,20 @@
package docker
import "errors"
import (
"errors"
"github.com/shirou/gopsutil/internal/common"
)
var ErrDockerNotAvailable = errors.New("docker not available")
var ErrCgroupNotAvailable = errors.New("cgroup not available")
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
}
type CgroupMemStat struct {
ContainerID string `json:"containerID"`
Cache uint64 `json:"cache"`

@ -23,7 +23,7 @@ func GetDockerStat() ([]CgroupDockerStat, error) {
return nil, ErrDockerNotAvailable
}
out, err := exec.Command(path, "ps", "-a", "--no-trunc", "--format", "{{.ID}}|{{.Image}}|{{.Names}}|{{.Status}}").Output()
out, err := invoke.Command(path, "ps", "-a", "--no-trunc", "--format", "{{.ID}}|{{.Image}}|{{.Names}}|{{.Status}}")
if err != nil {
return []CgroupDockerStat{}, err
}
@ -65,7 +65,7 @@ func GetDockerIDList() ([]string, error) {
return nil, ErrDockerNotAvailable
}
out, err := exec.Command(path, "ps", "-q", "--no-trunc").Output()
out, err := invoke.Command(path, "ps", "-q", "--no-trunc")
if err != nil {
return []string{}, err
}

@ -2,8 +2,16 @@ package host
import (
"encoding/json"
"github.com/shirou/gopsutil/internal/common"
)
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
}
// A HostInfoStat describes the host status.
// This is not in the psutil but it useful.
type InfoStat struct {

@ -131,12 +131,12 @@ func PlatformInformation() (string, string, string, error) {
if err != nil {
return "", "", "", err
}
out, err := exec.Command(uname, "-s").Output()
out, err := invoke.Command(uname, "-s")
if err == nil {
platform = strings.ToLower(strings.TrimSpace(string(out)))
}
out, err = exec.Command(uname, "-r").Output()
out, err = invoke.Command(uname, "-r")
if err == nil {
version = strings.ToLower(strings.TrimSpace(string(out)))
}

@ -136,12 +136,12 @@ func PlatformInformation() (string, string, string, error) {
return "", "", "", err
}
out, err := exec.Command(uname, "-s").Output()
out, err := invoke.Command(uname, "-s")
if err == nil {
platform = strings.ToLower(strings.TrimSpace(string(out)))
}
out, err = exec.Command(uname, "-r").Output()
out, err = invoke.Command(uname, "-r")
if err == nil {
version = strings.ToLower(strings.TrimSpace(string(out)))
}

@ -164,7 +164,7 @@ func getLSB() (*LSB, error) {
if err != nil {
return ret, err
}
out, err := exec.Command(lsb_release).Output()
out, err := invoke.Command(lsb_release)
if err != nil {
return ret, err
}

@ -8,8 +8,10 @@ package common
// - windows (amd64)
import (
"bufio"
"bytes"
"errors"
"io/ioutil"
"log"
"net/url"
"os"
"os/exec"
@ -19,6 +21,12 @@ import (
"runtime"
"strconv"
"strings"
"time"
)
var (
Timeout = 3 * time.Second
TimeoutErr = errors.New("Command timed out.")
)
type Invoker interface {
@ -28,7 +36,8 @@ type Invoker interface {
type Invoke struct{}
func (i Invoke) Command(name string, arg ...string) ([]byte, error) {
return exec.Command(name, arg...).Output()
cmd := exec.Command(name, arg...)
return CombinedOutputTimeout(cmd, Timeout)
}
type FakeInvoke struct {
@ -294,3 +303,41 @@ func HostSys(combineWith ...string) string {
func HostEtc(combineWith ...string) string {
return GetEnv("HOST_ETC", "/etc", combineWith...)
}
// CombinedOutputTimeout runs the given command with the given timeout and
// returns the combined output of stdout and stderr.
// If the command times out, it attempts to kill the process.
// copied from https://github.com/influxdata/telegraf
func CombinedOutputTimeout(c *exec.Cmd, timeout time.Duration) ([]byte, error) {
var b bytes.Buffer
c.Stdout = &b
c.Stderr = &b
if err := c.Start(); err != nil {
return nil, err
}
err := WaitTimeout(c, timeout)
return b.Bytes(), err
}
// WaitTimeout waits for the given command to finish with a timeout.
// It assumes the command has already been started.
// If the command times out, it attempts to kill the process.
// copied from https://github.com/influxdata/telegraf
func WaitTimeout(c *exec.Cmd, timeout time.Duration) error {
timer := time.NewTimer(timeout)
done := make(chan error)
go func() { done <- c.Wait() }()
select {
case err := <-done:
timer.Stop()
return err
case <-timer.C:
if err := c.Process.Kill(); err != nil {
log.Printf("FATAL error killing process: %s", err)
return err
}
// wait for the command to return after killing it
<-done
return TimeoutErr
}
}

@ -2,8 +2,16 @@ package mem
import (
"encoding/json"
"github.com/shirou/gopsutil/internal/common"
)
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
}
// Memory usage statistics. Total, Available and Used contain numbers of bytes
// for human consumption.
//

@ -16,7 +16,7 @@ func getVMStat(vms *VirtualMemoryStat) error {
if err != nil {
return err
}
out, err := exec.Command(vm_stat).Output()
out, err := invoke.Command(vm_stat)
if err != nil {
return err
}

@ -3,7 +3,6 @@
package mem
import (
"os/exec"
"strconv"
"strings"
"testing"
@ -15,7 +14,7 @@ func TestVirtualMemoryDarwin(t *testing.T) {
v, err := VirtualMemory()
assert.Nil(t, err)
outBytes, err := exec.Command("/usr/sbin/sysctl", "hw.memsize").Output()
outBytes, err := invoke.Command("/usr/sbin/sysctl", "hw.memsize")
assert.Nil(t, err)
outString := string(outBytes)
outString = strings.TrimSpace(outString)

@ -93,7 +93,7 @@ func SwapMemory() (*SwapMemoryStat, error) {
return nil, err
}
out, err := exec.Command(swapinfo).Output()
out, err := invoke.Command(swapinfo)
if err != nil {
return nil, err
}

@ -21,7 +21,7 @@ func IOCounters(pernic bool) ([]IOCountersStat, error) {
if err != nil {
return nil, err
}
out, err := exec.Command(netstat, "-ibdnW").Output()
out, err := invoke.Command(netstat, "-ibdnW")
if err != nil {
return nil, err
}

@ -16,7 +16,7 @@ func IOCounters(pernic bool) ([]IOCountersStat, error) {
if err != nil {
return nil, err
}
out, err := exec.Command(netstat, "-ibdnW").Output()
out, err := invoke.Command(netstat, "-ibdnW")
if err != nil {
return nil, err
}

@ -9,6 +9,8 @@ import (
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/internal/common"
)
// POSIX
@ -72,7 +74,10 @@ func (p *Process) SendSignal(sig syscall.Signal) error {
}
cmd := exec.Command(kill, "-s", sigAsStr, strconv.Itoa(int(p.Pid)))
cmd.Stderr = os.Stderr
err = cmd.Run()
if err := cmd.Start(); err != nil {
return err
}
err = common.WaitTimeout(cmd, common.Timeout)
if err != nil {
return err
}

@ -23,6 +23,11 @@ const (
MaxPathLength = 260
)
var (
modpsapi = syscall.NewLazyDLL("psapi.dll")
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
)
type SystemProcessInformation struct {
NextEntryOffset uint64
NumberOfThreads uint64
@ -53,6 +58,11 @@ type Win32_Process struct {
CreationDate *time.Time
ProcessID uint32
ThreadCount uint32
Status *string
ReadOperationCount uint64
ReadTransferCount uint64
WriteOperationCount uint64
WriteTransferCount uint64
/*
CSCreationClassName string
@ -76,14 +86,9 @@ type Win32_Process struct {
PeakVirtualSize uint64
PeakWorkingSetSize uint32
PrivatePageCount uint64
ReadOperationCount uint64
ReadTransferCount uint64
Status *string
TerminationDate *time.Time
UserModeTime uint64
WorkingSetSize uint64
WriteOperationCount uint64
WriteTransferCount uint64
*/
}
@ -158,12 +163,12 @@ func (p *Process) CmdlineSlice() ([]string, error) {
}
func (p *Process) CreateTime() (int64, error) {
dst, err := GetWin32Proc(p.Pid)
ru, err := getRusage(p.Pid)
if err != nil {
return 0, fmt.Errorf("could not get CreationDate: %s", err)
}
date := *dst[0].CreationDate
return date.Unix(), nil
return ru.CreationTime.Nanoseconds() / 1000000, nil
}
func (p *Process) Cwd() (string, error) {
@ -207,8 +212,20 @@ func (p *Process) Rlimit() ([]RlimitStat, error) {
return rlimit, common.ErrNotImplementedError
}
func (p *Process) IOCounters() (*IOCountersStat, error) {
return nil, common.ErrNotImplementedError
dst, err := GetWin32Proc(p.Pid)
if err != nil || len(dst) == 0 {
return nil, fmt.Errorf("could not get Win32Proc: %s", err)
}
ret := &IOCountersStat{
ReadCount: uint64(dst[0].ReadOperationCount),
ReadBytes: uint64(dst[0].ReadTransferCount),
WriteCount: uint64(dst[0].WriteOperationCount),
WriteBytes: uint64(dst[0].WriteTransferCount),
}
return ret, nil
}
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
return nil, common.ErrNotImplementedError
@ -234,7 +251,17 @@ func (p *Process) CPUAffinity() ([]int32, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
return nil, common.ErrNotImplementedError
mem, err := getMemoryInfo(p.Pid)
if err != nil {
return nil, err
}
ret := &MemoryInfoStat{
RSS: mem.WorkingSetSize,
VMS: mem.PagefileUsage,
}
return ret, nil
}
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
return nil, common.ErrNotImplementedError
@ -355,3 +382,45 @@ func getProcInfo(pid int32) (*SystemProcessInformation, error) {
return &sysProcInfo, nil
}
func getRusage(pid int32) (*syscall.Rusage, error) {
var CPU syscall.Rusage
c, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(pid))
if err != nil {
return nil, err
}
defer syscall.CloseHandle(c)
if err := syscall.GetProcessTimes(c, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil {
return nil, err
}
return &CPU, nil
}
func getMemoryInfo(pid int32) (PROCESS_MEMORY_COUNTERS, error) {
var mem PROCESS_MEMORY_COUNTERS
c, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(pid))
if err != nil {
return mem, err
}
defer syscall.CloseHandle(c)
if err := getProcessMemoryInfo(c, &mem); err != nil {
return mem, err
}
return mem, err
}
func getProcessMemoryInfo(h syscall.Handle, mem *PROCESS_MEMORY_COUNTERS) (err error) {
r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(h), uintptr(unsafe.Pointer(mem)), uintptr(unsafe.Sizeof(*mem)))
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}

@ -0,0 +1,16 @@
// +build windows
package process
type PROCESS_MEMORY_COUNTERS struct {
CB uint32
PageFaultCount uint32
PeakWorkingSetSize uint32
WorkingSetSize uint32
QuotaPeakPagedPoolUsage uint32
QuotaPagedPoolUsage uint32
QuotaPeakNonPagedPoolUsage uint32
QuotaNonPagedPoolUsage uint32
PagefileUsage uint32
PeakPagefileUsage uint32
}

@ -0,0 +1,16 @@
// +build windows
package process
type PROCESS_MEMORY_COUNTERS struct {
CB uint32
PageFaultCount uint32
PeakWorkingSetSize uint64
WorkingSetSize uint64
QuotaPeakPagedPoolUsage uint64
QuotaPagedPoolUsage uint64
QuotaPeakNonPagedPoolUsage uint64
QuotaNonPagedPoolUsage uint64
PagefileUsage uint64
PeakPagefileUsage uint64
}
Loading…
Cancel
Save