macpm 0.15__tar.gz → 0.22__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {macpm-0.15 → macpm-0.22}/PKG-INFO +1 -1
- {macpm-0.15 → macpm-0.22}/README.md +3 -2
- {macpm-0.15 → macpm-0.22}/macpm/macpm.py +67 -34
- {macpm-0.15 → macpm-0.22}/macpm.egg-info/PKG-INFO +1 -1
- {macpm-0.15 → macpm-0.22}/setup.py +1 -1
- {macpm-0.15 → macpm-0.22}/LICENSE +0 -0
- {macpm-0.15 → macpm-0.22}/macpm/__init__.py +0 -0
- {macpm-0.15 → macpm-0.22}/macpm.egg-info/SOURCES.txt +0 -0
- {macpm-0.15 → macpm-0.22}/macpm.egg-info/dependency_links.txt +0 -0
- {macpm-0.15 → macpm-0.22}/macpm.egg-info/entry_points.txt +0 -0
- {macpm-0.15 → macpm-0.22}/macpm.egg-info/not-zip-safe +0 -0
- {macpm-0.15 → macpm-0.22}/macpm.egg-info/requires.txt +0 -0
- {macpm-0.15 → macpm-0.22}/macpm.egg-info/top_level.txt +0 -0
- {macpm-0.15 → macpm-0.22}/setup.cfg +0 -0
|
@@ -5,8 +5,8 @@ or: pip install macpm
|
|
|
5
5
|
|
|
6
6
|
enhanced MAC Performance monitoring CLI tool for Apple Silicon
|
|
7
7
|
|
|
8
|
-

|
|
9
|
+

|
|
10
10
|
```shell
|
|
11
11
|
pip install macpm
|
|
12
12
|
```
|
|
@@ -19,6 +19,7 @@ forked form https://github.com/tlkh/asitop
|
|
|
19
19
|
3. adjust the hard coded max power in CPU/GPU/ANE
|
|
20
20
|
4. change the way to call powermetrics, no temp files in /tmp
|
|
21
21
|
5. press ESC or q to quit
|
|
22
|
+
6. press LEFT or RIGHT to switch color, press 1 : default view, 2 : show_core view
|
|
22
23
|
|
|
23
24
|
A Python-based `nvtop`-inspired command line tool for Apple Silicon (aka M1) Macs.
|
|
24
25
|
|
|
@@ -9,7 +9,7 @@ import psutil
|
|
|
9
9
|
import plistlib
|
|
10
10
|
import curses
|
|
11
11
|
|
|
12
|
-
version = 'macpm v0.
|
|
12
|
+
version = 'macpm v0.22'
|
|
13
13
|
parser = argparse.ArgumentParser(
|
|
14
14
|
description=f'{version}: Performance monitoring CLI tool for Apple Silicon')
|
|
15
15
|
parser.add_argument('--interval', type=int, default=1,
|
|
@@ -253,12 +253,13 @@ def parse_cpu_metrics(powermetrics_parse):
|
|
|
253
253
|
core = e_core if name[0] == 'E' else p_core
|
|
254
254
|
core.append(cpu["cpu"])
|
|
255
255
|
cpu_metric_dict[name + str(cpu["cpu"]) + "_freq_Mhz"] = int(cpu["freq_hz"] / (1e6))
|
|
256
|
-
|
|
256
|
+
idle_ratio = cluster["down_ratio"] + (1 - cluster["down_ratio"]) * (cpu["idle_ratio"] + cpu["down_ratio"])
|
|
257
|
+
cpu_metric_dict[name + str(cpu["cpu"]) + "_active"] = int((1 - idle_ratio) * 100)
|
|
257
258
|
if name[0] == 'E':
|
|
258
|
-
e_total_idle_ratio +=
|
|
259
|
+
e_total_idle_ratio += idle_ratio
|
|
259
260
|
e_core_count += 1
|
|
260
261
|
else:
|
|
261
|
-
p_total_idle_ratio +=
|
|
262
|
+
p_total_idle_ratio += idle_ratio
|
|
262
263
|
p_core_count += 1
|
|
263
264
|
|
|
264
265
|
cpu_metric_dict["E-Cluster_active"] = int((1 - e_total_idle_ratio/e_core_count)*100)
|
|
@@ -340,6 +341,7 @@ class DefaultView():
|
|
|
340
341
|
self.disk_write_bps_peak = 0
|
|
341
342
|
self.network_in_bps_peak = 0
|
|
342
343
|
self.network_out_bps_peak = 0
|
|
344
|
+
self.default_cpu_perline = 8
|
|
343
345
|
self.construct(soc_info_dict,args)
|
|
344
346
|
|
|
345
347
|
def construct(self,soc_info_dict,args):
|
|
@@ -351,15 +353,34 @@ class DefaultView():
|
|
|
351
353
|
self.e_core_count = soc_info_dict["e_core_count"]
|
|
352
354
|
self.e_core_gauges = [VGauge(val=0, color=args.color, border_color=args.color) for _ in range(self.e_core_count)]
|
|
353
355
|
self.p_core_count = soc_info_dict["p_core_count"]
|
|
354
|
-
self.
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
356
|
+
self.max_cpu_perline = self.default_cpu_perline
|
|
357
|
+
for i in range(int(self.default_cpu_perline/2),self.default_cpu_perline):
|
|
358
|
+
if self.p_core_count % i == 0:
|
|
359
|
+
self.max_cpu_perline = i
|
|
360
|
+
break
|
|
361
|
+
import math
|
|
362
|
+
p_core_lines = math.ceil(self.p_core_count / self.max_cpu_perline)
|
|
363
|
+
self.p_core_gauges = []
|
|
364
|
+
self.p_core_split = []
|
|
365
|
+
for i in range(p_core_lines):
|
|
366
|
+
self.p_core_gauges.append([])
|
|
367
|
+
self.p_core_gauges[i].extend([VGauge(val=0, color=args.color, border_color=args.color) for _ in range(self.max_cpu_perline if i < p_core_lines - 1 else self.p_core_count - i * self.max_cpu_perline)])
|
|
360
368
|
self.p_core_split.append(HSplit(
|
|
361
|
-
*self.
|
|
369
|
+
*self.p_core_gauges[i],
|
|
362
370
|
))
|
|
371
|
+
if args.show_cores:
|
|
372
|
+
self.processor_gauges = [self.cpu1_gauge,
|
|
373
|
+
HSplit(*self.e_core_gauges),
|
|
374
|
+
self.cpu2_gauge,]
|
|
375
|
+
#for i in range(len(self.p_core_split)):
|
|
376
|
+
self.processor_gauges.extend(self.p_core_split)
|
|
377
|
+
self.processor_gauges.extend(self.gpu_ane_gauges)
|
|
378
|
+
else:
|
|
379
|
+
self.processor_gauges = [
|
|
380
|
+
HSplit(self.cpu1_gauge, self.cpu2_gauge),
|
|
381
|
+
HSplit(*self.gpu_ane_gauges)
|
|
382
|
+
]
|
|
383
|
+
"""
|
|
363
384
|
self.processor_gauges = [self.cpu1_gauge,
|
|
364
385
|
HSplit(*self.e_core_gauges),
|
|
365
386
|
self.cpu2_gauge,
|
|
@@ -369,6 +390,7 @@ class DefaultView():
|
|
|
369
390
|
HSplit(self.cpu1_gauge, self.cpu2_gauge),
|
|
370
391
|
HSplit(*self.gpu_ane_gauges)
|
|
371
392
|
]
|
|
393
|
+
"""
|
|
372
394
|
self.processor_split = VSplit(
|
|
373
395
|
*self.processor_gauges,
|
|
374
396
|
title="Processor Utilization",
|
|
@@ -515,12 +537,14 @@ class DefaultView():
|
|
|
515
537
|
self.e_core_gauges[i].color = args.color
|
|
516
538
|
self.e_core_gauges[i].border_color = args.color
|
|
517
539
|
for i in range(len(self.p_core_gauges)):
|
|
518
|
-
self.p_core_gauges[i]
|
|
519
|
-
|
|
540
|
+
for j in range(len(self.p_core_gauges[i])):
|
|
541
|
+
self.p_core_gauges[i][j].color = args.color
|
|
542
|
+
self.p_core_gauges[i][j].border_color = args.color
|
|
543
|
+
"""
|
|
520
544
|
for i in range(len(self.p_core_gauges_ext)):
|
|
521
545
|
self.p_core_gauges_ext[i].color = args.color
|
|
522
546
|
self.p_core_gauges_ext[i].border_color = args.color
|
|
523
|
-
|
|
547
|
+
"""
|
|
524
548
|
thermal_pressure = parse_thermal_pressure(powermetrics_parse)
|
|
525
549
|
cpu_metrics_dict = parse_cpu_metrics(powermetrics_parse)
|
|
526
550
|
gpu_metrics_dict = parse_gpu_metrics(powermetrics_parse)
|
|
@@ -577,13 +601,14 @@ class DefaultView():
|
|
|
577
601
|
core_count += 1
|
|
578
602
|
core_count = 0
|
|
579
603
|
for i in cpu_metrics_dict["p_core"]:
|
|
580
|
-
core_gauges =self.p_core_gauges if core_count < 8 else self.p_core_gauges_ext
|
|
581
|
-
core_gauges
|
|
604
|
+
#core_gauges =self.p_core_gauges if core_count < 8 else self.p_core_gauges_ext
|
|
605
|
+
core_gauges = self.p_core_gauges[int(core_count / self.max_cpu_perline)]
|
|
606
|
+
core_gauges[core_count % self.max_cpu_perline].title = "".join([
|
|
582
607
|
("Core-" if self.p_core_count < 6 else 'C-') + str(i + 1) + " ",
|
|
583
608
|
str(cpu_metrics_dict["P-Cluster" + str(i) + "_active"]),
|
|
584
609
|
"%",
|
|
585
610
|
])
|
|
586
|
-
core_gauges[core_count %
|
|
611
|
+
core_gauges[core_count % self.max_cpu_perline].value = cpu_metrics_dict["P-Cluster" + str(i) + "_active"]
|
|
587
612
|
core_count += 1
|
|
588
613
|
|
|
589
614
|
self.gpu_gauge.title = "".join([
|
|
@@ -766,7 +791,7 @@ class DefaultView():
|
|
|
766
791
|
disk_read_iops = disk_metrics_dict["read_iops"]
|
|
767
792
|
if disk_read_iops > self.disk_read_iops_peak:
|
|
768
793
|
self.disk_read_iops_peak = disk_read_iops
|
|
769
|
-
self.disk_read_iops_charts.title = "Read iops: "+ f'{disk_read_iops}
|
|
794
|
+
self.disk_read_iops_charts.title = "Read iops: "+ f'{disk_read_iops}'
|
|
770
795
|
if self.disk_read_iops_charts.datapoints:
|
|
771
796
|
disk_read_iops_rate = int(disk_read_iops / self.disk_read_iops_peak * 100) if self.disk_read_iops_peak > 0 else 0
|
|
772
797
|
else:
|
|
@@ -776,7 +801,7 @@ class DefaultView():
|
|
|
776
801
|
disk_write_iops = disk_metrics_dict["write_iops"]
|
|
777
802
|
if disk_write_iops > self.disk_write_iops_peak:
|
|
778
803
|
self.disk_write_iops_peak = disk_write_iops
|
|
779
|
-
self.disk_write_iops_charts.title = "Write iops: "+ f'{disk_write_iops}
|
|
804
|
+
self.disk_write_iops_charts.title = "Write iops: "+ f'{disk_write_iops}'
|
|
780
805
|
if self.disk_write_iops_charts.datapoints:
|
|
781
806
|
disk_write_iops_rate = int(disk_read_iops / self.disk_write_iops_peak * 100) if self.disk_write_iops_peak > 0 else 0
|
|
782
807
|
else:
|
|
@@ -786,7 +811,7 @@ class DefaultView():
|
|
|
786
811
|
disk_read_bps = disk_metrics_dict["read_Bps"]
|
|
787
812
|
if disk_read_bps > self.disk_read_bps_peak:
|
|
788
813
|
self.disk_read_bps_peak = disk_read_bps
|
|
789
|
-
self.disk_read_bps_charts.title = "Read : "+ f'{format_number(disk_read_bps)}/s
|
|
814
|
+
self.disk_read_bps_charts.title = "Read : "+ f'{format_number(disk_read_bps)}/s'
|
|
790
815
|
if self.disk_read_bps_charts.datapoints:
|
|
791
816
|
disk_read_bps_rate = int(disk_read_bps / self.disk_read_bps_peak * 100) if self.disk_read_bps_peak > 0 else 0
|
|
792
817
|
else:
|
|
@@ -796,7 +821,7 @@ class DefaultView():
|
|
|
796
821
|
disk_write_bps = disk_metrics_dict["write_Bps"]
|
|
797
822
|
if disk_write_bps > self.disk_write_bps_peak:
|
|
798
823
|
self.disk_write_bps_peak = disk_write_bps
|
|
799
|
-
self.disk_write_bps_charts.title = "Write : "+ f'{format_number(disk_write_bps)}/s
|
|
824
|
+
self.disk_write_bps_charts.title = "Write : "+ f'{format_number(disk_write_bps)}/s'
|
|
800
825
|
if self.disk_write_bps_charts.datapoints:
|
|
801
826
|
disk_write_bps_rate = int(disk_write_bps / self.disk_write_bps_peak * 100) if self.disk_write_bps_peak > 0 else 0
|
|
802
827
|
else:
|
|
@@ -806,7 +831,7 @@ class DefaultView():
|
|
|
806
831
|
network_in_bps = network_metrics_dict["in_Bps"]
|
|
807
832
|
if network_in_bps > self.network_in_bps_peak:
|
|
808
833
|
self.network_in_bps_peak = network_in_bps
|
|
809
|
-
self.network_in_bps_charts.title = "in : "+ f'{format_number(network_in_bps)}/s
|
|
834
|
+
self.network_in_bps_charts.title = "in : "+ f'{format_number(network_in_bps)}/s'
|
|
810
835
|
if self.network_in_bps_charts.datapoints:
|
|
811
836
|
network_in_bps_rate = int(network_in_bps / self.network_in_bps_peak * 100) if self.network_in_bps_peak > 0 else 0
|
|
812
837
|
else:
|
|
@@ -816,23 +841,26 @@ class DefaultView():
|
|
|
816
841
|
network_out_bps = network_metrics_dict["out_Bps"]
|
|
817
842
|
if network_out_bps > self.network_out_bps_peak:
|
|
818
843
|
self.network_out_bps_peak = network_out_bps
|
|
819
|
-
self.network_out_bps_charts.title = "out : "+ f'{format_number(network_out_bps)}/s
|
|
844
|
+
self.network_out_bps_charts.title = "out : "+ f'{format_number(network_out_bps)}/s'
|
|
820
845
|
if self.network_out_bps_charts.datapoints:
|
|
821
846
|
network_out_bps_rate = int(network_out_bps / self.network_out_bps_peak * 100) if self.network_out_bps_peak > 0 else 0
|
|
822
847
|
else:
|
|
823
848
|
network_out_bps_rate = 100
|
|
824
849
|
self.network_out_bps_charts.append(network_out_bps_rate)
|
|
825
850
|
|
|
851
|
+
self.disk_io_charts.title = ''.join([f"Disk IO (peak R:{self.disk_read_iops_peak} W:{self.disk_write_iops_peak}",
|
|
852
|
+
f" | R:{format_number(self.disk_read_bps_peak)}/s W:{format_number(self.disk_write_bps_peak)}/s)"
|
|
853
|
+
])
|
|
854
|
+
self.network_io_charts.title = f"Network IO (peak in:{format_number(self.network_in_bps_peak)}/s out:{format_number(self.network_out_bps_peak)}/s)"
|
|
826
855
|
self.ui.display()
|
|
827
856
|
|
|
828
857
|
def get_avg(inlist):
|
|
829
858
|
avg = sum(inlist) / len(inlist)
|
|
830
859
|
return avg
|
|
831
860
|
|
|
832
|
-
def
|
|
861
|
+
def begin(stdscr):
|
|
833
862
|
soc_info_dict = get_soc_info()
|
|
834
|
-
view1 =
|
|
835
|
-
clear_console()
|
|
863
|
+
view1 = None
|
|
836
864
|
stdscr.nodelay(True)
|
|
837
865
|
view = 1
|
|
838
866
|
try:
|
|
@@ -844,6 +872,9 @@ def main(stdscr):
|
|
|
844
872
|
data = data + output
|
|
845
873
|
str_output = output.decode()
|
|
846
874
|
if str_output.startswith('</plist>'):
|
|
875
|
+
if view1 is None:
|
|
876
|
+
view1 = DefaultView(soc_info_dict=soc_info_dict,args=args)
|
|
877
|
+
clear_console()
|
|
847
878
|
data = data.replace(b'\x00',b'')
|
|
848
879
|
powermetrics_parse = plistlib.loads(data)
|
|
849
880
|
key = stdscr.getch()
|
|
@@ -882,18 +913,15 @@ def main(stdscr):
|
|
|
882
913
|
|
|
883
914
|
return
|
|
884
915
|
|
|
885
|
-
|
|
886
|
-
|
|
916
|
+
def main():
|
|
917
|
+
global powermetrics_process
|
|
887
918
|
print(f"\n{version} - enhanced MAC Performance monitoring CLI tool for Apple Silicon")
|
|
888
919
|
print("You can update macpm by running `pip install macpm --upgrade`")
|
|
889
920
|
print("Get help at `https://github.com/visualcjy/macpm`")
|
|
890
921
|
print("P.S. You are recommended to run macpm with `sudo macpm`\n")
|
|
891
922
|
print("\n[1/3] Loading macpm\n")
|
|
892
|
-
print("\033[?25l")
|
|
893
|
-
#global powermetrics_process
|
|
894
|
-
|
|
895
923
|
print("\n[2/3] Starting powermetrics process\n")
|
|
896
|
-
|
|
924
|
+
pause = os.popen("sudo echo").read()
|
|
897
925
|
command = " ".join([
|
|
898
926
|
"sudo nice -n",
|
|
899
927
|
str(10),
|
|
@@ -906,9 +934,14 @@ if __name__ == "__main__":
|
|
|
906
934
|
powermetrics_process = subprocess.Popen(command.split(" "), stdin=PIPE, stdout=PIPE)
|
|
907
935
|
|
|
908
936
|
print("\n[3/3] Waiting for first reading...\n")
|
|
909
|
-
|
|
910
|
-
curses.wrapper(
|
|
937
|
+
print("\033[?25l")
|
|
938
|
+
curses.wrapper(begin)
|
|
911
939
|
print("\033[?25h")
|
|
940
|
+
|
|
941
|
+
if __name__ == "__main__":
|
|
942
|
+
|
|
943
|
+
main()
|
|
944
|
+
|
|
912
945
|
try:
|
|
913
946
|
powermetrics_process.terminate()
|
|
914
947
|
print("Successfully terminated powermetrics process")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|