[process][windows] Fix #846 use win32 API in disk.IOCounters() instead of slow WMI call returning wrong values
This commit is contained in:
parent
a3b23c5ccf
commit
f98100720e
|
@ -5,6 +5,8 @@ package disk
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
|
@ -23,18 +25,24 @@ var (
|
|||
FileReadOnlyVolume = int64(524288) // 0x00080000
|
||||
)
|
||||
|
||||
type Win32_PerfFormattedData struct {
|
||||
Name string
|
||||
AvgDiskBytesPerRead uint64
|
||||
AvgDiskBytesPerWrite uint64
|
||||
AvgDiskReadQueueLength uint64
|
||||
AvgDiskWriteQueueLength uint64
|
||||
AvgDisksecPerRead uint64
|
||||
AvgDisksecPerWrite uint64
|
||||
// diskPerformance is an equivalent representation of DISK_PERFORMANCE in the Windows API.
|
||||
// https://docs.microsoft.com/fr-fr/windows/win32/api/winioctl/ns-winioctl-disk_performance
|
||||
type diskPerformance struct {
|
||||
BytesRead int64
|
||||
BytesWritten int64
|
||||
ReadTime int64
|
||||
WriteTime int64
|
||||
IdleTime int64
|
||||
ReadCount uint32
|
||||
WriteCount uint32
|
||||
QueueDepth uint32
|
||||
SplitCount uint32
|
||||
QueryTime int64
|
||||
StorageDeviceNumber uint32
|
||||
StorageManagerName [8]uint16
|
||||
alignmentPadding uint32 // necessary for 32bit support, see https://github.com/elastic/beats/pull/16553
|
||||
}
|
||||
|
||||
const WaitMSec = 500
|
||||
|
||||
func Usage(path string) (*UsageStat, error) {
|
||||
return UsageWithContext(context.Background(), path)
|
||||
}
|
||||
|
@ -136,31 +144,52 @@ func IOCounters(names ...string) (map[string]IOCountersStat, error) {
|
|||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
|
||||
ret := make(map[string]IOCountersStat, 0)
|
||||
var dst []Win32_PerfFormattedData
|
||||
// https://github.com/giampaolo/psutil/blob/544e9daa4f66a9f80d7bf6c7886d693ee42f0a13/psutil/arch/windows/disk.c#L83
|
||||
drivemap := make(map[string]IOCountersStat, 0)
|
||||
var diskPerformance diskPerformance
|
||||
|
||||
err := common.WMIQueryWithContext(ctx, "SELECT * FROM Win32_PerfFormattedData_PerfDisk_LogicalDisk", &dst)
|
||||
lpBuffer := make([]uint16, 254)
|
||||
lpBufferLen, err := windows.GetLogicalDriveStrings(uint32(len(lpBuffer)), &lpBuffer[0])
|
||||
if err != nil {
|
||||
return ret, err
|
||||
return drivemap, err
|
||||
}
|
||||
for _, d := range dst {
|
||||
if len(d.Name) > 3 { // not get _Total or Harddrive
|
||||
continue
|
||||
}
|
||||
for _, v := range lpBuffer[:lpBufferLen] {
|
||||
if 'A' <= v && v <= 'Z' {
|
||||
path := string(v) + ":"
|
||||
typepath, _ := windows.UTF16PtrFromString(path)
|
||||
typeret := windows.GetDriveType(typepath)
|
||||
if typeret == 0 {
|
||||
return drivemap, windows.GetLastError()
|
||||
}
|
||||
if typeret != windows.DRIVE_FIXED {
|
||||
continue
|
||||
}
|
||||
szDevice := fmt.Sprintf(`\\.\%s`, path)
|
||||
const IOCTL_DISK_PERFORMANCE = 0x70020
|
||||
h, err := windows.CreateFile(syscall.StringToUTF16Ptr(szDevice), 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, nil, windows.OPEN_EXISTING, 0, 0)
|
||||
if err != nil {
|
||||
if err == windows.ERROR_FILE_NOT_FOUND {
|
||||
continue
|
||||
}
|
||||
return drivemap, err
|
||||
}
|
||||
defer windows.CloseHandle(h)
|
||||
|
||||
if len(names) > 0 && !common.StringsHas(names, d.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
ret[d.Name] = IOCountersStat{
|
||||
Name: d.Name,
|
||||
ReadCount: uint64(d.AvgDiskReadQueueLength),
|
||||
WriteCount: d.AvgDiskWriteQueueLength,
|
||||
ReadBytes: uint64(d.AvgDiskBytesPerRead),
|
||||
WriteBytes: uint64(d.AvgDiskBytesPerWrite),
|
||||
ReadTime: d.AvgDisksecPerRead,
|
||||
WriteTime: d.AvgDisksecPerWrite,
|
||||
var diskPerformanceSize uint32
|
||||
err = windows.DeviceIoControl(h, IOCTL_DISK_PERFORMANCE, nil, 0, (*byte)(unsafe.Pointer(&diskPerformance)), uint32(unsafe.Sizeof(diskPerformance)), &diskPerformanceSize, nil)
|
||||
if err != nil {
|
||||
return drivemap, err
|
||||
}
|
||||
drivemap[path] = IOCountersStat{
|
||||
ReadBytes: uint64(diskPerformance.BytesRead),
|
||||
WriteBytes: uint64(diskPerformance.BytesWritten),
|
||||
ReadCount: uint64(diskPerformance.ReadCount),
|
||||
WriteCount: uint64(diskPerformance.WriteCount),
|
||||
ReadTime: uint64(diskPerformance.ReadTime / 10000 / 1000), // convert to ms: https://github.com/giampaolo/psutil/issues/1012
|
||||
WriteTime: uint64(diskPerformance.WriteTime / 10000 / 1000),
|
||||
Name: path,
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
return drivemap, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue