Skip to content

Commit

Permalink
feat: added efficiency and performance cores frequency and total core…
Browse files Browse the repository at this point in the history
…s frequency
  • Loading branch information
exelban committed Dec 20, 2024
1 parent 8fac9e4 commit d68d691
Show file tree
Hide file tree
Showing 14 changed files with 325 additions and 184 deletions.
17 changes: 17 additions & 0 deletions Kit/helpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,23 @@ internal func getIOName(_ entry: io_registry_entry_t) -> String? {
return String(cString: UnsafeRawPointer(pointer).assumingMemoryBound(to: CChar.self))
}

internal func convertCFDataToArr(_ data: CFData) -> [Int32] {
let length = CFDataGetLength(data)
var bytes = [UInt8](repeating: 0, count: length)
CFDataGetBytes(data, CFRange(location: 0, length: length), &bytes)

var arr: [Int32] = []
var chunks = stride(from: 0, to: bytes.count, by: 8).map { Array(bytes[$0..<min($0 + 8, bytes.count)])}
for chunk in chunks {
let v = UInt32(chunk[0]) | UInt32(chunk[1]) << 8 | UInt32(chunk[2]) << 16 | UInt32(chunk[3]) << 24
arr.append(Int32(v / 1000 / 1000))
}
bytes.removeAll()
chunks.removeAll()

return arr
}

public class ColorView: NSView {
public var inactiveColor: NSColor = NSColor.lightGray.withAlphaComponent(0.75)

Expand Down
43 changes: 41 additions & 2 deletions Kit/plugins/SystemKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ public struct cpu_s {
public var eCores: Int32? = nil
public var pCores: Int32? = nil
public var cores: [core_s]? = nil
public var eCoreFrequencies: [Int32]? = nil
public var pCoreFrequencies: [Int32]? = nil
}

public struct dimm_s {
Expand All @@ -128,6 +130,7 @@ public struct gpu_s {
public var vendor: String? = nil
public var vram: String? = nil
public var cores: Int? = nil
public var frequencies: [Int32]? = nil
}

public struct info_s {
Expand Down Expand Up @@ -319,6 +322,10 @@ public class SystemKit {
cpu.pCores = cores.1
cpu.cores = cores.2
}
if let freq = getFrequencies() {
cpu.eCoreFrequencies = freq.0
cpu.pCoreFrequencies = freq.1
}

return cpu
}
Expand Down Expand Up @@ -386,10 +393,8 @@ public class SystemKit {
IOObjectRelease(child)
}
IOObjectRelease(entry)

IOObjectRelease(service)
}

IOObjectRelease(iterator)

return (eCores, pCores, list)
Expand Down Expand Up @@ -417,6 +422,10 @@ public class SystemKit {
gpu.vram = vram
}

if let freq = getFrequencies() {
gpu.frequencies = freq.2
}

list.append(gpu)
}
}
Expand All @@ -429,6 +438,36 @@ public class SystemKit {
return list
}

