From e7372d18a1a661d8c3dba9f51e1f17b5f94171a7 Mon Sep 17 00:00:00 2001 From: Daniel Lange Date: Wed, 10 Jan 2024 11:17:08 +0100 Subject: New upstream version 3.3.0 --- darwin/Platform.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 199 insertions(+), 33 deletions(-) (limited to 'darwin/Platform.c') diff --git a/darwin/Platform.c b/darwin/Platform.c index 4b34d88..387910e 100644 --- a/darwin/Platform.c +++ b/darwin/Platform.c @@ -14,16 +14,30 @@ in the source distribution for its full text. #include #include #include +#include +#include +#include +#include +#include + +#include +#include +#include #include #include + +#include +#include #include #include +#include #include "ClockMeter.h" #include "CPUMeter.h" #include "CRT.h" #include "DateMeter.h" #include "DateTimeMeter.h" +#include "FileDescriptorMeter.h" #include "HostnameMeter.h" #include "LoadAverageMeter.h" #include "Macros.h" @@ -34,8 +48,9 @@ in the source distribution for its full text. #include "SysArchMeter.h" #include "TasksMeter.h" #include "UptimeMeter.h" -#include "darwin/DarwinProcessList.h" +#include "darwin/DarwinMachine.h" #include "darwin/PlatformHelpers.h" +#include "generic/fdstat_sysctl.h" #include "zfs/ZfsArcMeter.h" #include "zfs/ZfsCompressedArcMeter.h" @@ -126,6 +141,9 @@ const MeterClass* const Platform_meterTypes[] = { &RightCPUs8Meter_class, &ZfsArcMeter_class, &ZfsCompressedArcMeter_class, + &DiskIOMeter_class, + &NetworkIOMeter_class, + &FileDescriptorMeter_class, &BlankMeter_class, NULL }; @@ -134,6 +152,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(); @@ -148,6 +169,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; } @@ -172,7 +204,7 @@ void Platform_setBindings(Htop_Action* keys) { (void) keys; } -int Platform_getUptime() { +int Platform_getUptime(void) { struct timeval bootTime, currTime; int mib[2] = { CTL_KERN, KERN_BOOTTIME }; size_t size = sizeof(bootTime); @@ -200,19 +232,19 @@ void Platform_getLoadAverage(double* one, double* five, double* fifteen) { } } -int Platform_getMaxPid() { +pid_t Platform_getMaxPid(void) { /* http://opensource.apple.com/source/xnu/xnu-2782.1.97/bsd/sys/proc_internal.hh */ return 99999; } static double Platform_setCPUAverageValues(Meter* mtr) { - const ProcessList* dpl = mtr->pl; - unsigned int activeCPUs = dpl->activeCPUs; + const Machine* host = mtr->host; + unsigned int activeCPUs = host->activeCPUs; double sumNice = 0.0; double sumNormal = 0.0; double sumKernel = 0.0; double sumPercent = 0.0; - for (unsigned int i = 1; i <= dpl->existingCPUs; i++) { + for (unsigned int i = 1; i <= host->existingCPUs; i++) { sumPercent += Platform_setCPUValues(mtr, i); sumNice += mtr->values[CPU_METER_NICE]; sumNormal += mtr->values[CPU_METER_NORMAL]; @@ -230,9 +262,9 @@ double Platform_setCPUValues(Meter* mtr, unsigned int cpu) { return Platform_setCPUAverageValues(mtr); } - const DarwinProcessList* dpl = (const DarwinProcessList*)mtr->pl; - const processor_cpu_load_info_t prev = &dpl->prev_load[cpu - 1]; - const processor_cpu_load_info_t curr = &dpl->curr_load[cpu - 1]; + const DarwinMachine* dhost = (const DarwinMachine*) mtr->host; + const processor_cpu_load_info_t prev = &dhost->prev_load[cpu - 1]; + const processor_cpu_load_info_t curr = &dhost->curr_load[cpu - 1]; double total = 0; /* Take the sums */ @@ -259,16 +291,17 @@ double Platform_setCPUValues(Meter* mtr, unsigned int cpu) { } void Platform_setMemoryValues(Meter* mtr) { - const DarwinProcessList* dpl = (const DarwinProcessList*)mtr->pl; - const struct vm_statistics* vm = &dpl->vm_stats; + const DarwinMachine* dhost = (const DarwinMachine*) mtr->host; + const struct vm_statistics* vm = &dhost->vm_stats; double page_K = (double)vm_page_size / (double)1024; - mtr->total = dpl->host_info.max_mem / 1024; - mtr->values[0] = (double)(vm->active_count + vm->wire_count) * page_K; - mtr->values[1] = (double)vm->purgeable_count * page_K; - // mtr->values[2] = "shared memory, like tmpfs and shm" - mtr->values[3] = (double)vm->inactive_count * page_K; - // mtr->values[4] = "available memory" + mtr->total = dhost->host_info.max_mem / 1024; + mtr->values[MEMORY_METER_USED] = (double)(vm->active_count + vm->wire_count) * page_K; + // mtr->values[MEMORY_METER_SHARED] = "shared memory, like tmpfs and shm" + // mtr->values[MEMORY_METER_COMPRESSED] = "compressed memory, like zswap on linux" + mtr->values[MEMORY_METER_BUFFERS] = (double)vm->purgeable_count * page_K; + mtr->values[MEMORY_METER_CACHE] = (double)vm->inactive_count * page_K; + // mtr->values[MEMORY_METER_AVAILABLE] = "available memory" } void Platform_setSwapValues(Meter* mtr) { @@ -278,19 +311,21 @@ void Platform_setSwapValues(Meter* mtr) { sysctl(mib, 2, &swapused, &swlen, NULL, 0); mtr->total = swapused.xsu_total / 1024; - mtr->values[0] = swapused.xsu_used / 1024; + mtr->values[SWAP_METER_USED] = swapused.xsu_used / 1024; + // mtr->values[SWAP_METER_CACHE] = "pages that are both in swap and RAM, like SwapCached on linux" + // mtr->values[SWAP_METER_FRONTSWAP] = "pages that are accounted to swap but stored elsewhere, like frontswap on linux" } void Platform_setZfsArcValues(Meter* this) { - const DarwinProcessList* dpl = (const DarwinProcessList*) this->pl; + const DarwinMachine* dhost = (const DarwinMachine*) this->host; - ZfsArcMeter_readStats(this, &(dpl->zfs)); + ZfsArcMeter_readStats(this, &dhost->zfs); } void Platform_setZfsCompressedArcValues(Meter* this) { - const DarwinProcessList* dpl = (const DarwinProcessList*) this->pl; + const DarwinMachine* dhost = (const DarwinMachine*) this->host; - ZfsCompressedArcMeter_readStats(this, &(dpl->zfs)); + ZfsCompressedArcMeter_readStats(this, &dhost->zfs); } char* Platform_getProcessEnv(pid_t pid) { @@ -344,27 +379,158 @@ char* Platform_getProcessEnv(pid_t pid) { return env; } -char* Platform_getInodeFilename(pid_t pid, ino_t inode) { +FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) { (void)pid; - (void)inode; return NULL; } -FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) { - (void)pid; - return NULL; +void Platform_getFileDescriptors(double* used, double* max) { + Generic_getFileDescriptors_sysctl(used, 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; } +/* Caution: Given that interfaces are dynamic, and it is not possible to get statistics on interfaces that no longer exist, + if some interface disappears between the time of two samples, the values of the second sample may be lower than those of + the first one. */ bool Platform_getNetworkIO(NetworkIOData* data) { - // TODO - (void)data; - return false; + int mib[6] = {CTL_NET, + PF_ROUTE, /* routing messages */ + 0, /* protocal number, currently always 0 */ + 0, /* select all address families */ + NET_RT_IFLIST2, /* interface list with addresses */ + 0}; + + for (size_t retry = 0; retry < 4; retry++) { + size_t len = 0; + + /* Determine len */ + if (sysctl(mib, ARRAYSIZE(mib), NULL, &len, NULL, 0) < 0 || len == 0) + return false; + + len += 16 * retry * retry * sizeof(struct if_msghdr2); + char *buf = xMalloc(len); + + if (sysctl(mib, ARRAYSIZE(mib), buf, &len, NULL, 0) < 0) { + free(buf); + if (errno == ENOMEM && retry < 3) + continue; + else + return false; + } + + uint64_t bytesReceived_sum = 0, packetsReceived_sum = 0, bytesTransmitted_sum = 0, packetsTransmitted_sum = 0; + + for (char *next = buf; next < buf + len;) { + void *tmp = (void*) next; + struct if_msghdr *ifm = (struct if_msghdr*) tmp; + + next += ifm->ifm_msglen; + + if (ifm->ifm_type != RTM_IFINFO2) + continue; + + struct if_msghdr2 *ifm2 = (struct if_msghdr2*) ifm; + + if (ifm2->ifm_data.ifi_type != IFT_LOOP) { /* do not count loopback traffic */ + bytesReceived_sum += ifm2->ifm_data.ifi_ibytes; + packetsReceived_sum += ifm2->ifm_data.ifi_ipackets; + bytesTransmitted_sum += ifm2->ifm_data.ifi_obytes; + packetsTransmitted_sum += ifm2->ifm_data.ifi_opackets; + } + } + + data->bytesReceived = bytesReceived_sum; + data->packetsReceived = packetsReceived_sum; + data->bytesTransmitted = bytesTransmitted_sum; + data->packetsTransmitted = packetsTransmitted_sum; + + free(buf); + } + + return true; } void Platform_getBattery(double* percent, ACPresence* isOnAC) { -- cgit v1.2.3