From cc1485f969a7ef5efe5dca80c638245c783083b4 Mon Sep 17 00:00:00 2001 From: op06072 Date: Fri, 20 Jan 2023 01:25:16 +0900 Subject: [PATCH] FIx the leak and update readme --- README.md | 105 ++-- .../xcdebugger/Breakpoints_v2.xcbkptlist | 522 +++++++++++------- socpowerbuddy_swift/main.swift | 130 +++-- socpowerbuddy_swift/render.swift | 410 ++++++++------ socpowerbuddy_swift/sampler.swift | 368 +++++++----- socpowerbuddy_swift/static.swift | 37 +- 6 files changed, 920 insertions(+), 652 deletions(-) diff --git a/README.md b/README.md index f61803a..2540490 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

neoasitop

+

neoasitop

A sudoless performance monitoring CLI tool for Apple Silicon

@@ -10,32 +10,21 @@ + + Stars +

![](image/neoasitop.png) +# Introducing ## What is `neoasitop` -A Swift-based `asitop`-inspired command line tool for Apple Silicon (aka M1) Macs. - -* Utilization info: - * CPU (E-cluster and P-cluster), GPU - * Frequency and utilization, temperature - * ANE utilization (measured by power) - * Fan speed (if fan exists) - * SOC throttling -* Memory info: - * RAM and swap, size and usage - * Memory bandwidth (CPU/GPU/total) - * Media engine bandwidth usage -* Power info: - * System power, CPU power, GPU power, DRAM power - * Chart for CPU/GPU power - * Peak power, rolling average display +A Swift-based `asitop`-inspired command line tool for Apple Silicon (aka M series) Macs. `neoasitop` uses the custom [`socpowerbuddy`](https://github.com/BitesPotatoBacks/SocPowerBuddy)-inspired logic, which allows access to a variety of hardware performance counters without sudo permission. `neoasitop` is lightweight and has minimal performance impact. -**`neoasitop` only tested on following Apple Silicon Macs!** +**`neoasitop` officially tested on following Apple Silicon Macs!** * Test list * 2021 MacBook Pro[MacBookPro18,1] (M1 Pro, Ventura) @@ -43,24 +32,9 @@ A Swift-based `asitop`-inspired command line tool for Apple Silicon (aka M1) Mac * 2020 Mac mini[Macmini9,1] (M1, Monterey) * 2020 MacBook Air[MacBookAir10,1] (M1, Monterey) -## Installation and Usage - -1. Install the [Homebrew](https://brew.sh/index_ko) -2. Run `brew tap op06072/neoasitop` -3. Run `brew install neoasitop` -4. Run `neoasitop` +## Why -```shell -# advanced options -neoasitop [--interval ] [--color ] [--avg ] - -OPTIONS: - -i, --interval - Display interval and sampling interval for info gathering (seconds) (default: 1) - -c, --color Choose display color (0~8) (default: 2) - --avg Interval for averaged values (seconds) (default: 30) - -h, --help Show help information. -``` +Because I didn't want to be the system admin just to see the status of the system. Why kill a fly with a spear? Admin privileges are too powerful to just monitor the system. ## How it works @@ -86,26 +60,66 @@ OPTIONS: * Fan existence * memory and swap usage -Some information is guesstimate and hardcoded as there doesn't seem to be a official source for it on the system: +[`Hot`](https://github.com/macmade/Hot) is used to measure the following: + +* SOC Throttling + +Some information is guesstimated and hardcoded as there doesn't seem to be a official source for it on the system: * CPU/GPU TDP * CPU/GPU maximum memory bandwidth * ANE max power * Media engine max bandwidth -[`Hot`](https://github.com/macmade/Hot) +## Feature -* SOC Throttling +* Utilization info: + * CPU (E-cluster and P-cluster), GPU + * Frequency and utilization, temperature + * ANE utilization (measured by power) + * Fan speed (if fan exists) + * SOC throttling +* Memory info: + * RAM and swap, size and usage + * Memory bandwidth (CPU/GPU/total) + * Media engine bandwidth usage +* Power info: + * System power, CPU power, GPU power, DRAM power + * Chart for CPU/GPU power + * Peak power, rolling average display -## Why +# Installation, Usage, and Making +**Note:** Tool usage is listed by `neoasitop --help` +```shell +# advanced options +neoasitop [--interval ] [--color ] [--avg ] -Because I didn't find something like this online. Also, just curious about stuff. +OPTIONS: + -i, --interval + Display interval and sampling interval for info gathering (seconds) (default: 1) + -c, --color Choose display color (0~8) (default: 2) + --avg Interval for averaged values (seconds) (default: 30) + -h, --help Show help information. +``` -## Disclaimers +## Install using Homebrew +1. If you dont have Hombrew, [install it](https://brew.sh/index_ko)! +2. Add my tap using `brew tap op06072/neoasitop` +3. Install the tool with `brew install neoasitop` +4. Run `neoasitop`! -I just get this from `asitop` don't blame me if it fried your new MacBook or something. +## Install Manually +1. Download the bin from [latest release](https://github.com/op06072/NeoAsitop/releases). +2. Unzip the downloaded file into your desired dir (such as `/usr/bin`) +4. Run `neoasitop`! -## Credits +### Building the project +The source is bundled in a Xcode project. Simply build via Xcode on your mac! + +### Diagnosing missing entries for your system +A diagnostic dumping tool is included within each release: `iorepdump`. It dumps all IOReport groups matching those used by NeoAsitop. It's helpful for discovering entries on new silicon. + +# Credits Special thanks to: @@ -113,4 +127,7 @@ Special thanks to: - [BitesPotatoBacks](https://github.com/BitesPotatoBacks) for the project [SocPowerBuddy](https://github.com/BitesPotatoBacks/SocPowerBuddy) that gave me the way to replace powermetrics. - [exelban](https://github.com/exelban) for the project [stats](https://github.com/exelban/stats) that gave me the way to get sensor value. - [macmade](https://github.com/macmade) for the project [Hot](https://github.com/macmade/Hot) that gave me the way to get soc throttle status. -- [rderik](https://github.com/rderik) for the project [clock](https://github.com/rderik/clock) that gave me the way to use ncurses in swift. \ No newline at end of file +- [rderik](https://github.com/rderik) for the project [clock](https://github.com/rderik/clock) that gave me the way to use ncurses in swift. + +## Dislaimers +As I said, some information is just guesstimated. So don't blame me if it fried your new MacBook or something. ~~Well...I don't think that's going to happen.~~ \ No newline at end of file diff --git a/socpowerbuddy_swift.xcodeproj/xcuserdata/eomsehwan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/socpowerbuddy_swift.xcodeproj/xcuserdata/eomsehwan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 9cd9e33..f5ff394 100644 --- a/socpowerbuddy_swift.xcodeproj/xcuserdata/eomsehwan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/socpowerbuddy_swift.xcodeproj/xcuserdata/eomsehwan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -14,8 +14,8 @@ filePath = "socpowerbuddy_swift/sampler.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "299" - endingLineNumber = "299" + startingLineNumber = "344" + endingLineNumber = "344" landmarkName = "format(sd:vd:)" landmarkType = "9"> @@ -1447,9 +1447,9 @@ filePath = "socpowerbuddy_swift/static.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "376" - endingLineNumber = "376" - landmarkName = "generateSocMax(sd:)" + startingLineNumber = "381" + endingLineNumber = "381" + landmarkName = "archError(sd:)" landmarkType = "9"> @@ -1692,102 +1692,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1904,7 +1792,7 @@ BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> - - - - - - - - - - - - @@ -2717,15 +2557,15 @@ @@ -2733,15 +2573,15 @@ @@ -2749,15 +2589,15 @@ @@ -2765,15 +2605,95 @@ + + + + + + + + + + + + + + + + + + + + @@ -2781,15 +2701,15 @@ @@ -2797,33 +2717,241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/socpowerbuddy_swift/main.swift b/socpowerbuddy_swift/main.swift index e74b16c..6ac26be 100644 --- a/socpowerbuddy_swift/main.swift +++ b/socpowerbuddy_swift/main.swift @@ -38,11 +38,11 @@ while cmd.interval/1000 >= options.interval { cmd.interval /= 2 } -var cpu_peak_pwr: Float = 0 -var gpu_peak_pwr: Float = 0 +var cpu_peak_pwr: Float = 0 +var gpu_peak_pwr: Float = 0 var system_peak_pwr: Float = 0 -var cpu_avg_pwr_list: [Float] = [] -var gpu_avg_pwr_list: [Float] = [] +var cpu_avg_pwr_list: [Float] = [] +var gpu_avg_pwr_list: [Float] = [] var system_avg_pwr_list: [Float] = [] let procInfo = ProcessInfo() @@ -113,10 +113,10 @@ generateSocMax(sd: &sd) sd.max_pwr.append(8) sd.max_bw.append(7) -iorep.cpusubchn = nil -iorep.pwrsubchn = nil +iorep.cpusubchn = nil +iorep.pwrsubchn = nil iorep.clpcsubchn = nil -iorep.bwsubchn = nil +iorep.bwsubchn = nil iorep.cpuchn_cpu = IOReportCopyChannelsInGroup("CPU Stats", nil, 0, 0, 0) iorep.cpuchn_gpu = IOReportCopyChannelsInGroup("GPU Stats", nil, 0, 0, 0) iorep.pwrchn_eng = IOReportCopyChannelsInGroup("Energy Model", nil, 0, 0, 0) @@ -152,6 +152,13 @@ iorep.bwsub = IOReportCreateSubscription( &iorep.bwsubchn, 0, nil ) +iorep.cpuchn_cpu = nil +iorep.cpuchn_gpu = nil +iorep.pwrchn_eng = nil +iorep.pwrchn_pmp = nil +iorep.clpcchn = nil +iorep.bwchn = nil + print("\n [2/2] Gathering System Info\n") var fan_set = sd.fan_exist gen_screen() @@ -161,86 +168,77 @@ var monInfo = dispInfo(sd: sd) var cpu_pwr = monInfo.cpu_pwr.val var gpu_pwr = monInfo.gpu_pwr.val var xy: [Int32] = [0, 0] -var scrin = display(monInfo, true, nil, xy, options.color) // 레이아웃 렌더링 +var scrin: refreshInfo? = display(monInfo, true, nil, xy, options.color) // 레이아웃 렌더링 //print("layout finish") -var scr = scrin.tbx -xy = scrin.xy +var scr = scrin!.tbx +var bottomPnt: OpaquePointer? = nil +xy = scrin!.xy while true { autoreleasepool { - var rd = render_data() - var vd = vd_init(sd: sd) + var rd: render_data? = render_data() + var vd: variating_data? = vd_init(sd: sd) if fan_set { - getSensorVal(vd: &vd, set_mode: fan_set, sd: &sd) // 센서값 + getSensorVal(vd: &vd!, set_mode: fan_set, sd: &sd) // 센서값 fan_set = false } else { - getSensorVal(vd: &vd, sd: &sd) // 센서값 + getSensorVal(vd: &vd!, sd: &sd) // 센서값 } - getMemUsage(vd: &vd) - sd.ram_capacity = "\(Int(vd.mem_stat.total[0]))\(ByteUnit(vd.mem_stat.total[1]))" + getMemUsage(vd: &vd!) + sd.ram_capacity = "\(Int(vd!.mem_stat.total[0]))\(ByteUnit(vd!.mem_stat.total[1]))" monInfo = dispInfo(sd: sd) monInfo.cpu_pwr.val = cpu_pwr monInfo.gpu_pwr.val = gpu_pwr - sample(iorep: iorep, sd: sd, vd: &vd, cmd: cmd) // 데이터 샘플링 (애플 비공개 함수 이용) + sample(iorep: iorep, sd: sd, vd: &vd!, cmd: cmd) // 데이터 샘플링 (애플 비공개 함수 이용) //print("sampling finish") - format(sd: &sd, vd: &vd) // 포매팅 + format(sd: &sd, vd: &vd!) // 포매팅 //print("formatting finish") - summary(sd: sd, vd: vd, rd: &rd, rvd: &monInfo, opt: options.avg) - cpu_pwr = monInfo.cpu_pwr.val - gpu_pwr = monInfo.gpu_pwr.val - //print("summarize finish") - - switch getch() { - // Wait for user input - // Exit on 'q' - case Int32(UnicodeScalar("q").value): - endwin() - if scr.items.count != 0 { - if scr.items[0].items.count != 0 { - if sd.fan_exist { - del_tbox(tbx: &scr.items[0].items[2].items[0]) - } - for i in (0...2).reversed() { - del_tbox(tbx: &scr.items[0].items[i]) - } - } - if scr.items[1].items.count != 0 { - for i in (0...1).reversed() { - del_tbox(tbx: &scr.items[1].items[i]) - } + summary(sd: sd, vd: vd!, rd: &rd!, rvd: &monInfo, opt: options.avg) + rd = nil + vd = nil + } + + cpu_pwr = monInfo.cpu_pwr.val + gpu_pwr = monInfo.gpu_pwr.val + //print("summarize finish") + + switch getch() { + // Wait for user input + // Exit on 'q' + case Int32(UnicodeScalar("q").value): + endwin() + if scr.items.count != 0 { + if scr.items[0].items.count != 0 { + if sd.fan_exist { + del_tbox(tbx: &scr.items[0].items[2].items[0]) } - for i in 0...2 { - del_tbox(tbx: &scr.items[i]) + for i in (0...2).reversed() { + del_tbox(tbx: &scr.items[0].items[i]) } } - del_tbox(tbx: &scr) - exit(EX_OK) - default: - scrin = display(monInfo, false, scr, xy, options.color) // 정보 출력 - scr = scrin.tbx - xy = scrin.xy - wclear(scr.t.win) - - //dfs_kill(tbx: &scr) - - var first_box = 1 - if fan_set { - del_tbox(tbx: &scr.items[0].items[2].items[0]) - first_box = 2 - } - for i in (0...first_box).reversed() { - del_tbox(tbx: &scr.items[0].items[i]) - } - for i in (0...1).reversed() { - del_tbox(tbx: &scr.items[1].items[i]) + if scr.items[1].items.count != 0 { + for i in (0...1).reversed() { + del_tbox(tbx: &scr.items[1].items[i]) + } } for i in 0...2 { del_tbox(tbx: &scr.items[i]) } - del_tbox(tbx: &scr) - //print("render finish") } - Thread.sleep(forTimeInterval: options.interval-(cmd.interval*1e-3)) + del_tbox(tbx: &scr) + print("\nGood Bye") + exit(EX_OK) + default: + autoreleasepool { + scrin = display(monInfo, false, scr, xy, options.color, bottomPnt) // 정보 출력 + scr = scrin!.tbx + xy = scrin!.xy + bottomPnt = scrin!.bottom + scrin = nil + } + wclear(scr.t.win) + //print("render finish") } + Thread.sleep(forTimeInterval: options.interval-(cmd.interval*1e-3)) } diff --git a/socpowerbuddy_swift/render.swift b/socpowerbuddy_swift/render.swift index e97098b..906eb5c 100644 --- a/socpowerbuddy_swift/render.swift +++ b/socpowerbuddy_swift/render.swift @@ -48,6 +48,7 @@ struct chartInfo { struct refreshInfo { var tbx: tbox + var bottom: OpaquePointer? var xy: [Int32] } @@ -184,12 +185,16 @@ func gen_screen() { nodelay(stdscr, true) } -func screen_bottom() { +func screen_bottom(_ bottm: OpaquePointer? = nil) -> OpaquePointer? { autoreleasepool { let size = get_size() let lines = size[0]-1 let cols = size[1] - let bottom = newwin(1, cols, lines, 0)! + var bottom = newwin(1, cols, lines, 0)! + if bottm != nil { + delwin(bottom) + bottom = bottm! + } init_pair(3, Int16(blue), Int16(blue)) wattron(bottom, COLOR_PAIR(3)) box(bottom, 0, 0) @@ -200,6 +205,8 @@ func screen_bottom() { waddstr(bottom, quit_msg) wattroff(bottom, COLOR_PAIR(2)) wrefresh(bottom) + + return bottom } } @@ -225,41 +232,41 @@ func screen_init() -> tbox { } func Stack(size: Int32, title: [String], border: Int, stack: split, tbx: inout tbox, offset: Int32? = nil, render: Bool) { + let hstack = 1-stack.mode + let vstack = stack.mode + let t = tbx.t + var line = t.h + var col = t.w + var left = t.x + var top = t.y + var tiles: [tbox]? = [] + var colr = green + + if t.c != black && t.c != red && t.title != "" { + line -= 2 + col -= 2 + left += 1 + top += 1 + } else if t.title != "" { + line -= 1 + col -= 1 + left += 1 + top += 1 + } + + var hsize = col + var vsize = line + var hplus: Int32 = 0 + var vplus: Int32 = 0 + if hstack > 0 { + hsize /= size + hplus = hsize + } else if vstack > 0 { + vsize /= size + vplus = vsize + } + autoreleasepool { - let hstack = 1-stack.mode - let vstack = stack.mode - let t = tbx.t - var line = t.h - var col = t.w - var left = t.x - var top = t.y - var tiles: [tbox] = [] - var colr = green - - if t.c != black && t.c != red && t.title != "" { - line -= 2 - col -= 2 - left += 1 - top += 1 - } else if t.title != "" { - line -= 1 - col -= 1 - left += 1 - top += 1 - } - - var hsize = col - var vsize = line - var hplus: Int32 = 0 - var vplus: Int32 = 0 - if hstack > 0 { - hsize /= size - hplus = hsize - } else if vstack > 0 { - vsize /= size - vplus = vsize - } - for i in 0.. 0 { - if border == 2 { - init_pair(5, Int16(yellow), Int16(black)) - wattron(win, COLOR_PAIR(5)) - colr = yellow - } else if border == 3 { - init_pair(6, Int16(red), Int16(black)) - wattron(win, COLOR_PAIR(6)) - colr = red + autoreleasepool { + var win: OpaquePointer? = nil + if tbx.items.count > 0 { + win = tbx.items[Int(i)].t.win + wresize(win, vsize+spair, hsize) + mvwin(win, y, x) + } else { + win = newwin(vsize+spair, hsize, y, x) } - box(win, 0, 0) - } else { - colr = black - } - var titl = "" - if title.count > i { - titl = title[Int(i)] - if titl != "" { - var start = col/8 - if border == 1{ - start = col/10 + wattron(win, COLOR_PAIR(1)) + //werase(win) + if border > 0 { + if border == 2 { + init_pair(5, Int16(yellow), Int16(black)) + wattron(win, COLOR_PAIR(5)) + colr = yellow + } else if border == 3 { + init_pair(6, Int16(red), Int16(black)) + wattron(win, COLOR_PAIR(6)) + colr = red } - start -= Int32(titl.count/2) - if start < 0 { - start = 0 + box(win, 0, 0) + } else { + colr = black + } + var titl = "" + if title.count > i { + titl = title[Int(i)] + if titl != "" { + var start = col/8 + if border == 1{ + start = col/10 + } + start -= Int32(titl.count/2) + if start < 0 { + start = 0 + } + wmove(win, 0, start) + wattron(win, COLOR_PAIR(1)) + waddstr(win, " \(titl) ") } - wmove(win, 0, start) - wattron(win, COLOR_PAIR(1)) - waddstr(win, " \(titl) ") } + + wattroff(win, COLOR_PAIR(1)) + if tbx.items.count > 0 { + tiles!.append(tbox( + t: Tile(x: x, y: y, w: hsize, h: vsize, c: colr, win: win, title: titl), + items: tbx.items[Int(i)].items + )) + } else { + tiles!.append(tbox( + t: Tile(x: x, y: y, w: hsize, h: vsize, c: colr, win: win, title: titl), + items: [] + )) + } + if render { + wrefresh(win) + } + win = nil } - - wattroff(win, COLOR_PAIR(1)) - if render { - wrefresh(win) - } - tiles.append(tbox( - t: Tile(x: x, y: y, w: hsize, h: vsize, c: colr, win: win, title: titl), - items: [] - )) } - tbx.items = tiles + tbx.items = tiles! + tiles = nil } } @@ -371,7 +396,7 @@ func Gauge(value: Float? = nil, gauge: split, tbx: inout tbox, datapoint: [Float } for i in peak...line { wmove(win, i, 1+(offset ?? 0)) - waddstr(win,bar) + waddstr(win, bar) } } else if vgauge != 0 { if title != "" { @@ -420,32 +445,49 @@ func Gauge(value: Float? = nil, gauge: split, tbx: inout tbox, datapoint: [Float } } -func display(_ disp: dispInfo, _ gn: Bool = false, _ scrin: tbox? = nil, _ xy: [Int32], _ colr: UInt8 = 2) -> refreshInfo { +func display(_ disp: dispInfo, _ gn: Bool = false, _ scrin: tbox? = nil, _ xy: [Int32], _ colr: UInt8 = 2, _ bottom: OpaquePointer? = nil) -> refreshInfo { let size = get_size() let lines = size[0] let cols = size[1] var scrn = scrin ?? screen_init() + var btm: OpaquePointer? = nil - autoreleasepool { - - if lines < 34 || cols < 63 { - endwin() - print("Terminal size is too small!\nThis tool needs 63 cols and 34 lines at least!") - exit(1) - } + if lines < 34 || cols < 63 { + endwin() + print("Terminal size is too small!\nThis tool needs 63 cols and 34 lines at least!") + exit(1) + } - if (cols != xy[0]) || (lines != xy[1]) { - scrn = screen_init() - } - - init_pair(1, Int16(colr), Int16(black)) - - var first_stack: Int32 = 2 - if sd.fan_exist { - first_stack = 3 + if (cols != xy[0]) || (lines != xy[1]) { + if !gn { + var first_box = 1 + if sd.fan_exist { + del_tbox(tbx: &scrn.items[0].items[2].items[0]) + first_box = 2 + } + for i in (0...first_box).reversed() { + del_tbox(tbx: &scrn.items[0].items[i]) + } + for i in (0...1).reversed() { + del_tbox(tbx: &scrn.items[1].items[i]) + } + for i in 0...2 { + del_tbox(tbx: &scrn.items[i]) + } + del_tbox(tbx: &scrn) } - - //print("rendering start") + scrn = screen_init() + } + + init_pair(1, Int16(colr), Int16(black)) + + var first_stack: Int32 = 2 + if sd.fan_exist { + first_stack = 3 + } + + //print("rendering start") + autoreleasepool { Stack( size: 3, title: [disp.proc_grp, disp.mem_grp, disp.pwr_grp], @@ -467,28 +509,31 @@ func display(_ disp: dispInfo, _ gn: Bool = false, _ scrin: tbox? = nil, _ xy: [ size: 2, title: [disp.cpu_pwr.title, disp.gpu_pwr.title], border: 0, stack: .hsplit, tbx: &scrn.items[2], render: !gn ) - //print("third box") - var first_box = [[""]] - if sd.fan_exist { - first_box = [ - [disp.ecpu_usg.title, disp.pcpu_usg.title], - [disp.gpu_usg.title, disp.ane_usg.title], - [disp.fan_usg.title, ""] - ] - } else { - first_box = [ - [disp.ecpu_usg.title, disp.pcpu_usg.title], - [disp.gpu_usg.title, disp.ane_usg.title] - ] - } - - for (idx, titl) in first_box.enumerated() { - Stack( - size: 2, title: titl, border: 0, stack: .hsplit, - tbx: &scrn.items[0].items[idx], render: !gn - ) - } - //print("fan gauge start") + } + + //print("third box") + var first_box = [[""]] + if sd.fan_exist { + first_box = [ + [disp.ecpu_usg.title, disp.pcpu_usg.title], + [disp.gpu_usg.title, disp.ane_usg.title], + [disp.fan_usg.title, ""] + ] + } else { + first_box = [ + [disp.ecpu_usg.title, disp.pcpu_usg.title], + [disp.gpu_usg.title, disp.ane_usg.title] + ] + } + + for (idx, titl) in first_box.enumerated() { + Stack( + size: 2, title: titl, border: 0, stack: .hsplit, + tbx: &scrn.items[0].items[idx], render: !gn + ) + } + //print("fan gauge start") + autoreleasepool { if sd.fan_mode > 0 { Stack( size: Int32(sd.fan_mode), title: ["", ""], border: 0, @@ -505,47 +550,49 @@ func display(_ disp: dispInfo, _ gn: Bool = false, _ scrin: tbox? = nil, _ xy: [ ) // FAN Speed } } - //print("fan gauge finish") - - let proc_gauge_info = [ - [disp.ecpu_usg.val, disp.pcpu_usg.val], - [disp.gpu_usg.val, disp.ane_usg.val] - ] - for i in 0...1 { - for j in 0...1 { - //print("processor gauge start") - Gauge( - value: proc_gauge_info[i][j], - gauge: .hgauge, - tbx: &scrn.items[0].items[i].items[j], - render: !gn - ) - } - } //processor utilization group - //print("processor gauge finish") - - if sd.fan_exist { - let fan_label = scrn.items[0].items[2].items[1].t - var mid = Int32((fan_label.h-1)/2) - wattron(fan_label.win, COLOR_PAIR(1)) - for i in disp.airflow_info { - wmove(fan_label.win, mid, 0) - waddstr(fan_label.win, i) - mid += 1 - } - wattroff(fan_label.win, COLOR_PAIR(1)) - if !gn { - wrefresh(fan_label.win) - } + } + //print("fan gauge finish") + + let proc_gauge_info = [ + [disp.ecpu_usg.val, disp.pcpu_usg.val], + [disp.gpu_usg.val, disp.ane_usg.val] + ] + for i in 0...1 { + for j in 0...1 { + //print("processor gauge start") + Gauge( + value: proc_gauge_info[i][j], + gauge: .hgauge, + tbx: &scrn.items[0].items[i].items[j], + render: !gn + ) } - - Gauge( - value: disp.ram_usg.val, - gauge: .hgauge, - tbx: &scrn.items[1].items[0], - render: !gn - ) // RAM Usage - //print("ram gauge finish") + } //processor utilization group + //print("processor gauge finish") + + if sd.fan_exist { + let fan_label = scrn.items[0].items[2].items[1].t + var mid = Int32((fan_label.h-1)/2) + wattron(fan_label.win, COLOR_PAIR(1)) + for i in disp.airflow_info { + wmove(fan_label.win, mid, 0) + waddstr(fan_label.win, i) + mid += 1 + } + wattroff(fan_label.win, COLOR_PAIR(1)) + if !gn { + wrefresh(fan_label.win) + } + } + + Gauge( + value: disp.ram_usg.val, + gauge: .hgauge, + tbx: &scrn.items[1].items[0], + render: !gn + ) // RAM Usage + //print("ram gauge finish") + autoreleasepool { Stack( size: 4, title: [ @@ -555,31 +602,32 @@ func display(_ disp: dispInfo, _ gn: Bool = false, _ scrin: tbox? = nil, _ xy: [ border: 0, stack: .hsplit, tbx: &scrn.items[1].items[1], render: !gn ) - let bw_grp = [ - disp.ecpu_bw.val, disp.pcpu_bw.val, - disp.gpu_bw.val, disp.media_bw.val - ] - for i in 0...3 { - Gauge( - value: bw_grp[i], gauge: .hgauge, - tbx: &scrn.items[1].items[1].items[i], - render: !gn - ) - } // Bandwidth Group - //print("bw gauge finish") - Gauge( - gauge: .vgauge, tbx: &scrn.items[2].items[0], - datapoint: disp.cpu_pwr.val, - render: !gn - ) - //print("cpu_pwr gauge finish") + } + + let bw_grp = [ + disp.ecpu_bw.val, disp.pcpu_bw.val, + disp.gpu_bw.val, disp.media_bw.val + ] + for i in 0...3 { Gauge( - gauge: .vgauge, tbx: &scrn.items[2].items[1], - datapoint: disp.gpu_pwr.val, + value: bw_grp[i], gauge: .hgauge, + tbx: &scrn.items[1].items[1].items[i], render: !gn ) - //print("gpu_pwr gauge finish") - screen_bottom() - } - return refreshInfo(tbx: scrn, xy: [cols, lines]) + } // Bandwidth Group + //print("bw gauge finish") + Gauge( + gauge: .vgauge, tbx: &scrn.items[2].items[0], + datapoint: disp.cpu_pwr.val, + render: !gn + ) + //print("cpu_pwr gauge finish") + Gauge( + gauge: .vgauge, tbx: &scrn.items[2].items[1], + datapoint: disp.gpu_pwr.val, + render: !gn + ) + //print("gpu_pwr gauge finish") + btm = screen_bottom(bottom) + return refreshInfo(tbx: scrn, bottom: btm, xy: [cols, lines]) } diff --git a/socpowerbuddy_swift/sampler.swift b/socpowerbuddy_swift/sampler.swift index 6c6898f..dc552c0 100644 --- a/socpowerbuddy_swift/sampler.swift +++ b/socpowerbuddy_swift/sampler.swift @@ -12,168 +12,211 @@ func sample(iorep: iorep_data, sd: static_data, vd: inout variating_data, cmd: cmd_data) { - autoreleasepool { - let ptype_state = "P" - let vtype_state = "V" - let idletype_state = "IDLE" - let offtype_state = "OFF" - - // It's awful and horrible memory leaking time! - // I have no idea how can I fix this. - var tmp_samp = IOReportCreateSamples( - iorep.cpusub, iorep.cpusubchn?.takeUnretainedValue(), nil - ).takeRetainedValue() - - let cpusamp_a = tmp_samp - tmp_samp = IOReportCreateSamples( - iorep.pwrsub, iorep.pwrsubchn?.takeUnretainedValue(), nil - ).takeRetainedValue() - let pwrsamp_a = tmp_samp - tmp_samp = IOReportCreateSamples( - iorep.clpcsub, iorep.clpcsubchn?.takeUnretainedValue(), nil - ).takeRetainedValue() - let clpcsamp_a = tmp_samp - tmp_samp = IOReportCreateSamples( - iorep.bwsub, iorep.bwsubchn?.takeUnretainedValue(), nil - ).takeRetainedValue() - let bwsamp_a = tmp_samp - - if cmd.interval > 0 { - Thread.sleep(forTimeInterval: cmd.interval*1e-3) - } - - tmp_samp = IOReportCreateSamples( - iorep.cpusub, iorep.cpusubchn?.takeUnretainedValue(), nil - ).takeRetainedValue() - let cpusamp_b = tmp_samp - tmp_samp = IOReportCreateSamples( - iorep.pwrsub, iorep.pwrsubchn?.takeUnretainedValue(), nil - ).takeRetainedValue() - let pwrsamp_b = tmp_samp - tmp_samp = IOReportCreateSamples( - iorep.bwsub, iorep.bwsubchn?.takeUnretainedValue(), nil - ).takeRetainedValue() - let clpcsamp_b = tmp_samp - tmp_samp = IOReportCreateSamples( - iorep.bwsub, iorep.bwsubchn?.takeUnretainedValue(), nil - ).takeRetainedValue() - let bwsamp_b = tmp_samp - - var ttmp = IOReportCreateSamplesDelta(cpusamp_a, cpusamp_b, nil)?.takeRetainedValue() - - let cpu_delta = Array((ttmp as! Dictionary).values)[0] as? Array - ttmp = IOReportCreateSamplesDelta(pwrsamp_a, pwrsamp_b, nil)?.takeRetainedValue() - let pwr_delta = Array((ttmp as! Dictionary).values)[0] as? Array - ttmp = IOReportCreateSamplesDelta(clpcsamp_a, clpcsamp_b, nil)?.takeRetainedValue() - let clpc_delta = Array((ttmp as! Dictionary).values)[0] as? Array - ttmp = IOReportCreateSamplesDelta(bwsamp_a, bwsamp_b, nil)?.takeRetainedValue() - let bw_delta = Array((ttmp as! Dictionary).values)[0] as? Array - // Fortunately, You just passed the memory leak part "this time". - - for sample in cpu_delta! { - for i in stride(from: 0, to: IOReportStateGetCount(sample), by: 1) { - let subgroup = IOReportChannelGetSubGroup(sample) - let idx_name = IOReportStateGetNameForIndex(sample, i) - let chann_name = IOReportChannelGetChannelName(sample) - let residency = IOReportStateGetResidency(sample, i) - - for ii in 0.. 0 { + Thread.sleep(forTimeInterval: cmd.interval*1e-3) + } + + let cpusamp_b = IOReportCreateSamples(iorep.cpusub, iorep.cpusubchn?.takeUnretainedValue(), nil) + let pwrsamp_b = IOReportCreateSamples(iorep.pwrsub, iorep.pwrsubchn?.takeUnretainedValue(), nil) + let clpcsamp_b = IOReportCreateSamples(iorep.clpcsub, iorep.clpcsubchn?.takeUnretainedValue(), nil) + let bwsamp_b = IOReportCreateSamples(iorep.bwsub, iorep.bwsubchn?.takeUnretainedValue(), nil) + + let cpu_delta = IOReportCreateSamplesDelta(cpusamp_a?.takeUnretainedValue(), cpusamp_b?.takeUnretainedValue(), nil) + let pwr_delta = IOReportCreateSamplesDelta(pwrsamp_a?.takeUnretainedValue(), pwrsamp_b?.takeUnretainedValue(), nil) + let clpc_delta = IOReportCreateSamplesDelta(clpcsamp_a?.takeUnretainedValue(), clpcsamp_b?.takeUnretainedValue(), nil) + let bw_delta = IOReportCreateSamplesDelta(bwsamp_a?.takeUnretainedValue(), bwsamp_b?.takeUnretainedValue(), nil) + + cpusamp_a?.release() + cpusamp_b?.release() + pwrsamp_a?.release() + pwrsamp_b?.release() + clpcsamp_a?.release() + clpcsamp_b?.release() + bwsamp_a?.release() + bwsamp_b?.release() + + var tmp_vd: variating_data? = vd + + IOReportIterate(cpu_delta?.takeUnretainedValue(), { sample in + for i in stride(from: 0, to: IOReportStateGetCount(sample), by: 1) { + var subgroup = IOReportChannelGetSubGroup(sample) + var idx_name = IOReportStateGetNameForIndex(sample, i) + var chann_name = IOReportChannelGetChannelName(sample) + let residency = IOReportStateGetResidency(sample, i) + + for ii in 0..? = chann_name!.split(separator: " ") + var tmp_name: String? = last_tmp![0..? = [raw!] - if chann_name == last_name+" wr" { - vd.bandwidth_cnt[last_name]!.append(raw/Double(cmd.interval/1e+3)/1e9) - } else if chann_name.contains(" rd") { - let last_tmp = chann_name.split(separator: " ") - last_name = last_tmp[0.. Dictionary? { @@ -190,9 +233,9 @@ func appleSiliconSensors(page: Int32, usage: Int32, typ: Int32) -> Dictionary Dictionary