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>
|
||||
#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;
|
||||
}
|
||||
|
||||
// https://github.com/lufia/iostat/blob/9f7362b77ad333b26c01c99de52a11bdb650ded2/iostat_darwin.h
|
||||
typedef struct DriveStats DriveStats;
|
||||
typedef struct CPUStats CPUStats;
|
||||
|
||||
enum {
|
||||
NDRIVE = 16,
|
||||
NAMELEN = 31
|
||||
};
|
||||
|
||||
struct DriveStats {
|
||||
char name[NAMELEN+1];
|
||||
int64_t size;
|
||||
int64_t blocksize;
|
||||
|
||||
int64_t read;
|
||||
int64_t written;
|
||||
int64_t nread;
|
||||
int64_t nwrite;
|
||||
int64_t readtime;
|
||||
int64_t writetime;
|
||||
int64_t readlat;
|
||||
int64_t writelat;
|
||||
};
|
||||
|
||||
struct CPUStats {
|
||||
natural_t user;
|
||||
natural_t nice;
|
||||
natural_t sys;
|
||||
natural_t idle;
|
||||
};
|
||||
|
||||
extern int readdrivestat(DriveStats a[], int n);
|
||||
extern int readcpustat(CPUStats *cpu);
|
||||
|
Loading…
Reference in New Issue