private func getFrequencies() -> ([Int32], [Int32], [Int32])? {
var iterator = io_iterator_t()
let result = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("AppleARMIODevice"), &iterator)
if result != kIOReturnSuccess {
print("Error find AppleARMIODevice: " + (String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error"))
return nil
}

var eFreq: [Int32] = []
var pFreq: [Int32] = []
var gpuFreq: [Int32] = []

while case let child = IOIteratorNext(iterator), child != 0 {
defer { IOObjectRelease(child) }
guard let name = getIOName(child), name == "pmgr", let props = getIOProperties(child) else { continue }

if let data = props.value(forKey: "voltage-states1-sram") {
eFreq = convertCFDataToArr(data as! CFData)
}
if let data = props.value(forKey: "voltage-states5-sram") {
pFreq = convertCFDataToArr(data as! CFData)
}
if let data = props.value(forKey: "voltage-states9-sram") {
gpuFreq = convertCFDataToArr(data as! CFData)
}
}

return (eFreq, pFreq, gpuFreq)
}

public func getRamInfo() -> ram_s? {
guard let res = process(path: "/usr/sbin/system_profiler", arguments: ["SPMemoryDataType", "-json"]) else {
return nil
Expand Down
32 changes: 32 additions & 0 deletions Modules/CPU/bridge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// bridge.h
// Stats
//
// Created by Serhiy Mytrovtsiy on 17/12/2024
// Using Swift 6.0
// Running on macOS 15.1
//
// Copyright © 2024 Serhiy Mytrovtsiy. All rights reserved.
//

#ifndef bridge_h
#define bridge_h

#include <CoreFoundation/CoreFoundation.h>

typedef struct IOReportSubscriptionRef* IOReportSubscriptionRef;

CFDictionaryRef IOReportCopyChannelsInGroup(CFStringRef a, CFStringRef b, uint64_t c, uint64_t d, uint64_t e);
void IOReportMergeChannels(CFDictionaryRef a, CFDictionaryRef b, CFTypeRef null);
IOReportSubscriptionRef IOReportCreateSubscription(void* a, CFMutableDictionaryRef b, CFMutableDictionaryRef* c, uint64_t d, CFTypeRef e);
CFDictionaryRef IOReportCreateSamples(IOReportSubscriptionRef a, CFMutableDictionaryRef b, CFTypeRef c);
CFDictionaryRef IOReportCreateSamplesDelta(CFDictionaryRef a, CFDictionaryRef b, CFTypeRef c);
CFStringRef IOReportChannelGetGroup(CFDictionaryRef a);
CFStringRef IOReportChannelGetSubGroup(CFDictionaryRef a);
CFStringRef IOReportChannelGetChannelName(CFDictionaryRef a);
CFStringRef IOReportChannelGetUnitLabel(CFDictionaryRef a);
int32_t IOReportStateGetCount(CFDictionaryRef a);
CFStringRef IOReportStateGetNameForIndex(CFDictionaryRef a, int32_t b);
int64_t IOReportStateGetResidency(CFDictionaryRef a, int32_t b);

#endif /* bridge_h */
11 changes: 3 additions & 8 deletions Modules/CPU/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public class CPU: Module {
return color.additional as! NSColor
}
private var pCoreColor: NSColor {
let color = SColor.secondBlue
let color = SColor.indigo
let key = Store.shared.string(key: "\(self.config.name)_pCoresColor", defaultValue: color.key)
if let c = SColor.fromString(key).additional as? NSColor {
return c
Expand Down Expand Up @@ -115,7 +115,8 @@ public class CPU: Module {
self.limitReader = LimitReader(.CPU, popup: true) { [weak self] value in
self?.popupView.limitCallback(value)
}
self.frequencyReader = FrequencyReader(.CPU, popup: true) { [weak self] value in
#else
self.frequencyReader = FrequencyReader(.CPU, popup: false) { [weak self] value in
self?.popupView.frequencyCallback(value)
}
#endif
Expand All @@ -135,12 +136,6 @@ public class CPU: Module {
self.settingsView.setTopInterval = { [weak self] value in
self?.processReader?.setInterval(value)
}
self.settingsView.IPGCallback = { [weak self] value in
if value {
self?.frequencyReader?.setup()
}
self?.popupView.toggleFrequency(state: value)
}

self.setReaders([
self.loadReader,
Expand Down
104 changes: 82 additions & 22 deletions Modules/CPU/popup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ internal class Popup: PopupWrapper {
}
}
private let averageHeight: CGFloat = (22*3) + Constants.Popup.separatorHeight
private var frequencyHeight: CGFloat {
get {
var count: CGFloat = 1
if SystemKit.shared.device.info.cpu?.eCores != nil {
count += 1
}
if SystemKit.shared.device.info.cpu?.pCores != nil {
count += 1
}
return (22*count) + Constants.Popup.separatorHeight
}
}
private let processHeight: CGFloat = 22

private var systemField: NSTextField? = nil
Expand All @@ -45,6 +57,11 @@ internal class Popup: PopupWrapper {
private var average1Field: NSTextField? = nil
private var average5Field: NSTextField? = nil
private var average15Field: NSTextField? = nil
private var coresFreqField: NSTextField? = nil
private var eCoresFreqField: NSTextField? = nil
private var pCoresFreqField: NSTextField? = nil
private var eCoresFreqColorView: NSView? = nil
private var pCoresFreqColorView: NSView? = nil

private var systemColorView: NSView? = nil
private var userColorView: NSView? = nil
Expand Down Expand Up @@ -83,7 +100,7 @@ internal class Popup: PopupWrapper {
private var chartColor: NSColor { self.chartColorState.additional as? NSColor ?? NSColor.systemBlue }
private var eCoresColorState: SColor = .teal
private var eCoresColor: NSColor { self.eCoresColorState.additional as? NSColor ?? NSColor.systemTeal }
private var pCoresColorState: SColor = .secondBlue
private var pCoresColorState: SColor = .indigo
private var pCoresColor: NSColor { self.pCoresColorState.additional as? NSColor ?? NSColor.systemBlue }

private var numberOfProcesses: Int {
Expand Down Expand Up @@ -115,7 +132,7 @@ internal class Popup: PopupWrapper {
width: Constants.Popup.width,
height: self.dashboardHeight + self.chartHeight + self.averageHeight
))
self.setFrameSize(NSSize(width: self.frame.width, height: self.frame.height + self.detailsHeight + self.processesHeight))
self.setFrameSize(NSSize(width: self.frame.width, height: self.frame.height + self.detailsHeight + self.frequencyHeight + self.processesHeight))

self.systemColorState = SColor.fromString(Store.shared.string(key: "\(self.title)_systemColor", defaultValue: self.systemColorState.key))
self.userColorState = SColor.fromString(Store.shared.string(key: "\(self.title)_userColor", defaultValue: self.userColorState.key))
Expand All @@ -135,12 +152,14 @@ internal class Popup: PopupWrapper {
gridView.addRow(with: [self.initChart()])
gridView.addRow(with: [self.initDetails()])
gridView.addRow(with: [self.initAverage()])
gridView.addRow(with: [self.initFrequency()])
gridView.addRow(with: [self.initProcesses()])

gridView.row(at: 0).height = self.dashboardHeight
gridView.row(at: 1).height = self.chartHeight
gridView.row(at: 2).height = self.detailsHeight
gridView.row(at: 3).height = self.averageHeight
gridView.row(at: 4).height = self.frequencyHeight

self.addSubview(gridView)
self.grid = gridView
Expand Down Expand Up @@ -189,7 +208,7 @@ internal class Popup: PopupWrapper {

let usage = NSView(frame: NSRect(x: usageX, y: (view.frame.height - usageSize)/2, width: usageSize, height: usageSize))
let temperature = NSView(frame: NSRect(x: (usageX - 50)/2, y: (view.frame.height - 50)/2 - 3, width: 50, height: 50))
let frequency = NSView(frame: NSRect(x: (usageX+usageSize) + (usageX - 50)/2, y: (view.frame.height - 50)/2 - 3, width: 50, height: 50))
let frequency = NSView(frame: NSRect(x: (usageX+usageSize) + (usageX - 50)/2, y: 0, width: 50, height: self.dashboardHeight))

self.circle = PieChartView(frame: NSRect(x: 0, y: 0, width: usage.frame.width, height: usage.frame.height), segments: [], drawValue: true)
self.circle!.toolTip = localizedString("CPU usage")
Expand Down Expand Up @@ -315,6 +334,30 @@ internal class Popup: PopupWrapper {
return view
}

private func initFrequency() -> NSView {
let view: NSView = NSView(frame: NSRect(x: 0, y: 0, width: self.frame.width, height: self.frequencyHeight))
let separator = separatorView(localizedString("Frequency"), origin: NSPoint(x: 0, y: self.frequencyHeight-Constants.Popup.separatorHeight), width: self.frame.width)
let container: NSStackView = NSStackView(frame: NSRect(x: 0, y: 0, width: view.frame.width, height: separator.frame.origin.y))
container.orientation = .vertical
container.spacing = 0

self.coresFreqField = popupRow(container, title: "\(localizedString("All cores")):", value: "").1

if isARM {
if SystemKit.shared.device.info.cpu?.eCores != nil {
(self.eCoresFreqColorView, _, self.eCoresFreqField) = popupWithColorRow(container, color: self.eCoresColor, title: "\(localizedString("Efficiency cores")):", value: "")
}
if SystemKit.shared.device.info.cpu?.pCores != nil {
(self.pCoresFreqColorView, _, self.pCoresFreqField) = popupWithColorRow(container, color: self.pCoresColor, title: "\(localizedString("Performance cores")):", value: "")
}
}

view.addSubview(separator)
view.addSubview(container)

return view
}

private func initProcesses() -> NSView {
if self.numberOfProcesses == 0 { return NSView() }

Expand Down Expand Up @@ -388,7 +431,7 @@ internal class Popup: PopupWrapper {
})
}

public func frequencyCallback(_ value: Double?) {
public func frequencyCallback(_ value: [Double]?) {
guard let value else { return }

DispatchQueue.main.async(execute: {
Expand All @@ -397,13 +440,33 @@ internal class Popup: PopupWrapper {
}

if (self.window?.isVisible ?? false) || !self.initializedFrequency {
if value > self.maxFreq {
self.maxFreq = value
}

if let freqCircle = self.frequencyCircle {
freqCircle.setValue((100*value)/self.maxFreq)
freqCircle.setText("\((value/1000).rounded(toPlaces: 2))")
if value.count == 1 {
let freq = value.first ?? 0
if freq > self.maxFreq {
self.maxFreq = freq
}
self.coresFreqField?.stringValue = "\(Int(freq)) MHz"
if let circle = self.frequencyCircle {
circle.setValue((100*freq)/self.maxFreq)
circle.setText("\((freq/1000).rounded(toPlaces: 2))")
}
} else if value.count == 2 {
let e = value.first ?? 0
let p = value.last ?? 0
self.eCoresFreqField?.stringValue = "\(Int(e)) MHz"
self.pCoresFreqField?.stringValue = "\(Int(p)) MHz"

if let eCoreCount = SystemKit.shared.device.info.cpu?.eCores, let pCoreCount = SystemKit.shared.device.info.cpu?.pCores {
let freq = ((e * Double(eCoreCount)) + (p * Double(pCoreCount))) / Double(eCoreCount + pCoreCount)
if freq > self.maxFreq {
self.maxFreq = freq
}
self.coresFreqField?.stringValue = "\(Int(freq)) MHz"
if let circle = self.frequencyCircle {
circle.setValue((100*freq)/self.maxFreq)
circle.setText("\((freq/1000).rounded(toPlaces: 2))")
}
}
}

self.initializedFrequency = true
Expand Down Expand Up @@ -461,15 +524,6 @@ internal class Popup: PopupWrapper {
})
}

public func toggleFrequency(state: Bool) {
DispatchQueue.main.async(execute: {
if let view = self.frequencyCircle {
view.isHidden = !state
}
self.initializedFrequency = false
})
}

// MARK: - Settings

public override func settings() -> NSView? {
Expand Down Expand Up @@ -578,15 +632,21 @@ internal class Popup: PopupWrapper {
}
self.eCoresColorState = newValue
Store.shared.set(key: "\(self.title)_eCoresColor", value: key)
self.eCoresColorView?.layer?.backgroundColor = (newValue.additional as? NSColor)?.cgColor
if let color = (newValue.additional as? NSColor) {
self.eCoresColorView?.layer?.backgroundColor = color.cgColor
self.eCoresFreqColorView?.layer?.backgroundColor = color.cgColor
}
}
@objc private func togglePCoresColor(_ sender: NSMenuItem) {
guard let key = sender.representedObject as? String, let newValue = SColor.allColors.first(where: { $0.key == key }) else {
return
}
self.pCoresColorState = newValue
Store.shared.set(key: "\(self.title)_pCoresColor", value: key)
self.pCoresColorView?.layer?.backgroundColor = (newValue.additional as? NSColor)?.cgColor
if let color = (newValue.additional as? NSColor) {
self.pCoresColorView?.layer?.backgroundColor = color.cgColor
self.pCoresFreqColorView?.layer?.backgroundColor = color.cgColor
}
}
@objc private func toggleLineChartHistory(_ sender: NSMenuItem) {
guard let key = sender.representedObject as? String, let value = Int(key) else { return }
Expand Down
2 changes: 1 addition & 1 deletion Modules/CPU/portal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class Portal: PortalWrapper {
private var idleColor: NSColor { self.idleColorState.additional as? NSColor ?? NSColor.lightGray }
private var eCoresColorState: SColor = .teal
private var eCoresColor: NSColor { self.eCoresColorState.additional as? NSColor ?? NSColor.systemTeal }
private var pCoresColorState: SColor = .secondBlue
private var pCoresColorState: SColor = .indigo
private var pCoresColor: NSColor { self.pCoresColorState.additional as? NSColor ?? NSColor.systemBlue }

public override func load() {
Expand Down
Loading

0 comments on commit d68d691

Please sign in to comment.