136 lines
4.5 KiB
Objective-C
136 lines
4.5 KiB
Objective-C
#import "MMMemoryTelemetryProvider.h"
|
|
#import <sys/sysctl.h>
|
|
|
|
@interface MMMemoryTelemetryProvider () {
|
|
uint64_t _totalPhysicalMemoryBytes;
|
|
vm_size_t _pageSize;
|
|
}
|
|
@end
|
|
|
|
@implementation MMMemoryTelemetryProvider
|
|
|
|
- (instancetype)init {
|
|
self = [super init];
|
|
if (self) {
|
|
// Read physical memory size
|
|
uint64_t memSize = 0;
|
|
size_t size = sizeof(memSize);
|
|
sysctlbyname("hw.memsize", &memSize, &size, NULL, 0);
|
|
_totalPhysicalMemoryBytes = memSize;
|
|
|
|
// Read virtual memory page size
|
|
vm_size_t pSize = 4096;
|
|
host_page_size(mach_host_self(), &pSize);
|
|
_pageSize = pSize;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (MMTelemetryDomain)domain {
|
|
return MMTelemetryDomainMemory;
|
|
}
|
|
|
|
- (NSString *)providerIdentifier {
|
|
return @"com.i3omb.macmonitor.telemetry.memory";
|
|
}
|
|
|
|
- (BOOL)isAvailable {
|
|
return YES;
|
|
}
|
|
|
|
- (uint64_t)totalPhysicalMemoryBytes {
|
|
return _totalPhysicalMemoryBytes;
|
|
}
|
|
|
|
+ (NSDictionary<NSString *, id> *)calculateMemoryMetricsWithVMInfo:(const vm_statistics64_data_t *)vmInfo
|
|
pageSize:(vm_size_t)pageSize
|
|
totalPhysicalRAM:(uint64_t)totalRAM
|
|
swapUsage:(const struct xsw_usage * _Nullable)swap {
|
|
if (!vmInfo) return @{};
|
|
|
|
uint64_t appMemory = (vmInfo->internal_page_count > vmInfo->purgeable_count)
|
|
? (uint64_t)(vmInfo->internal_page_count - vmInfo->purgeable_count) * pageSize
|
|
: 0;
|
|
uint64_t wired = (uint64_t)vmInfo->wire_count * pageSize;
|
|
uint64_t compressed = (uint64_t)vmInfo->compressor_page_count * pageSize;
|
|
uint64_t used = appMemory + wired + compressed;
|
|
|
|
uint64_t freeRAM = (uint64_t)vmInfo->free_count * pageSize;
|
|
uint64_t purgeable = (uint64_t)vmInfo->purgeable_count * pageSize;
|
|
uint64_t active = (uint64_t)vmInfo->active_count * pageSize;
|
|
uint64_t inactive = (uint64_t)vmInfo->inactive_count * pageSize;
|
|
|
|
// Calculate Memory Pressure percentage
|
|
uint64_t availableForUse = (uint64_t)(vmInfo->free_count + vmInfo->inactive_count) * pageSize;
|
|
double pressurePct = 0.0;
|
|
if (totalRAM > 0) {
|
|
pressurePct = (1.0 - ((double)availableForUse / (double)totalRAM)) * 100.0;
|
|
if (pressurePct < 0.0) pressurePct = 0.0;
|
|
if (pressurePct > 100.0) pressurePct = 100.0;
|
|
}
|
|
|
|
NSString *pressureStatus = @"Normal";
|
|
if (pressurePct >= 80.0) {
|
|
pressureStatus = @"Critical";
|
|
} else if (pressurePct >= 60.0) {
|
|
pressureStatus = @"Warning";
|
|
}
|
|
|
|
uint64_t swapTotal = swap ? swap->xsu_total : 0;
|
|
uint64_t swapUsed = swap ? swap->xsu_used : 0;
|
|
uint64_t swapFree = swap ? swap->xsu_avail : 0;
|
|
|
|
return @{
|
|
@"totalBytes": @(totalRAM),
|
|
@"usedBytes": @(used),
|
|
@"freeBytes": @(freeRAM),
|
|
@"appMemoryBytes": @(appMemory),
|
|
@"wiredBytes": @(wired),
|
|
@"compressedBytes": @(compressed),
|
|
@"purgeableBytes": @(purgeable),
|
|
@"activeBytes": @(active),
|
|
@"inactiveBytes": @(inactive),
|
|
@"memoryPressurePercent": @(pressurePct),
|
|
@"memoryPressureStatus": pressureStatus,
|
|
@"swapTotalBytes": @(swapTotal),
|
|
@"swapUsedBytes": @(swapUsed),
|
|
@"swapFreeBytes": @(swapFree)
|
|
};
|
|
}
|
|
|
|
- (nullable NSDictionary<NSString *, id> *)sampleTelemetryWithError:(NSError **)error {
|
|
vm_statistics64_data_t vmInfo = {0};
|
|
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
|
|
|
|
kern_return_t kr = host_statistics64(
|
|
mach_host_self(),
|
|
HOST_VM_INFO64,
|
|
(host_info64_t)&vmInfo,
|
|
&count
|
|
);
|
|
|
|
if (kr != KERN_SUCCESS) {
|
|
if (error) {
|
|
*error = [NSError errorWithDomain:@"com.i3omb.MacMonitor.Memory"
|
|
code:kr
|
|
userInfo:@{NSLocalizedDescriptionKey: @"host_statistics64 failed to sample VM metrics"}];
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
// Read swap usage
|
|
struct xsw_usage swap = {0};
|
|
size_t swapSize = sizeof(swap);
|
|
struct xsw_usage *swapPtr = NULL;
|
|
if (sysctlbyname("vm.swapusage", &swap, &swapSize, NULL, 0) == 0) {
|
|
swapPtr = &swap;
|
|
}
|
|
|
|
return [MMMemoryTelemetryProvider calculateMemoryMetricsWithVMInfo:&vmInfo
|
|
pageSize:_pageSize
|
|
totalPhysicalRAM:_totalPhysicalMemoryBytes
|
|
swapUsage:swapPtr];
|
|
}
|
|
|
|
@end
|