Merge pull request #1313 from hashicorp/b-update-gopsutils

Update gopsutils
This commit is contained in:
Sean Chittenden 2016-06-17 13:42:08 -07:00 committed by GitHub
commit 9aeac0b073
29 changed files with 430 additions and 130 deletions

View File

@ -133,6 +133,10 @@ func (c *AllocStatusCommand) Run(args []string) int {
var statsErr error
var stats *api.AllocResourceUsage
stats, statsErr = client.Allocations().Stats(alloc, nil)
if statsErr != nil {
c.Ui.Output("")
c.Ui.Error(fmt.Sprintf("couldn't retrieve stats (HINT: ensure Client.Advertise.HTTP is set): %v", statsErr))
}
// Format the allocation data
basic := []string{
@ -166,11 +170,6 @@ func (c *AllocStatusCommand) Run(args []string) int {
c.Ui.Output(formatAllocMetrics(alloc.Metrics, true, " "))
}
if statsErr != nil {
c.Ui.Output("")
c.Ui.Error(fmt.Sprintf("couldn't retreive stats: %v", statsErr))
}
return 0
}

View File

@ -222,6 +222,10 @@ func (c *NodeStatusCommand) Run(args []string) int {
func (c *NodeStatusCommand) formatNode(client *api.Client, node *api.Node) int {
// Get the host stats
hostStats, nodeStatsErr := client.Nodes().Stats(node.ID, nil)
if nodeStatsErr != nil {
c.Ui.Output("")
c.Ui.Error(fmt.Sprintf("error fetching node stats (HINT: ensure Client.Advertise.HTTP is set): %v", nodeStatsErr))
}
// Format the header output
basic := []string{
@ -257,6 +261,10 @@ func (c *NodeStatusCommand) formatNode(client *api.Client, node *api.Node) int {
}
hostResources, err := getHostResources(hostStats, node)
if err != nil {
c.Ui.Output("")
c.Ui.Error(fmt.Sprintf("error fetching node stats (HINT: ensure Client.Advertise.HTTP is set): %v", err))
}
if err == nil {
c.Ui.Output(c.Colorize().Color("\n[bold]Host Resource Utilization[reset]"))
c.Ui.Output(formatList(hostResources))
@ -286,10 +294,6 @@ func (c *NodeStatusCommand) formatNode(client *api.Client, node *api.Node) int {
if c.verbose {
c.formatAttributes(node)
}
if nodeStatsErr != nil {
c.Ui.Output("")
c.Ui.Error(fmt.Sprintf("error fetching node stats: %v", nodeStatsErr))
}
return 0
}

View File

@ -5,6 +5,9 @@ import (
"runtime"
"strconv"
"strings"
"sync"
"github.com/shirou/gopsutil/internal/common"
)
type TimesStat struct {
@ -37,8 +40,22 @@ type InfoStat struct {
Flags []string `json:"flags"`
}
var lastCPUTimes []TimesStat
var lastPerCPUTimes []TimesStat
type lastPercent struct {
sync.Mutex
lastCPUTimes []TimesStat
lastPerCPUTimes []TimesStat
}
var lastCPUPercent lastPercent
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
lastCPUPercent.Lock()
lastCPUPercent.lastCPUTimes, _ = Times(false)
lastCPUPercent.lastPerCPUTimes, _ = Times(true)
lastCPUPercent.Unlock()
}
func Counts(logical bool) (int, error) {
return runtime.NumCPU(), nil

View File

@ -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
}

View File

@ -10,7 +10,9 @@ package cpu
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#include <mach/host_info.h>
#if TARGET_OS_MAC
#include <libproc.h>
#endif
#include <mach/processor_info.h>
#include <mach/vm_map.h>
*/

View File

@ -27,7 +27,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)

View File

@ -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)

View File

@ -7,24 +7,46 @@ import (
"time"
)
func Percent(interval time.Duration, percpu bool) ([]float64, error) {
getAllBusy := func(t TimesStat) (float64, float64) {
busy := t.User + t.System + t.Nice + t.Iowait + t.Irq +
t.Softirq + t.Steal + t.Guest + t.GuestNice + t.Stolen
return busy + t.Idle, busy
func getAllBusy(t TimesStat) (float64, float64) {
busy := t.User + t.System + t.Nice + t.Iowait + t.Irq +
t.Softirq + t.Steal + t.Guest + t.GuestNice + t.Stolen
return busy + t.Idle, busy
}
func calculateBusy(t1, t2 TimesStat) float64 {
t1All, t1Busy := getAllBusy(t1)
t2All, t2Busy := getAllBusy(t2)
if t2Busy <= t1Busy {
return 0
}
if t2All <= t1All {
return 1
}
return (t2Busy - t1Busy) / (t2All - t1All) * 100
}
func calculateAllBusy(t1, t2 []TimesStat) ([]float64, error) {
// Make sure the CPU measurements have the same length.
if len(t1) != len(t2) {
return nil, fmt.Errorf(
"received two CPU counts: %d != %d",
len(t1), len(t2),
)
}
calculate := func(t1, t2 TimesStat) float64 {
t1All, t1Busy := getAllBusy(t1)
t2All, t2Busy := getAllBusy(t2)
ret := make([]float64, len(t1))
for i, t := range t2 {
ret[i] = calculateBusy(t1[i], t)
}
return ret, nil
}
if t2Busy <= t1Busy {
return 0
}
if t2All <= t1All {
return 1
}
return (t2Busy - t1Busy) / (t2All - t1All) * 100
//Percent calculates the percentage of cpu used either per CPU or combined.
//If an interval of 0 is given it will compare the current cpu times against the last call.
func Percent(interval time.Duration, percpu bool) ([]float64, error) {
if interval <= 0 {
return percentUsedFromLastCall(percpu)
}
// Get CPU usage at the start of the interval.
@ -33,9 +55,7 @@ func Percent(interval time.Duration, percpu bool) ([]float64, error) {
return nil, err
}
if interval > 0 {
time.Sleep(interval)
}
time.Sleep(interval)
// And at the end of the interval.
cpuTimes2, err := Times(percpu)
@ -43,17 +63,28 @@ func Percent(interval time.Duration, percpu bool) ([]float64, error) {
return nil, err
}
// Make sure the CPU measurements have the same length.
if len(cpuTimes1) != len(cpuTimes2) {
return nil, fmt.Errorf(
"received two CPU counts: %d != %d",
len(cpuTimes1), len(cpuTimes2),
)
return calculateAllBusy(cpuTimes1, cpuTimes2)
}
func percentUsedFromLastCall(percpu bool) ([]float64, error) {
cpuTimes, err := Times(percpu)
if err != nil {
return nil, err
}
lastCPUPercent.Lock()
defer lastCPUPercent.Unlock()
var lastTimes []TimesStat
if percpu {
lastTimes = lastCPUPercent.lastPerCPUTimes
lastCPUPercent.lastPerCPUTimes = cpuTimes
} else {
lastTimes = lastCPUPercent.lastCPUTimes
lastCPUPercent.lastCPUTimes = cpuTimes
}
ret := make([]float64, len(cpuTimes1))
for i, t := range cpuTimes2 {
ret[i] = calculate(cpuTimes1[i], t)
if lastTimes == nil {
return nil, fmt.Errorf("Error getting times for cpu percent. LastTimes was nil")
}
return ret, nil
return calculateAllBusy(lastTimes, cpuTimes)
}

View File

@ -283,6 +283,10 @@ func IOCounters() (map[string]IOCountersStat, error) {
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) < 14 {
// malformed line in /proc/diskstats, avoid panic by ignoring.
continue
}
name := fields[2]
reads, err := strconv.ParseUint((fields[3]), 10, 64)
if err != nil {
@ -332,6 +336,8 @@ func IOCounters() (map[string]IOCountersStat, error) {
return ret, nil
}
// GetDiskSerialNumber returns Serial Number of given device or empty string
// on error. Name of device is expected, eg. /dev/sda
func GetDiskSerialNumber(name string) string {
n := fmt.Sprintf("--name=%s", name)
udevadm, err := exec.LookPath("/sbin/udevadm")

View File

@ -2,17 +2,25 @@ 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 {
Hostname string `json:"hostname"`
Uptime uint64 `json:"uptime"`
BootTime uint64 `json:"bootTime"`
Procs uint64 `json:"procs"` // number of processes
OS string `json:"os"` // ex: freebsd, linux
Platform string `json:"platform"` // ex: ubuntu, linuxmint
Procs uint64 `json:"procs"` // number of processes
OS string `json:"os"` // ex: freebsd, linux
Platform string `json:"platform"` // ex: ubuntu, linuxmint
PlatformFamily string `json:"platformFamily"` // ex: debian, rhel
PlatformVersion string `json:"platformVersion"`
VirtualizationSystem string `json:"virtualizationSystem"`

View File

@ -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)))
}

View File

@ -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)))
}

View File

@ -15,7 +15,7 @@ import (
"strings"
"time"
"github.com/shirou/gopsutil/internal/common"
common "github.com/shirou/gopsutil/internal/common"
)
type LSB struct {
@ -136,6 +136,26 @@ func Users() ([]UserStat, error) {
}
func getOSRelease() (platform string, version string, err error) {
contents, err := common.ReadLines(common.HostEtc("os-release"))
if err != nil {
return "", "", nil // return empty
}
for _, line := range contents {
field := strings.Split(line, "=")
if len(field) < 2 {
continue
}
switch field[0] {
case "ID": // use ID for lowercase
platform = field[1]
case "VERSION":
version = field[1]
}
}
return platform, version, nil
}
func getLSB() (*LSB, error) {
ret := &LSB{}
if common.PathExists(common.HostEtc("lsb-release")) {
@ -164,7 +184,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
}
@ -256,6 +276,18 @@ func PlatformInformation() (platform string, family string, version string, err
} else if common.PathExists(common.HostEtc("arch-release")) {
platform = "arch"
version = lsb.Release
} else if common.PathExists(common.HostEtc("alpine-release")) {
platform = "alpine"
contents, err := common.ReadLines(common.HostEtc("alpine-release"))
if err == nil && len(contents) > 0 {
version = contents[0]
}
} else if common.PathExists(common.HostEtc("os-release")) {
p, v, err := getOSRelease()
if err == nil {
platform = p
version = v
}
} else if lsb.ID == "RedHat" {
platform = "redhat"
version = lsb.Release
@ -290,6 +322,10 @@ func PlatformInformation() (platform string, family string, version string, err
family = "arch"
case "exherbo":
family = "exherbo"
case "alpine":
family = "alpine"
case "coreos":
family = "coreos"
}
return platform, family, version, nil
@ -351,7 +387,7 @@ func Virtualization() (string, string, error) {
if common.PathExists(filename + "/capabilities") {
contents, err := common.ReadLines(filename + "/capabilities")
if err == nil {
if common.StringsHas(contents, "control_d") {
if common.StringsContains(contents, "control_d") {
role = "host"
}
}
@ -379,9 +415,9 @@ func Virtualization() (string, string, error) {
if common.PathExists(filename) {
contents, err := common.ReadLines(filename)
if err == nil {
if common.StringsHas(contents, "QEMU Virtual CPU") ||
common.StringsHas(contents, "Common KVM processor") ||
common.StringsHas(contents, "Common 32-bit KVM processor") {
if common.StringsContains(contents, "QEMU Virtual CPU") ||
common.StringsContains(contents, "Common KVM processor") ||
common.StringsContains(contents, "Common 32-bit KVM processor") {
system = "kvm"
role = "guest"
}
@ -402,8 +438,8 @@ func Virtualization() (string, string, error) {
contents, err := common.ReadLines(filename + "/self/status")
if err == nil {
if common.StringsHas(contents, "s_context:") ||
common.StringsHas(contents, "VxID:") {
if common.StringsContains(contents, "s_context:") ||
common.StringsContains(contents, "VxID:") {
system = "linux-vserver"
}
// TODO: guest or host
@ -413,16 +449,28 @@ func Virtualization() (string, string, error) {
if common.PathExists(filename + "/self/cgroup") {
contents, err := common.ReadLines(filename + "/self/cgroup")
if err == nil {
if common.StringsHas(contents, "lxc") ||
common.StringsHas(contents, "docker") {
if common.StringsContains(contents, "lxc") {
system = "lxc"
role = "guest"
} else if common.PathExists("/usr/bin/lxc-version") { // TODO: which
} else if common.StringsContains(contents, "docker") {
system = "docker"
role = "guest"
} else if common.StringsContains(contents, "machine-rkt") {
system = "rkt"
role = "guest"
} else if common.PathExists("/usr/bin/lxc-version") {
system = "lxc"
role = "host"
}
}
}
if common.PathExists(common.HostEtc("os-release")) {
p, _, err := getOSRelease()
if err == nil && p == "coreos" {
system = "rkt" // Is it true?
role = "host"
}
}
return system, role, nil
}

View File

@ -1,3 +1,5 @@
// +build linux
// +build ppc64le
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_linux.go

View File

@ -50,7 +50,7 @@ func Info() (*InfoStat, error) {
boot, err := BootTime()
if err == nil {
ret.BootTime = boot
ret.Uptime = uptime(boot)
ret.Uptime, _ = Uptime()
}
procs, err := process.Pids()
@ -76,7 +76,7 @@ func GetOSInfo() (Win32_OperatingSystem, error) {
return dst[0], nil
}
func BootTime() (uint64, error) {
func Uptime() (uint64, error) {
if osInfo == nil {
_, err := GetOSInfo()
if err != nil {
@ -88,16 +88,16 @@ func BootTime() (uint64, error) {
return uint64(now.Sub(t).Seconds()), nil
}
func uptime(boot uint64) uint64 {
return uint64(time.Now().Unix()) - boot
func bootTime(up uint64) uint64 {
return uint64(time.Now().Unix()) - up
}
func Uptime() (uint64, error) {
boot, err := BootTime()
func BootTime() (uint64, error) {
up, err := Uptime()
if err != nil {
return 0, err
}
return uptime(boot), nil
return bootTime(up), nil
}
func PlatformInformation() (platform string, family string, version string, err error) {

View File

@ -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 {
@ -118,20 +127,20 @@ func IntToString(orig []int8) string {
}
func UintToString(orig []uint8) string {
ret := make([]byte, len(orig))
size := -1
for i, o := range orig {
if o == 0 {
size = i
break
}
ret[i] = byte(o)
}
if size == -1 {
size = len(orig)
}
ret := make([]byte, len(orig))
size := -1
for i, o := range orig {
if o == 0 {
size = i
break
}
ret[i] = byte(o)
}
if size == -1 {
size = len(orig)
}
return string(ret[0:size])
return string(ret[0:size])
}
func ByteToString(orig []byte) string {
@ -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
}
}

View File

@ -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.
//

View File

@ -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
}

View File

@ -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
}

View File

@ -18,15 +18,18 @@ func init() {
}
type IOCountersStat struct {
Name string `json:"name"` // interface name
Name string `json:"name"` // interface name
BytesSent uint64 `json:"bytesSent"` // number of bytes sent
BytesRecv uint64 `json:"bytesRecv"` // number of bytes received
PacketsSent uint64 `json:"packetsSent"` // number of packets sent
PacketsRecv uint64 `json:"packetsRecv"` // number of packets received
Errin uint64 `json:"errin"` // total number of errors while receiving
Errout uint64 `json:"errout"` // total number of errors while sending
Dropin uint64 `json:"dropin"` // total number of incoming packets which were dropped
Dropout uint64 `json:"dropout"` // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
Errin uint64 `json:"errin"` // total number of errors while receiving
Errout uint64 `json:"errout"` // total number of errors while sending
Dropin uint64 `json:"dropin"` // total number of incoming packets which were dropped
Dropout uint64 `json:"dropout"` // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
Fifoin uint64 `json:"fifoin"` // total number of FIFO buffers errors while receiving
Fifoout uint64 `json:"fifoout"` // total number of FIFO buffers errors while sending
}
// Addr is implemented compatibility to psutil

View File

@ -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
}

View File

@ -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
}

View File

@ -63,6 +63,10 @@ func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
if err != nil {
return ret, err
}
fifoIn, err := strconv.ParseUint(fields[4], 10, 64)
if err != nil {
return ret, err
}
bytesSent, err := strconv.ParseUint(fields[8], 10, 64)
if err != nil {
return ret, err
@ -79,6 +83,10 @@ func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
if err != nil {
return ret, err
}
fifoOut, err := strconv.ParseUint(fields[14], 10, 64)
if err != nil {
return ret, err
}
nic := IOCountersStat{
Name: interfaceName,
@ -86,10 +94,12 @@ func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
PacketsRecv: packetsRecv,
Errin: errIn,
Dropin: dropIn,
Fifoin: fifoIn,
BytesSent: bytesSent,
PacketsSent: packetsSent,
Errout: errOut,
Dropout: dropOut,
Fifoout: fifoOut,
}
ret = append(ret, nic)
}

View File

@ -0,0 +1,9 @@
// +build linux
// +build arm64
package process
const (
ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK)
PageSize = 4096 // C.sysconf(C._SC_PAGE_SIZE)
)

View File

@ -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
}

View File

@ -23,6 +23,11 @@ const (
MaxPathLength = 260
)
var (
modpsapi = syscall.NewLazyDLL("psapi.dll")
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
)
type SystemProcessInformation struct {
NextEntryOffset uint64
NumberOfThreads uint64
@ -46,13 +51,18 @@ type MemoryMapsStat struct {
}
type Win32_Process struct {
Name string
ExecutablePath *string
CommandLine *string
Priority uint32
CreationDate *time.Time
ProcessID uint32
ThreadCount uint32
Name string
ExecutablePath *string
CommandLine *string
Priority uint32
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
}

View File

@ -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
}

View File

@ -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
}

42
vendor/vendor.json vendored
View File

@ -666,52 +666,52 @@
"revision": "983d3a5fab1bf04d1b412465d2d9f8430e2e917e"
},
{
"checksumSHA1": "dtcffK/n1nDKPtvHg2GnU1C194s=",
"checksumSHA1": "G1oy2AGv5pCnNL0hRfg+mlX4Uq4=",
"comment": "1.0.0-230-gf58654f",
"path": "github.com/shirou/gopsutil/cpu",
"revision": "7b991b8135166c7fc81b65665a2f35c7a1966cfc",
"revisionTime": "2016-05-04T15:08:50Z"
"revision": "5c1bfed85550640833e8bbf50156d114ba99fbf2",
"revisionTime": "2016-06-17T08:26:08Z"
},
{
"checksumSHA1": "zs7XTdxVVhxUUwA4kSdSJlNfVZc=",
"checksumSHA1": "x4HZyWURx/UwxHVrdaTGbTFd198=",
"path": "github.com/shirou/gopsutil/disk",
"revision": "83c6e72cbdef6e8ada934549abf700ff0ba96776",
"revisionTime": "2016-05-20T22:39:10Z"
"revision": "5c1bfed85550640833e8bbf50156d114ba99fbf2",
"revisionTime": "2016-06-17T08:26:08Z"
},
{
"checksumSHA1": "lpPewrgMOYaTKZ0wRZpmZJxnEBw=",
"checksumSHA1": "tV0skuyoy255WiTlKjd24T+5DeU=",
"comment": "1.0.0-230-gf58654f",
"path": "github.com/shirou/gopsutil/host",
"revision": "7b991b8135166c7fc81b65665a2f35c7a1966cfc",
"revisionTime": "2016-05-04T15:08:50Z"
"revision": "5c1bfed85550640833e8bbf50156d114ba99fbf2",
"revisionTime": "2016-06-17T08:26:08Z"
},
{
"checksumSHA1": "xrMuUxCr8UckY5oI2lwCerYwIhk=",
"checksumSHA1": "zJZyxS96XiEnDJSZkWwXtktziRY=",
"comment": "1.0.0-230-gf58654f",
"path": "github.com/shirou/gopsutil/internal/common",
"revision": "7b991b8135166c7fc81b65665a2f35c7a1966cfc",
"revisionTime": "2016-05-04T15:08:50Z"
"revision": "5c1bfed85550640833e8bbf50156d114ba99fbf2",
"revisionTime": "2016-06-17T08:26:08Z"
},
{
"checksumSHA1": "bHTDi2QAN4SmdZpHOtyQ6fQeCnQ=",
"checksumSHA1": "LUipApIqOLcKbZfwXknNCifGles=",
"comment": "1.0.0-230-gf58654f",
"path": "github.com/shirou/gopsutil/mem",
"revision": "7b991b8135166c7fc81b65665a2f35c7a1966cfc",
"revisionTime": "2016-05-04T15:08:50Z"
"revision": "5c1bfed85550640833e8bbf50156d114ba99fbf2",
"revisionTime": "2016-06-17T08:26:08Z"
},
{
"checksumSHA1": "LHJDMUXWamoP/yje0R42k96OPG8=",
"checksumSHA1": "k57srhFXKSysrFdEh3b6oiO48hw=",
"comment": "1.0.0-230-gf58654f",
"path": "github.com/shirou/gopsutil/net",
"revision": "7b991b8135166c7fc81b65665a2f35c7a1966cfc",
"revisionTime": "2016-05-04T15:08:50Z"
"revision": "5c1bfed85550640833e8bbf50156d114ba99fbf2",
"revisionTime": "2016-06-17T08:26:08Z"
},
{
"checksumSHA1": "o544bXejDPLi6qpjHav8a91W4Ks=",
"checksumSHA1": "+m5V0QobB9gklJkz+zk0NvaSeOs=",
"comment": "1.0.0-230-gf58654f",
"path": "github.com/shirou/gopsutil/process",
"revision": "7b991b8135166c7fc81b65665a2f35c7a1966cfc",
"revisionTime": "2016-05-04T15:08:50Z"
"revision": "5c1bfed85550640833e8bbf50156d114ba99fbf2",
"revisionTime": "2016-06-17T08:26:08Z"
},
{
"path": "github.com/shirou/w32",