|
|
@ -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 len(names) > 0 && !common.StringsHas(names, d.Name) {
|
|
|
|
if typeret == 0 {
|
|
|
|
continue
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
ret[d.Name] = IOCountersStat{
|
|
|
|
var diskPerformanceSize uint32
|
|
|
|
Name: d.Name,
|
|
|
|
err = windows.DeviceIoControl(h, IOCTL_DISK_PERFORMANCE, nil, 0, (*byte)(unsafe.Pointer(&diskPerformance)), uint32(unsafe.Sizeof(diskPerformance)), &diskPerformanceSize, nil)
|
|
|
|
ReadCount: uint64(d.AvgDiskReadQueueLength),
|
|
|
|
if err != nil {
|
|
|
|
WriteCount: d.AvgDiskWriteQueueLength,
|
|
|
|
return drivemap, err
|
|
|
|
ReadBytes: uint64(d.AvgDiskBytesPerRead),
|
|
|
|
}
|
|
|
|
WriteBytes: uint64(d.AvgDiskBytesPerWrite),
|
|
|
|
drivemap[path] = IOCountersStat{
|
|
|
|
ReadTime: d.AvgDisksecPerRead,
|
|
|
|
ReadBytes: uint64(diskPerformance.BytesRead),
|
|
|
|
WriteTime: d.AvgDisksecPerWrite,
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|