Skip to content

Commit

Permalink
Darwin: add DiskIOMeter support
Browse files Browse the repository at this point in the history
  • Loading branch information
UeiWang authored and BenBE committed Apr 22, 2023
1 parent 7a7c693 commit ed7eac5
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 3 deletions.
2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ AC_CHECK_FUNCS([ \

if test "$my_htop_platform" = darwin; then
AC_CHECK_FUNCS([mach_timebase_info])
AC_CHECK_DECLS([IOMainPort], [], [], [[#include <IOKit/IOKitLib.h>]])
AC_CHECK_DECLS([IOMasterPort], [], [], [[#include <IOKit/IOKitLib.h>]])
fi

if test "$my_htop_platform" = pcp; then
Expand Down
108 changes: 105 additions & 3 deletions darwin/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,19 @@ in the source distribution for its full text.
#include <math.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/_types/_mach_port_t.h>

#include <CoreFoundation/CFBase.h>
#include <CoreFoundation/CFDictionary.h>
#include <CoreFoundation/CFNumber.h>
#include <CoreFoundation/CFString.h>
#include <CoreFoundation/CoreFoundation.h>

#include <IOKit/IOKitLib.h>
#include <IOKit/IOTypes.h>
#include <IOKit/ps/IOPowerSources.h>
#include <IOKit/ps/IOPSKeys.h>
#include <IOKit/storage/IOBlockStorageDriver.h>

#include "ClockMeter.h"
#include "CPUMeter.h"
Expand Down Expand Up @@ -128,6 +137,7 @@ const MeterClass* const Platform_meterTypes[] = {
&RightCPUs8Meter_class,
&ZfsArcMeter_class,
&ZfsCompressedArcMeter_class,
&DiskIOMeter_class,
&FileDescriptorMeter_class,
&BlankMeter_class,
NULL
Expand All @@ -137,6 +147,9 @@ static double Platform_nanosecondsPerMachTick = 1.0;

static double Platform_nanosecondsPerSchedulerTick = -1;

static bool iokit_available = false;
static mach_port_t iokit_port; // the mach port used to initiate communication with IOKit

bool Platform_init(void) {
Platform_nanosecondsPerMachTick = Platform_calculateNanosecondsPerMachTick();

Expand All @@ -151,6 +164,17 @@ bool Platform_init(void) {
const double nanos_per_sec = 1e9;
Platform_nanosecondsPerSchedulerTick = nanos_per_sec / scheduler_ticks_per_sec;

// Since macOS 12.0, IOMasterPort is deprecated, and one should use IOMainPort instead
#if defined(HAVE_DECL_IOMAINPORT) && HAVE_DECL_IOMAINPORT
if (!IOMainPort(bootstrap_port, &iokit_port)) {
iokit_available = true;
}
#elif defined(HAVE_DECL_IOMASTERPORT) && HAVE_DECL_IOMASTERPORT
if (!IOMasterPort(bootstrap_port, &iokit_port)) {
iokit_available = true;
}
#endif

return true;
}

Expand Down Expand Up @@ -357,9 +381,87 @@ void Platform_getFileDescriptors(double* used, double* max) {
}

bool Platform_getDiskIO(DiskIOData* data) {
// TODO
(void)data;
return false;
if (!iokit_available)
return false;

io_iterator_t drive_list;

/* Get the list of all drives */
if (IOServiceGetMatchingServices(iokit_port, IOServiceMatching("IOBlockStorageDriver"), &drive_list))
return false;

unsigned long long int read_sum = 0, write_sum = 0, timeSpend_sum = 0;

io_registry_entry_t drive;
while ((drive = IOIteratorNext(drive_list)) != 0) {
CFMutableDictionaryRef properties_tmp = NULL;

/* Get the properties of this drive */
if (IORegistryEntryCreateCFProperties(drive, &properties_tmp, kCFAllocatorDefault, 0)) {
IOObjectRelease(drive);
IOObjectRelease(drive_list);
return false;
}

if (!properties_tmp) {
IOObjectRelease(drive);
continue;
}

CFDictionaryRef properties = properties_tmp;

/* Get the statistics of this drive */
CFDictionaryRef statistics = (CFDictionaryRef) CFDictionaryGetValue(properties, CFSTR(kIOBlockStorageDriverStatisticsKey));

if (!statistics) {
CFRelease(properties);
IOObjectRelease(drive);
continue;
}

CFNumberRef number;
unsigned long long int value;

/* Get bytes read */
number = (CFNumberRef) CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey));
if (number != 0) {
CFNumberGetValue(number, kCFNumberSInt64Type, &value);
read_sum += value;
}

/* Get bytes written */
number = (CFNumberRef) CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey));
if (number != 0) {
CFNumberGetValue(number, kCFNumberSInt64Type, &value);
write_sum += value;
}

/* Get total read time (in ns) */
number = (CFNumberRef) CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey));
if (number != 0) {
CFNumberGetValue(number, kCFNumberSInt64Type, &value);
timeSpend_sum += value;
}

/* Get total write time (in ns) */
number = (CFNumberRef) CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey));
if (number != 0) {
CFNumberGetValue(number, kCFNumberSInt64Type, &value);
timeSpend_sum += value;
}

CFRelease(properties);
IOObjectRelease(drive);
}

data->totalBytesRead = read_sum;
data->totalBytesWritten = write_sum;
data->totalMsTimeSpend = timeSpend_sum / 1e6; /* Convert from ns to ms */

if (drive_list)
IOObjectRelease(drive_list);

return true;
}

bool Platform_getNetworkIO(NetworkIOData* data) {
Expand Down

0 comments on commit ed7eac5

Please sign in to comment.