I'm trying to get the current CPU load as a percentage, but when I try with the code below, the data I get is absurd
print(stats.cpu_ticks)
not much changes
time | cpu_tick[0] | cpu_tick[1] | cpu_tick[2] | cpu_tick[3] |
---|---|---|---|---|
1s | 1810101 | 782080 | 22191087 | 0 |
2s | 1810214 | 782122 | 22191725 | 0 |
3s | 1810322 | 782158 | 22192376 | 0 |
print("\tSYSTEM: \(Int(cpuUsage.system))%")
print("\tUSER: \(Int(cpuUsage.user))%")
print("\tIDLE: \(Int(cpuUsage.idle))%")
print("\tNICE: \(Int(cpuUsage.nice))%")
and here nothing change
time | system | user | idle | nice |
---|---|---|---|---|
1s | 3% | 7% | 89% | 0% |
2s | 3% | 7% | 89% | 0% |
3s | 3% | 7% | 89% | 0% |
Load info struct
fileprivate static func hostCPULoadInfo() -> host_cpu_load_info {
var info = host_cpu_load_info_data_t()
var count = mach_msg_type_number_t(MemoryLayout<host_cpu_load_info>.stride / MemoryLayout<integer_t>.stride)
let kerr: kern_return_t = withUnsafeMutablePointer(to: &info, {
host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, $0.withMemoryRebound(to: integer_t.self, capacity: 1, { $0 }), &count)
})
guard kerr == KERN_SUCCESS else {
return host_cpu_load_info()
}
return info
}
private mutating func cpuUsage() -> (system: Double, user: Double, idle: Double, nice: Double) {
let stats = LoadInfo.hostCPULoadInfo()
print(stats.cpu_ticks)
let userDiff = stats.cpu_ticks.0 - loadPrevious.cpu_ticks.0
let systemDiff = stats.cpu_ticks.1 - loadPrevious.cpu_ticks.1
let idleDiff = stats.cpu_ticks.2 - loadPrevious.cpu_ticks.2
let niceDiff = stats.cpu_ticks.3 - loadPrevious.cpu_ticks.3
let totalTicks = UInt64(systemDiff + userDiff + idleDiff + niceDiff)
let onePercent = Double(totalTicks / 100)
let system = Double(systemDiff) / onePercent
let user = Double(userDiff) / onePercent
let idle = Double(idleDiff) / onePercent
let nice = Double(niceDiff) / onePercent
loadPrevious = stats
return (system, user, idle, nice)
}
public func getCPUUsage() {
var test = LoadInfo()
let cpuUsage = test.cpuUsage()
print("\tSYSTEM: \(Int(cpuUsage.system))%")
print("\tUSER: \(Int(cpuUsage.user))%")
print("\tIDLE: \(Int(cpuUsage.idle))%")
print("\tNICE: \(Int(cpuUsage.nice))%")
}
This is how this function is called (every second)
private func updateStatistics() {
loadInfo.getCPUUsage()
}
So the provided code works well with data of similar accuracy to Activity Monitor
fileprivate static func hostCPULoadInfo() -> host_cpu_load_info {
var info = host_cpu_load_info_data_t()
var count = mach_msg_type_number_t(MemoryLayout<host_cpu_load_info>.stride / MemoryLayout<integer_t>.stride)
let kerr: kern_return_t = withUnsafeMutablePointer(to: &info, {
host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, $0.withMemoryRebound(to: integer_t.self, capacity: 1, { $0 }), &count)
})
guard kerr == KERN_SUCCESS else {
return host_cpu_load_info()
}
return info
}
var loadPrevious: host_cpu_load_info = hostCPULoadInfo()
private mutating func cpuUsage() -> (system: Double, user: Double, idle: Double, nice: Double) {
let stats = LoadInfo.hostCPULoadInfo()
print(stats.cpu_ticks)
let userDiff = stats.cpu_ticks.0 - loadPrevious.cpu_ticks.0
let systemDiff = stats.cpu_ticks.1 - loadPrevious.cpu_ticks.1
let idleDiff = stats.cpu_ticks.2 - loadPrevious.cpu_ticks.2
let niceDiff = stats.cpu_ticks.3 - loadPrevious.cpu_ticks.3
let totalTicks = UInt64(systemDiff + userDiff + idleDiff + niceDiff)
let onePercent = Double(totalTicks / 100)
let system = Double(systemDiff) / onePercent
let user = Double(userDiff) / onePercent
let idle = Double(idleDiff) / onePercent
let nice = Double(niceDiff) / onePercent
loadPrevious = stats
return (system, user, idle, nice)
}
The problem was caused by creating a new LoadInfo instance in the getCPUUsage function every time it was called, so none of the LoadPreviouse data was properly used. All we need to do is simply get rid of the getCPUUsage function and for example in our view structure or wherever we need CPU usage data, create a LoadInfo instance and simply call the cpuUsage function e.g. like this
@State private var loadInfo = LoadInfo()
private func getCPUUsage() {
let cpuUsage = loadInfo.cpuUsage()
print("\tSYSTEM: \(Int(cpuUsage.system))%")
print("\tUSER: \(Int(cpuUsage.user))%")
print("\tIDLE: \(Int(cpuUsage.idle))%")
print("\tNICE: \(Int(cpuUsage.nice))%")
}