feat(macos): add Apple Silicon cpu frequency

This commit is contained in:
utox39
2025-03-20 13:43:09 +01:00
parent 7dba1c169c
commit 5fe913da11

View File

@@ -22,6 +22,7 @@ pub const SystemUptime = struct {
pub const CpuInfo = struct { pub const CpuInfo = struct {
cpu_name: []u8, cpu_name: []u8,
cpu_cores: i32, cpu_cores: i32,
cpu_max_freq: f64,
}; };
pub const GpuInfo = struct { pub const GpuInfo = struct {
@@ -160,12 +161,85 @@ pub fn getCpuInfo(allocator: std.mem.Allocator) !CpuInfo {
return error.FailedToGetPhysicalCpuInfo; return error.FailedToGetPhysicalCpuInfo;
} }
// TODO: add cpu frequency (find a way to get it even on Apple Silicon) // TODO: add cpu frequency for Intel
return CpuInfo{ const cpu_freq_mhz = try getCpuFreqAppleSilicon();
.cpu_name = cpu_name,
.cpu_cores = n_cpu, const cpu_freq_ghz = @floor(cpu_freq_mhz) / 1000;
};
return CpuInfo{ .cpu_name = cpu_name, .cpu_cores = n_cpu, .cpu_max_freq = cpu_freq_ghz };
}
fn getCpuFreqAppleSilicon() !f64 {
// https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/cpu/cpu_apple.c
// Retrieve the matching service for "pmgr"
// https://developer.apple.com/documentation/iokit/1514535-ioservicegetmatchingservice
const service = c_iokit.IOServiceGetMatchingService(c_iokit.kIOMasterPortDefault, c_iokit.IOServiceNameMatching("pmgr"));
if (service == c_iokit.FALSE) return error.NoMatchingService;
defer _ = c_iokit.IOObjectRelease(service);
// Check that the service conforms to "AppleARMIODevice"
// https://developer.apple.com/documentation/iokit/1514505-ioobjectconformsto
if (c_iokit.IOObjectConformsTo(service, "AppleARMIODevice") == c_iokit.FALSE) {
return error.NotAppleARMIODevice;
}
// CFSTR is a macro and can't be translated by Zig
// The CFString is created "manually"
const vs5s_key = c_iokit.CFStringCreateWithCString(c_iokit.kCFAllocatorDefault, "voltage-states5-sram", c_iokit.kCFStringEncodingUTF8);
if (vs5s_key == null) {
return error.FailedToCreateCFKey;
}
defer c_iokit.CFRelease(vs5s_key);
// Retrieve the property from the registry entry
// https://developer.apple.com/documentation/iokit/1514293-ioregistryentrycreatecfproperty
const freq_property = c_iokit.IORegistryEntryCreateCFProperty(service, vs5s_key, c_iokit.kCFAllocatorDefault, 0);
if (freq_property == null) return error.PropertyNotFound;
defer c_iokit.CFRelease(freq_property);
// Ensure the property is a CFData object
if (c_iokit.CFGetTypeID(freq_property) != c_cf.CFDataGetTypeID())
return error.InvalidPropertyType;
const freq_data = @as(*const c_iokit.__CFData, @ptrCast(freq_property));
// Get the length of the CFData
const freq_data_length = c_iokit.CFDataGetLength(freq_data);
// voltage-states5-sram stores supported <frequency / voltage> pairs of pcores from the lowest to the highest
if (freq_data_length == 0 or @as(u32, @intCast(freq_data_length)) % (@sizeOf(u32) * 2) != 0)
return error.InvalidVoltageStates5SramLength;
// Get data pointer
const freq_data_ptr = c_iokit.CFDataGetBytePtr(freq_data);
if (freq_data_ptr == null)
return error.InvalidVoltageStates5SramData;
const freq_array = @as([*]const u32, @ptrCast(@alignCast(freq_data_ptr)));
// The first element contains the minimum freq
var p_max: u32 = freq_array[0];
const total_elements = @as(u32, @intCast(freq_data_length)) / @sizeOf(u32);
// Iterate on values, starting at index 2, skipping voltage (each pair is <frequency, voltage>)
var i: usize = 2;
while (i < total_elements) : (i += 2) {
const current = freq_array[i];
if (current == 0) break;
if (current > p_max) {
p_max = current;
}
}
// Assume that p_max is in Hz, M1~M3
if (p_max > 100_000_000) {
return @as(f64, @floatFromInt(p_max)) / 1_000 / 1_000;
} else { // Assume that p_max is in kHz, M4 and later
return @as(f64, @floatFromInt(p_max)) / 1_000;
}
} }
/// Returns the gpu info. /// Returns the gpu info.