mirror of
https://github.com/shirou/gopsutil.git
synced 2025-04-26 13:48:59 +08:00
[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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/shirou/gopsutil/internal/common"
|
"github.com/shirou/gopsutil/internal/common"
|
||||||
@ -23,18 +25,24 @@ var (
|
|||||||
FileReadOnlyVolume = int64(524288) // 0x00080000
|
FileReadOnlyVolume = int64(524288) // 0x00080000
|
||||||
)
|
)
|
||||||
|
|
||||||
type Win32_PerfFormattedData struct {
|
// diskPerformance is an equivalent representation of DISK_PERFORMANCE in the Windows API.
|
||||||
Name string
|
// https://docs.microsoft.com/fr-fr/windows/win32/api/winioctl/ns-winioctl-disk_performance
|
||||||
AvgDiskBytesPerRead uint64
|
type diskPerformance struct {
|
||||||
AvgDiskBytesPerWrite uint64
|
BytesRead int64
|
||||||
AvgDiskReadQueueLength uint64
|
BytesWritten int64
|
||||||
AvgDiskWriteQueueLength uint64
|
ReadTime int64
|
||||||
AvgDisksecPerRead uint64
|
WriteTime int64
|
||||||
AvgDisksecPerWrite uint64
|
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) {
|
func Usage(path string) (*UsageStat, error) {
|
||||||
return UsageWithContext(context.Background(), path)
|
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) {
|
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
|
||||||
ret := make(map[string]IOCountersStat, 0)
|
// https://github.com/giampaolo/psutil/blob/544e9daa4f66a9f80d7bf6c7886d693ee42f0a13/psutil/arch/windows/disk.c#L83
|
||||||
var dst []Win32_PerfFormattedData
|
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 {
|
if err != nil {
|
||||||
return ret, err
|
return drivemap, err
|
||||||
}
|
}
|
||||||
for _, d := range dst {
|
for _, v := range lpBuffer[:lpBufferLen] {
|
||||||
if len(d.Name) > 3 { // not get _Total or Harddrive
|
if 'A' <= v && v <= 'Z' {
|
||||||
continue
|
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) {
|
var diskPerformanceSize uint32
|
||||||
continue
|
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
|
||||||
ret[d.Name] = IOCountersStat{
|
}
|
||||||
Name: d.Name,
|
drivemap[path] = IOCountersStat{
|
||||||
ReadCount: uint64(d.AvgDiskReadQueueLength),
|
ReadBytes: uint64(diskPerformance.BytesRead),
|
||||||
WriteCount: d.AvgDiskWriteQueueLength,
|
WriteBytes: uint64(diskPerformance.BytesWritten),
|
||||||
ReadBytes: uint64(d.AvgDiskBytesPerRead),
|
ReadCount: uint64(diskPerformance.ReadCount),
|
||||||
WriteBytes: uint64(d.AvgDiskBytesPerWrite),
|
WriteCount: uint64(diskPerformance.WriteCount),
|
||||||
ReadTime: d.AvgDisksecPerRead,
|
ReadTime: uint64(diskPerformance.ReadTime / 10000 / 1000), // convert to ms: https://github.com/giampaolo/psutil/issues/1012
|
||||||
WriteTime: d.AvgDisksecPerWrite,
|
WriteTime: uint64(diskPerformance.WriteTime / 10000 / 1000),
|
||||||
|
Name: path,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret, nil
|
return drivemap, nil
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user