mirror of https://github.com/shirou/gopsutil
Merge pull request #750 from Lomanic/issue560
[disk][darwin] Fix #560 using github.com/lufia/iostat cgo implementationpull/754/head
commit
fe02b2b4ba
@ -0,0 +1,131 @@
|
|||||||
|
// https://github.com/lufia/iostat/blob/9f7362b77ad333b26c01c99de52a11bdb650ded2/iostat_darwin.c
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include "disk_darwin.h"
|
||||||
|
|
||||||
|
#define IOKIT 1 /* to get io_name_t in device_types.h */
|
||||||
|
|
||||||
|
#include <IOKit/IOKitLib.h>
|
||||||
|
#include <IOKit/storage/IOBlockStorageDriver.h>
|
||||||
|
#include <IOKit/storage/IOMedia.h>
|
||||||
|
#include <IOKit/IOBSD.h>
|
||||||
|
|
||||||
|
#include <mach/mach_host.h>
|
||||||
|
|
||||||
|
static int getdrivestat(io_registry_entry_t d, DriveStats *stat);
|
||||||
|
static int fillstat(io_registry_entry_t d, DriveStats *stat);
|
||||||
|
|
||||||
|
int
|
||||||
|
readdrivestat(DriveStats a[], int n)
|
||||||
|
{
|
||||||
|
mach_port_t port;
|
||||||
|
CFMutableDictionaryRef match;
|
||||||
|
io_iterator_t drives;
|
||||||
|
io_registry_entry_t d;
|
||||||
|
kern_return_t status;
|
||||||
|
int na, rv;
|
||||||
|
|
||||||
|
IOMasterPort(bootstrap_port, &port);
|
||||||
|
match = IOServiceMatching("IOMedia");
|
||||||
|
CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
|
||||||
|
status = IOServiceGetMatchingServices(port, match, &drives);
|
||||||
|
if(status != KERN_SUCCESS)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
na = 0;
|
||||||
|
while(na < n && (d=IOIteratorNext(drives)) > 0){
|
||||||
|
rv = getdrivestat(d, &a[na]);
|
||||||
|
if(rv < 0)
|
||||||
|
return -1;
|
||||||
|
if(rv > 0)
|
||||||
|
na++;
|
||||||
|
IOObjectRelease(d);
|
||||||
|
}
|
||||||
|
IOObjectRelease(drives);
|
||||||
|
return na;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
getdrivestat(io_registry_entry_t d, DriveStats *stat)
|
||||||
|
{
|
||||||
|
io_registry_entry_t parent;
|
||||||
|
kern_return_t status;
|
||||||
|
CFDictionaryRef props;
|
||||||
|
CFStringRef name;
|
||||||
|
CFNumberRef num;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
memset(stat, 0, sizeof *stat);
|
||||||
|
status = IORegistryEntryGetParentEntry(d, kIOServicePlane, &parent);
|
||||||
|
if(status != KERN_SUCCESS)
|
||||||
|
return -1;
|
||||||
|
if(!IOObjectConformsTo(parent, "IOBlockStorageDriver")){
|
||||||
|
IOObjectRelease(parent);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = IORegistryEntryCreateCFProperties(d, (CFMutableDictionaryRef *)&props, kCFAllocatorDefault, kNilOptions);
|
||||||
|
if(status != KERN_SUCCESS){
|
||||||
|
IOObjectRelease(parent);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
name = (CFStringRef)CFDictionaryGetValue(props, CFSTR(kIOBSDNameKey));
|
||||||
|
CFStringGetCString(name, stat->name, NAMELEN, CFStringGetSystemEncoding());
|
||||||
|
num = (CFNumberRef)CFDictionaryGetValue(props, CFSTR(kIOMediaSizeKey));
|
||||||
|
CFNumberGetValue(num, kCFNumberSInt64Type, &stat->size);
|
||||||
|
num = (CFNumberRef)CFDictionaryGetValue(props, CFSTR(kIOMediaPreferredBlockSizeKey));
|
||||||
|
CFNumberGetValue(num, kCFNumberSInt64Type, &stat->blocksize);
|
||||||
|
CFRelease(props);
|
||||||
|
|
||||||
|
rv = fillstat(parent, stat);
|
||||||
|
IOObjectRelease(parent);
|
||||||
|
if(rv < 0)
|
||||||
|
return -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
char *key;
|
||||||
|
size_t off;
|
||||||
|
} statstab[] = {
|
||||||
|
{kIOBlockStorageDriverStatisticsBytesReadKey, offsetof(DriveStats, read)},
|
||||||
|
{kIOBlockStorageDriverStatisticsBytesWrittenKey, offsetof(DriveStats, written)},
|
||||||
|
{kIOBlockStorageDriverStatisticsReadsKey, offsetof(DriveStats, nread)},
|
||||||
|
{kIOBlockStorageDriverStatisticsWritesKey, offsetof(DriveStats, nwrite)},
|
||||||
|
{kIOBlockStorageDriverStatisticsTotalReadTimeKey, offsetof(DriveStats, readtime)},
|
||||||
|
{kIOBlockStorageDriverStatisticsTotalWriteTimeKey, offsetof(DriveStats, writetime)},
|
||||||
|
{kIOBlockStorageDriverStatisticsLatentReadTimeKey, offsetof(DriveStats, readlat)},
|
||||||
|
{kIOBlockStorageDriverStatisticsLatentWriteTimeKey, offsetof(DriveStats, writelat)},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
fillstat(io_registry_entry_t d, DriveStats *stat)
|
||||||
|
{
|
||||||
|
CFDictionaryRef props, v;
|
||||||
|
CFNumberRef num;
|
||||||
|
kern_return_t status;
|
||||||
|
typeof(statstab[0]) *bp, *ep;
|
||||||
|
|
||||||
|
status = IORegistryEntryCreateCFProperties(d, (CFMutableDictionaryRef *)&props, kCFAllocatorDefault, kNilOptions);
|
||||||
|
if(status != KERN_SUCCESS)
|
||||||
|
return -1;
|
||||||
|
v = (CFDictionaryRef)CFDictionaryGetValue(props, CFSTR(kIOBlockStorageDriverStatisticsKey));
|
||||||
|
if(v == NULL){
|
||||||
|
CFRelease(props);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ep = &statstab[sizeof(statstab)/sizeof(statstab[0])];
|
||||||
|
for(bp = &statstab[0]; bp < ep; bp++){
|
||||||
|
CFStringRef s;
|
||||||
|
|
||||||
|
s = CFStringCreateWithCString(kCFAllocatorDefault, bp->key, CFStringGetSystemEncoding());
|
||||||
|
num = (CFNumberRef)CFDictionaryGetValue(v, s);
|
||||||
|
if(num)
|
||||||
|
CFNumberGetValue(num, kCFNumberSInt64Type, ((char*)stat)+bp->off);
|
||||||
|
CFRelease(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(props);
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,164 +1,33 @@
|
|||||||
#include <CoreFoundation/CoreFoundation.h>
|
// https://github.com/lufia/iostat/blob/9f7362b77ad333b26c01c99de52a11bdb650ded2/iostat_darwin.h
|
||||||
#include <IOKit/IOKitLib.h>
|
typedef struct DriveStats DriveStats;
|
||||||
#include <IOKit/storage/IOBlockStorageDriver.h>
|
typedef struct CPUStats CPUStats;
|
||||||
#include <IOKit/storage/IOMedia.h>
|
|
||||||
#include <IOKit/IOBSD.h>
|
enum {
|
||||||
|
NDRIVE = 16,
|
||||||
// The iterator of all things disk. Allocated by StartIOCounterFetch, released
|
NAMELEN = 31
|
||||||
// by EndIOCounterFetch.
|
};
|
||||||
static io_iterator_t diskIter;
|
|
||||||
|
struct DriveStats {
|
||||||
// Begins fetching IO counters.
|
char name[NAMELEN+1];
|
||||||
//
|
int64_t size;
|
||||||
// Returns 1 if the fetch started successfully, false otherwise.
|
int64_t blocksize;
|
||||||
//
|
|
||||||
// If the fetch was started successfully, you must call EndIOCounterFetch once
|
int64_t read;
|
||||||
// done to release resources.
|
int64_t written;
|
||||||
int StartIOCounterFetch()
|
int64_t nread;
|
||||||
{
|
int64_t nwrite;
|
||||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
|
int64_t readtime;
|
||||||
IOServiceMatching(kIOMediaClass),
|
int64_t writetime;
|
||||||
&diskIter) != kIOReturnSuccess) {
|
int64_t readlat;
|
||||||
return 0;
|
int64_t writelat;
|
||||||
}
|
};
|
||||||
|
|
||||||
return 1;
|
struct CPUStats {
|
||||||
}
|
natural_t user;
|
||||||
|
natural_t nice;
|
||||||
// Releases resources from fetching IO counters.
|
natural_t sys;
|
||||||
void EndIOCounterFetch()
|
natural_t idle;
|
||||||
{
|
};
|
||||||
IOObjectRelease(diskIter);
|
|
||||||
}
|
extern int readdrivestat(DriveStats a[], int n);
|
||||||
|
extern int readcpustat(CPUStats *cpu);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue