mirror of
https://github.com/shirou/gopsutil.git
synced 2025-04-28 13:48:49 +08:00
disk_darwin: Add support for IOCounters using IOKit
This commit is contained in:
parent
f18f7dcbae
commit
b327360349
@ -87,10 +87,6 @@ func Partitions(all bool) ([]PartitionStat, error) {
|
|||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IOCounters() (map[string]IOCountersStat, error) {
|
|
||||||
return nil, common.ErrNotImplementedError
|
|
||||||
}
|
|
||||||
|
|
||||||
func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
|
func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
|
||||||
var _p0 unsafe.Pointer
|
var _p0 unsafe.Pointer
|
||||||
var bufsize uintptr
|
var bufsize uintptr
|
||||||
|
164
disk/disk_darwin.h
Normal file
164
disk/disk_darwin.h
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include <IOKit/IOKitLib.h>
|
||||||
|
#include <IOKit/storage/IOBlockStorageDriver.h>
|
||||||
|
#include <IOKit/storage/IOMedia.h>
|
||||||
|
#include <IOKit/IOBSD.h>
|
||||||
|
|
||||||
|
// The iterator of all things disk. Allocated by StartIOCounterFetch, released
|
||||||
|
// by EndIOCounterFetch.
|
||||||
|
static io_iterator_t diskIter;
|
||||||
|
|
||||||
|
// Begins fetching IO counters.
|
||||||
|
//
|
||||||
|
// Returns 1 if the fetch started successfully, false otherwise.
|
||||||
|
//
|
||||||
|
// If the fetch was started successfully, you must call EndIOCounterFetch once
|
||||||
|
// done to release resources.
|
||||||
|
int StartIOCounterFetch()
|
||||||
|
{
|
||||||
|
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
|
||||||
|
IOServiceMatching(kIOMediaClass),
|
||||||
|
&diskIter) != kIOReturnSuccess) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Releases resources from fetching IO counters.
|
||||||
|
void EndIOCounterFetch()
|
||||||
|
{
|
||||||
|
IOObjectRelease(diskIter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The current disk entry of interest. Allocated by FetchNextDisk(), released by
|
||||||
|
// ReadDiskInfo().
|
||||||
|
static io_registry_entry_t diskEntry;
|
||||||
|
|
||||||
|
// The parent of diskEntry. Same lifetimes.
|
||||||
|
static io_registry_entry_t parentEntry;
|
||||||
|
|
||||||
|
// Fetches the next disk. Note that a disk entry is allocated, and will be held
|
||||||
|
// until it is processed and freed by ReadDiskInfo.
|
||||||
|
int FetchNextDisk()
|
||||||
|
{
|
||||||
|
while ((diskEntry = IOIteratorNext(diskIter)) != 0) {
|
||||||
|
// We are iterating IOMedia. We need to get the parent too (IOBSD).
|
||||||
|
if (IORegistryEntryGetParentEntry(diskEntry, kIOServicePlane, &parentEntry) != kIOReturnSuccess) {
|
||||||
|
// something is wrong...
|
||||||
|
IOObjectRelease(diskEntry);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IOObjectConformsTo(parentEntry, "IOBlockStorageDriver")) {
|
||||||
|
// no use to us, try the next disk
|
||||||
|
IOObjectRelease(diskEntry);
|
||||||
|
IOObjectRelease(parentEntry);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Got a disk OK.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No more disks.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reads the current disk (from iteration) info into DiskInfo struct.
|
||||||
|
// Once done, all resources from the current iteration of reading are freed,
|
||||||
|
// ready for FetchNextDisk() to be called again.
|
||||||
|
int ReadDiskInfo(DiskInfo *info)
|
||||||
|
{
|
||||||
|
// Parent props. Allocated by us.
|
||||||
|
CFDictionaryRef parentProps = NULL;
|
||||||
|
|
||||||
|
// Disk props. Allocated by us.
|
||||||
|
CFDictionaryRef diskProps = NULL;
|
||||||
|
|
||||||
|
// Disk stats, fetched by us, but not allocated by us.
|
||||||
|
CFDictionaryRef stats = NULL;
|
||||||
|
|
||||||
|
if (IORegistryEntryCreateCFProperties(diskEntry, (CFMutableDictionaryRef *)&parentProps,
|
||||||
|
kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||||
|
{
|
||||||
|
// can't get parent props, give up
|
||||||
|
CFRelease(parentProps);
|
||||||
|
IOObjectRelease(diskEntry);
|
||||||
|
IOObjectRelease(parentEntry);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IORegistryEntryCreateCFProperties(parentEntry, (CFMutableDictionaryRef *)&diskProps,
|
||||||
|
kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||||
|
{
|
||||||
|
// can't get disk props, give up
|
||||||
|
CFRelease(parentProps);
|
||||||
|
CFRelease(diskProps);
|
||||||
|
IOObjectRelease(diskEntry);
|
||||||
|
IOObjectRelease(parentEntry);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start fetching
|
||||||
|
CFStringRef cfDiskName = (CFStringRef)CFDictionaryGetValue(parentProps, CFSTR(kIOBSDNameKey));
|
||||||
|
CFStringGetCString(cfDiskName, info->DiskName, MAX_DISK_NAME, CFStringGetSystemEncoding());
|
||||||
|
stats = (CFDictionaryRef)CFDictionaryGetValue( diskProps, CFSTR(kIOBlockStorageDriverStatisticsKey));
|
||||||
|
|
||||||
|
if (stats == NULL) {
|
||||||
|
// stat fetch failed...
|
||||||
|
CFRelease(parentProps);
|
||||||
|
CFRelease(diskProps);
|
||||||
|
IOObjectRelease(parentEntry);
|
||||||
|
IOObjectRelease(diskEntry);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFNumberRef cfnum;
|
||||||
|
|
||||||
|
if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) {
|
||||||
|
CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->Reads);
|
||||||
|
} else {
|
||||||
|
info->Reads = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) {
|
||||||
|
CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->Writes);
|
||||||
|
} else {
|
||||||
|
info->Writes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) {
|
||||||
|
CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->ReadBytes);
|
||||||
|
} else {
|
||||||
|
info->ReadBytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) {
|
||||||
|
CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->WriteBytes);
|
||||||
|
} else {
|
||||||
|
info->WriteBytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey)))) {
|
||||||
|
CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->ReadTime);
|
||||||
|
} else {
|
||||||
|
info->ReadTime = 0;
|
||||||
|
}
|
||||||
|
if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) {
|
||||||
|
CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->WriteTime);
|
||||||
|
} else {
|
||||||
|
info->WriteTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: read/write time are in ns, but we want ms.
|
||||||
|
info->ReadTime = info->ReadTime / 1000 / 1000;
|
||||||
|
info->WriteTime = info->WriteTime / 1000 / 1000;
|
||||||
|
|
||||||
|
CFRelease(parentProps);
|
||||||
|
CFRelease(diskProps);
|
||||||
|
IOObjectRelease(parentEntry);
|
||||||
|
IOObjectRelease(diskEntry);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
85
disk/disk_darwin_cgo.go
Normal file
85
disk/disk_darwin_cgo.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// +build darwin
|
||||||
|
// +build cgo
|
||||||
|
|
||||||
|
package disk
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -mmacosx-version-min=10.10 -DMACOSX_DEPLOYMENT_TARGET=10.10
|
||||||
|
#cgo LDFLAGS: -mmacosx-version-min=10.10 -lobjc -framework Foundation -framework IOKit
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// ### enough?
|
||||||
|
const int MAX_DISK_NAME = 100;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char DiskName[MAX_DISK_NAME];
|
||||||
|
int64_t Reads;
|
||||||
|
int64_t Writes;
|
||||||
|
int64_t ReadBytes;
|
||||||
|
int64_t WriteBytes;
|
||||||
|
int64_t ReadTime;
|
||||||
|
int64_t WriteTime;
|
||||||
|
} DiskInfo;
|
||||||
|
|
||||||
|
#include "disk_darwin.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IOCounters() (map[string]IOCountersStat, error) {
|
||||||
|
if C.StartIOCounterFetch() == 0 {
|
||||||
|
return nil, errors.New("Unable to fetch disk list")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up when we are done.
|
||||||
|
defer C.EndIOCounterFetch()
|
||||||
|
ret := make(map[string]IOCountersStat, 0)
|
||||||
|
|
||||||
|
for {
|
||||||
|
res := C.FetchNextDisk()
|
||||||
|
if res == -1 {
|
||||||
|
return nil, errors.New("Unable to fetch disk information")
|
||||||
|
} else if res == 0 {
|
||||||
|
break // done
|
||||||
|
}
|
||||||
|
|
||||||
|
di := C.DiskInfo{}
|
||||||
|
if C.ReadDiskInfo((*C.DiskInfo)(unsafe.Pointer(&di))) == -1 {
|
||||||
|
return nil, errors.New("Unable to fetch disk properties")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to only get the necessary part of the C string.
|
||||||
|
isRuneNull := func(r rune) bool {
|
||||||
|
return r == '\u0000'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map from the darwin-specific C struct to the Go type
|
||||||
|
//
|
||||||
|
// ### missing: IopsInProgress, WeightedIO, MergedReadCount,
|
||||||
|
// MergedWriteCount, SerialNumber
|
||||||
|
// IOKit can give us at least the serial number I think...
|
||||||
|
d := IOCountersStat{
|
||||||
|
// Note: The Go type wants unsigned values, but CFNumberGetValue
|
||||||
|
// doesn't appear to be able to give us unsigned values. So, we
|
||||||
|
// cast, and hope for the best.
|
||||||
|
ReadBytes: uint64(di.ReadBytes),
|
||||||
|
WriteBytes: uint64(di.WriteBytes),
|
||||||
|
ReadCount: uint64(di.Reads),
|
||||||
|
WriteCount: uint64(di.Writes),
|
||||||
|
ReadTime: uint64(di.ReadTime),
|
||||||
|
WriteTime: uint64(di.WriteTime),
|
||||||
|
IoTime: uint64(di.ReadTime + di.WriteTime),
|
||||||
|
Name: strings.TrimFunc(C.GoStringN(&di.DiskName[0], C.MAX_DISK_NAME), isRuneNull),
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[d.Name] = d
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
10
disk/disk_darwin_nocgo.go
Normal file
10
disk/disk_darwin_nocgo.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// +build darwin
|
||||||
|
// +build !cgo
|
||||||
|
|
||||||
|
package disk
|
||||||
|
|
||||||
|
import "github.com/shirou/gopsutil/internal/common"
|
||||||
|
|
||||||
|
func IOCounters() (map[string]IOCountersStat, error) {
|
||||||
|
return nil, common.ErrNotImplementedError
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user