From 903277ce2f1501d31ea8fb03731a30b382ddd1a5 Mon Sep 17 00:00:00 2001 From: WAKAYAMA Shirou Date: Wed, 4 May 2016 22:39:44 +0900 Subject: [PATCH 1/2] [process]windows: implement process.MemoryInfo (but no swap) --- process/process_windows.go | 45 ++++++++++++++++++++++++++++++++++++++-- process/process_windows_386.go | 16 ++++++++++++++ process/process_windows_amd64.go | 16 ++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 process/process_windows_386.go create mode 100644 process/process_windows_amd64.go diff --git a/process/process_windows.go b/process/process_windows.go index 3176cde..e5852ae 100644 --- a/process/process_windows.go +++ b/process/process_windows.go @@ -23,6 +23,11 @@ const ( MaxPathLength = 260 ) +var ( + modpsapi = syscall.NewLazyDLL("psapi.dll") + procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") +) + type SystemProcessInformation struct { NextEntryOffset uint64 NumberOfThreads uint64 @@ -75,7 +80,7 @@ type Win32_Process struct { PeakPageFileUsage uint32 PeakVirtualSize uint64 PeakWorkingSetSize uint32 - PrivatePageCount uint64 + PrivatePageCount uint64 ReadOperationCount uint64 ReadTransferCount uint64 Status *string @@ -234,7 +239,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 +370,29 @@ func getProcInfo(pid int32) (*SystemProcessInformation, error) { return &sysProcInfo, 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 +} diff --git a/process/process_windows_386.go b/process/process_windows_386.go new file mode 100644 index 0000000..68f3153 --- /dev/null +++ b/process/process_windows_386.go @@ -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 +} diff --git a/process/process_windows_amd64.go b/process/process_windows_amd64.go new file mode 100644 index 0000000..df286df --- /dev/null +++ b/process/process_windows_amd64.go @@ -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 +} From ba34a3af8cc38f4c2bef584d184023121b29b23e Mon Sep 17 00:00:00 2001 From: WAKAYAMA Shirou Date: Wed, 4 May 2016 23:25:43 +0900 Subject: [PATCH 2/2] [process]windows: add IO counters and fix CreateTime --- README.rst | 4 +-- process/process_windows.go | 62 +++++++++++++++++++++++++++++++++------------- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/README.rst b/README.rst index b96fd5f..8a99795 100644 --- a/README.rst +++ b/README.rst @@ -187,13 +187,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 diff --git a/process/process_windows.go b/process/process_windows.go index e5852ae..c3d2837 100644 --- a/process/process_windows.go +++ b/process/process_windows.go @@ -51,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 @@ -80,15 +85,10 @@ type Win32_Process struct { PeakPageFileUsage uint32 PeakVirtualSize uint64 PeakWorkingSetSize uint32 - PrivatePageCount uint64 - ReadOperationCount uint64 - ReadTransferCount uint64 - Status *string + PrivatePageCount uint64 TerminationDate *time.Time UserModeTime uint64 WorkingSetSize uint64 - WriteOperationCount uint64 - WriteTransferCount uint64 */ } @@ -163,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) { @@ -212,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 @@ -371,6 +383,22 @@ 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))