Files
MacMonitor/Sources/Telemetry/System/MMLoadAverageProvider.m
gronod 66401bec28
MacMonitor CI/CD Pipeline / Build & Test (Intel x86_64) (push) Canceled after 0s
feat(telemetry): implement load average and thread concurrency provider (fixes #7)
2026-09-08 12:33:14 +01:00

93 lines
3.2 KiB
Objective-C

#import "MMLoadAverageProvider.h"
#import <mach/mach.h>
#import <mach/processor_info.h>
#import <sys/sysctl.h>
#import <stdlib.h>
@implementation MMLoadAverageProvider
- (instancetype)init {
self = [super init];
return self;
}
- (MMTelemetryDomain)domain {
return MMTelemetryDomainSystem;
}
- (NSString *)providerIdentifier {
return @"com.i3omb.macmonitor.telemetry.system.load";
}
- (BOOL)isAvailable {
return YES;
}
+ (NSDictionary<NSString *, id> *)calculateLoadMetricsWithLoad1:(double)load1
load5:(double)load5
load15:(double)load15
taskCount:(int)taskCount
threadCount:(int)threadCount
cpuCount:(int)cpuCount
machFactor:(double)machFactor {
int safeCpus = cpuCount > 0 ? cpuCount : 1;
double norm1 = load1 / (double)safeCpus;
double norm5 = load5 / (double)safeCpus;
double norm15 = load15 / (double)safeCpus;
return @{
@"load1m": @(load1),
@"load5m": @(load5),
@"load15m": @(load15),
@"normalizedLoad1m": @(norm1),
@"normalizedLoad5m": @(norm5),
@"normalizedLoad15m": @(norm15),
@"taskCount": @(taskCount),
@"threadCount": @(threadCount),
@"logicalCpuCount": @(safeCpus),
@"machFactor": @(machFactor),
@"isOverloaded": @(norm1 > 1.0)
};
}
- (nullable NSDictionary<NSString *, id> *)sampleTelemetryWithError:(NSError **)error {
// 1. Get BSD load averages
double load[3] = {0.0, 0.0, 0.0};
int ret = getloadavg(load, 3);
if (ret <= 0) {
load[0] = 0.0;
load[1] = 0.0;
load[2] = 0.0;
}
// 2. Query Mach processor set for task & thread counts and mach factor
mach_port_t host = mach_host_self();
processor_set_name_port_t pset = MACH_PORT_NULL;
processor_set_load_info_data_t loadInfo = {0};
mach_msg_type_number_t count = PROCESSOR_SET_LOAD_INFO_COUNT;
kern_return_t kr = processor_set_default(host, &pset);
if (kr == KERN_SUCCESS && MACH_PORT_VALID(pset)) {
kr = processor_set_statistics(pset, PROCESSOR_SET_LOAD_INFO, (processor_set_info_t)&loadInfo, &count);
mach_port_deallocate(mach_task_self(), pset);
}
double machFactor = (double)loadInfo.mach_factor / (double)LOAD_SCALE;
// 3. Query logical CPU core count
int cpuCount = 1;
size_t size = sizeof(cpuCount);
sysctlbyname("hw.logicalcpu", &cpuCount, &size, NULL, 0);
if (cpuCount <= 0) cpuCount = 1;
return [MMLoadAverageProvider calculateLoadMetricsWithLoad1:load[0]
load5:load[1]
load15:load[2]
taskCount:loadInfo.task_count
threadCount:loadInfo.thread_count
cpuCount:cpuCount
machFactor:machFactor];
}
@end