macpm 0.12__tar.gz → 0.13__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.12 → macpm-0.13}/PKG-INFO +1 -1
- {macpm-0.12 → macpm-0.13}/README.md +4 -1
- {macpm-0.12 → macpm-0.13}/macpm/macpm.py +375 -43
- {macpm-0.12 → macpm-0.13}/macpm.egg-info/PKG-INFO +1 -1
- {macpm-0.12 → macpm-0.13}/macpm.egg-info/SOURCES.txt +0 -2
- {macpm-0.12 → macpm-0.13}/setup.py +1 -2
- macpm-0.12/macpm/parsers.py +0 -171
- macpm-0.12/macpm/utils.py +0 -192
- {macpm-0.12 → macpm-0.13}/LICENSE +0 -0
- {macpm-0.12 → macpm-0.13}/macpm/__init__.py +0 -0
- {macpm-0.12 → macpm-0.13}/macpm.egg-info/dependency_links.txt +0 -0
- {macpm-0.12 → macpm-0.13}/macpm.egg-info/entry_points.txt +0 -0
- {macpm-0.12 → macpm-0.13}/macpm.egg-info/not-zip-safe +0 -0
- {macpm-0.12 → macpm-0.13}/macpm.egg-info/requires.txt +0 -0
- {macpm-0.12 → macpm-0.13}/macpm.egg-info/top_level.txt +0 -0
- {macpm-0.12 → macpm-0.13}/setup.cfg +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# macpm
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
PyPI - Downloads (https://pypi.org/project/macpm/#files)
|
|
4
|
+
or: pip install macpm
|
|
4
5
|
|
|
5
6
|
Performance monitoring CLI tool for Apple Silicon
|
|
6
7
|
|
|
@@ -15,6 +16,8 @@ pip install macpm
|
|
|
15
16
|
forked form https://github.com/tlkh/asitop
|
|
16
17
|
1. fixed the problem that "E-CPU Usage" and "P-CPU Usage" always 100%
|
|
17
18
|
2. add "Disk IO" and "Network IO" info
|
|
19
|
+
3. adjust the hard coded max power in CPU/GPU/ANE
|
|
20
|
+
4. change the way to call powermetrics, no temp files in /tmp
|
|
18
21
|
|
|
19
22
|
A Python-based `nvtop`-inspired command line tool for Apple Silicon (aka M1) Macs.
|
|
20
23
|
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import time
|
|
2
1
|
import argparse
|
|
3
2
|
import humanize
|
|
4
3
|
from collections import deque
|
|
5
4
|
from dashing import VSplit, HSplit, HGauge, HChart, VGauge, HBrailleChart, HBrailleFilledChart
|
|
6
|
-
|
|
5
|
+
import os, time
|
|
6
|
+
import subprocess
|
|
7
|
+
from subprocess import PIPE
|
|
8
|
+
import psutil
|
|
9
|
+
import plistlib
|
|
7
10
|
|
|
8
11
|
parser = argparse.ArgumentParser(
|
|
9
|
-
description='macpm: Performance monitoring CLI tool for Apple Silicon')
|
|
12
|
+
description='macpm v0.13: Performance monitoring CLI tool for Apple Silicon')
|
|
10
13
|
parser.add_argument('--interval', type=int, default=1,
|
|
11
14
|
help='Display interval and sampling interval for powermetrics (seconds)')
|
|
12
15
|
parser.add_argument('--color', type=int, default=2,
|
|
@@ -15,10 +18,314 @@ parser.add_argument('--avg', type=int, default=30,
|
|
|
15
18
|
help='Interval for averaged values (seconds)')
|
|
16
19
|
parser.add_argument('--show_cores', type=bool, default=False,
|
|
17
20
|
help='Choose show cores mode')
|
|
18
|
-
|
|
19
|
-
help='Max show count to restart powermetrics')
|
|
21
|
+
|
|
20
22
|
args = parser.parse_args()
|
|
21
23
|
|
|
24
|
+
powermetrics_process = None
|
|
25
|
+
|
|
26
|
+
def clear_console():
|
|
27
|
+
command = 'clear'
|
|
28
|
+
os.system(command)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def convert_to_GB(value):
|
|
32
|
+
return round(value/1024/1024/1024, 1)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_ram_metrics_dict():
|
|
36
|
+
ram_metrics = psutil.virtual_memory()
|
|
37
|
+
swap_metrics = psutil.swap_memory()
|
|
38
|
+
total_GB = convert_to_GB(ram_metrics.total)
|
|
39
|
+
free_GB = convert_to_GB(ram_metrics.available)
|
|
40
|
+
used_GB = convert_to_GB(ram_metrics.total-ram_metrics.available)
|
|
41
|
+
swap_total_GB = convert_to_GB(swap_metrics.total)
|
|
42
|
+
swap_used_GB = convert_to_GB(swap_metrics.used)
|
|
43
|
+
swap_free_GB = convert_to_GB(swap_metrics.total-swap_metrics.used)
|
|
44
|
+
if swap_total_GB > 0:
|
|
45
|
+
swap_free_percent = int(100-(swap_free_GB/swap_total_GB*100))
|
|
46
|
+
else:
|
|
47
|
+
swap_free_percent = None
|
|
48
|
+
ram_metrics_dict = {
|
|
49
|
+
"total_GB": round(total_GB, 1),
|
|
50
|
+
"free_GB": round(free_GB, 1),
|
|
51
|
+
"used_GB": round(used_GB, 1),
|
|
52
|
+
"free_percent": int(100-(ram_metrics.available/ram_metrics.total*100)),
|
|
53
|
+
"swap_total_GB": swap_total_GB,
|
|
54
|
+
"swap_used_GB": swap_used_GB,
|
|
55
|
+
"swap_free_GB": swap_free_GB,
|
|
56
|
+
"swap_free_percent": swap_free_percent,
|
|
57
|
+
}
|
|
58
|
+
return ram_metrics_dict
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def get_cpu_info():
|
|
62
|
+
cpu_info = os.popen('sysctl -a | grep machdep.cpu').read()
|
|
63
|
+
cpu_info_lines = cpu_info.split("\n")
|
|
64
|
+
data_fields = ["machdep.cpu.brand_string", "machdep.cpu.core_count"]
|
|
65
|
+
cpu_info_dict = {}
|
|
66
|
+
for l in cpu_info_lines:
|
|
67
|
+
for h in data_fields:
|
|
68
|
+
if h in l:
|
|
69
|
+
value = l.split(":")[1].strip()
|
|
70
|
+
cpu_info_dict[h] = value
|
|
71
|
+
return cpu_info_dict
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def get_core_counts():
|
|
75
|
+
cores_info = os.popen('sysctl -a | grep hw.perflevel').read()
|
|
76
|
+
cores_info_lines = cores_info.split("\n")
|
|
77
|
+
data_fields = ["hw.perflevel0.logicalcpu", "hw.perflevel1.logicalcpu"]
|
|
78
|
+
cores_info_dict = {}
|
|
79
|
+
for l in cores_info_lines:
|
|
80
|
+
for h in data_fields:
|
|
81
|
+
if h in l:
|
|
82
|
+
value = int(l.split(":")[1].strip())
|
|
83
|
+
cores_info_dict[h] = value
|
|
84
|
+
return cores_info_dict
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def get_gpu_cores():
|
|
88
|
+
try:
|
|
89
|
+
cores = os.popen(
|
|
90
|
+
"system_profiler -detailLevel basic SPDisplaysDataType | grep 'Total Number of Cores'").read()
|
|
91
|
+
cores = int(cores.split(": ")[-1])
|
|
92
|
+
except:
|
|
93
|
+
cores = "?"
|
|
94
|
+
return cores
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def get_soc_info():
|
|
98
|
+
cpu_info_dict = get_cpu_info()
|
|
99
|
+
core_counts_dict = get_core_counts()
|
|
100
|
+
try:
|
|
101
|
+
e_core_count = core_counts_dict["hw.perflevel1.logicalcpu"]
|
|
102
|
+
p_core_count = core_counts_dict["hw.perflevel0.logicalcpu"]
|
|
103
|
+
except:
|
|
104
|
+
e_core_count = "?"
|
|
105
|
+
p_core_count = "?"
|
|
106
|
+
soc_info = {
|
|
107
|
+
"name": cpu_info_dict["machdep.cpu.brand_string"],
|
|
108
|
+
"core_count": int(cpu_info_dict["machdep.cpu.core_count"]),
|
|
109
|
+
"cpu_max_power": None,
|
|
110
|
+
"gpu_max_power": None,
|
|
111
|
+
"cpu_max_bw": None,
|
|
112
|
+
"gpu_max_bw": None,
|
|
113
|
+
"e_core_count": e_core_count,
|
|
114
|
+
"p_core_count": p_core_count,
|
|
115
|
+
"gpu_core_count": get_gpu_cores()
|
|
116
|
+
}
|
|
117
|
+
# TDP (power)
|
|
118
|
+
if soc_info["name"] == "Apple M1 Max":
|
|
119
|
+
soc_info["cpu_max_power"] = 30
|
|
120
|
+
soc_info["gpu_max_power"] = 60
|
|
121
|
+
elif soc_info["name"] == "Apple M1 Pro":
|
|
122
|
+
soc_info["cpu_max_power"] = 30
|
|
123
|
+
soc_info["gpu_max_power"] = 30
|
|
124
|
+
elif soc_info["name"] == "Apple M1":
|
|
125
|
+
soc_info["cpu_max_power"] = 20
|
|
126
|
+
soc_info["gpu_max_power"] = 20
|
|
127
|
+
elif soc_info["name"] == "Apple M1 Ultra":
|
|
128
|
+
soc_info["cpu_max_power"] = 60
|
|
129
|
+
soc_info["gpu_max_power"] = 120
|
|
130
|
+
elif soc_info["name"] == "Apple M2":
|
|
131
|
+
soc_info["cpu_max_power"] = 25
|
|
132
|
+
soc_info["gpu_max_power"] = 15
|
|
133
|
+
else:
|
|
134
|
+
soc_info["cpu_max_power"] = 20
|
|
135
|
+
soc_info["gpu_max_power"] = 20
|
|
136
|
+
# bandwidth
|
|
137
|
+
if soc_info["name"] == "Apple M1 Max":
|
|
138
|
+
soc_info["cpu_max_bw"] = 250
|
|
139
|
+
soc_info["gpu_max_bw"] = 400
|
|
140
|
+
elif soc_info["name"] == "Apple M1 Pro":
|
|
141
|
+
soc_info["cpu_max_bw"] = 200
|
|
142
|
+
soc_info["gpu_max_bw"] = 200
|
|
143
|
+
elif soc_info["name"] == "Apple M1":
|
|
144
|
+
soc_info["cpu_max_bw"] = 70
|
|
145
|
+
soc_info["gpu_max_bw"] = 70
|
|
146
|
+
elif soc_info["name"] == "Apple M1 Ultra":
|
|
147
|
+
soc_info["cpu_max_bw"] = 500
|
|
148
|
+
soc_info["gpu_max_bw"] = 800
|
|
149
|
+
elif soc_info["name"] == "Apple M2":
|
|
150
|
+
soc_info["cpu_max_bw"] = 100
|
|
151
|
+
soc_info["gpu_max_bw"] = 100
|
|
152
|
+
else:
|
|
153
|
+
soc_info["cpu_max_bw"] = 70
|
|
154
|
+
soc_info["gpu_max_bw"] = 70
|
|
155
|
+
return soc_info
|
|
156
|
+
|
|
157
|
+
def parse_thermal_pressure(powermetrics_parse):
|
|
158
|
+
return powermetrics_parse["thermal_pressure"]
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def parse_bandwidth_metrics(powermetrics_parse):
|
|
162
|
+
bandwidth_metrics = powermetrics_parse["bandwidth_counters"]
|
|
163
|
+
bandwidth_metrics_dict = {}
|
|
164
|
+
data_fields = ["PCPU0 DCS RD", "PCPU0 DCS WR",
|
|
165
|
+
"PCPU1 DCS RD", "PCPU1 DCS WR",
|
|
166
|
+
"PCPU2 DCS RD", "PCPU2 DCS WR",
|
|
167
|
+
"PCPU3 DCS RD", "PCPU3 DCS WR",
|
|
168
|
+
"PCPU DCS RD", "PCPU DCS WR",
|
|
169
|
+
"ECPU0 DCS RD", "ECPU0 DCS WR",
|
|
170
|
+
"ECPU1 DCS RD", "ECPU1 DCS WR",
|
|
171
|
+
"ECPU DCS RD", "ECPU DCS WR",
|
|
172
|
+
"GFX DCS RD", "GFX DCS WR",
|
|
173
|
+
"ISP DCS RD", "ISP DCS WR",
|
|
174
|
+
"STRM CODEC DCS RD", "STRM CODEC DCS WR",
|
|
175
|
+
"PRORES DCS RD", "PRORES DCS WR",
|
|
176
|
+
"VDEC DCS RD", "VDEC DCS WR",
|
|
177
|
+
"VENC0 DCS RD", "VENC0 DCS WR",
|
|
178
|
+
"VENC1 DCS RD", "VENC1 DCS WR",
|
|
179
|
+
"VENC2 DCS RD", "VENC2 DCS WR",
|
|
180
|
+
"VENC3 DCS RD", "VENC3 DCS WR",
|
|
181
|
+
"VENC DCS RD", "VENC DCS WR",
|
|
182
|
+
"JPG0 DCS RD", "JPG0 DCS WR",
|
|
183
|
+
"JPG1 DCS RD", "JPG1 DCS WR",
|
|
184
|
+
"JPG2 DCS RD", "JPG2 DCS WR",
|
|
185
|
+
"JPG3 DCS RD", "JPG3 DCS WR",
|
|
186
|
+
"JPG DCS RD", "JPG DCS WR",
|
|
187
|
+
"DCS RD", "DCS WR"]
|
|
188
|
+
for h in data_fields:
|
|
189
|
+
bandwidth_metrics_dict[h] = 0
|
|
190
|
+
for l in bandwidth_metrics:
|
|
191
|
+
if l["name"] in data_fields:
|
|
192
|
+
bandwidth_metrics_dict[l["name"]] = l["value"]/(1e9)
|
|
193
|
+
bandwidth_metrics_dict["PCPU DCS RD"] = bandwidth_metrics_dict["PCPU DCS RD"] + \
|
|
194
|
+
bandwidth_metrics_dict["PCPU0 DCS RD"] + \
|
|
195
|
+
bandwidth_metrics_dict["PCPU1 DCS RD"] + \
|
|
196
|
+
bandwidth_metrics_dict["PCPU2 DCS RD"] + \
|
|
197
|
+
bandwidth_metrics_dict["PCPU3 DCS RD"]
|
|
198
|
+
bandwidth_metrics_dict["PCPU DCS WR"] = bandwidth_metrics_dict["PCPU DCS WR"] + \
|
|
199
|
+
bandwidth_metrics_dict["PCPU0 DCS WR"] + \
|
|
200
|
+
bandwidth_metrics_dict["PCPU1 DCS WR"] + \
|
|
201
|
+
bandwidth_metrics_dict["PCPU2 DCS WR"] + \
|
|
202
|
+
bandwidth_metrics_dict["PCPU3 DCS WR"]
|
|
203
|
+
bandwidth_metrics_dict["JPG DCS RD"] = bandwidth_metrics_dict["JPG DCS RD"] + \
|
|
204
|
+
bandwidth_metrics_dict["JPG0 DCS RD"] + \
|
|
205
|
+
bandwidth_metrics_dict["JPG1 DCS RD"] + \
|
|
206
|
+
bandwidth_metrics_dict["JPG2 DCS RD"] + \
|
|
207
|
+
bandwidth_metrics_dict["JPG3 DCS RD"]
|
|
208
|
+
bandwidth_metrics_dict["JPG DCS WR"] = bandwidth_metrics_dict["JPG DCS WR"] + \
|
|
209
|
+
bandwidth_metrics_dict["JPG0 DCS WR"] + \
|
|
210
|
+
bandwidth_metrics_dict["JPG1 DCS WR"] + \
|
|
211
|
+
bandwidth_metrics_dict["JPG2 DCS WR"] + \
|
|
212
|
+
bandwidth_metrics_dict["JPG3 DCS WR"]
|
|
213
|
+
bandwidth_metrics_dict["VENC DCS RD"] = bandwidth_metrics_dict["VENC DCS RD"] + \
|
|
214
|
+
bandwidth_metrics_dict["VENC0 DCS RD"] + \
|
|
215
|
+
bandwidth_metrics_dict["VENC1 DCS RD"] + \
|
|
216
|
+
bandwidth_metrics_dict["VENC2 DCS RD"] + \
|
|
217
|
+
bandwidth_metrics_dict["VENC3 DCS RD"]
|
|
218
|
+
bandwidth_metrics_dict["VENC DCS WR"] = bandwidth_metrics_dict["VENC DCS WR"] + \
|
|
219
|
+
bandwidth_metrics_dict["VENC0 DCS WR"] + \
|
|
220
|
+
bandwidth_metrics_dict["VENC1 DCS WR"] + \
|
|
221
|
+
bandwidth_metrics_dict["VENC2 DCS WR"] + \
|
|
222
|
+
bandwidth_metrics_dict["VENC3 DCS WR"]
|
|
223
|
+
bandwidth_metrics_dict["MEDIA DCS"] = sum([
|
|
224
|
+
bandwidth_metrics_dict["ISP DCS RD"], bandwidth_metrics_dict["ISP DCS WR"],
|
|
225
|
+
bandwidth_metrics_dict["STRM CODEC DCS RD"], bandwidth_metrics_dict["STRM CODEC DCS WR"],
|
|
226
|
+
bandwidth_metrics_dict["PRORES DCS RD"], bandwidth_metrics_dict["PRORES DCS WR"],
|
|
227
|
+
bandwidth_metrics_dict["VDEC DCS RD"], bandwidth_metrics_dict["VDEC DCS WR"],
|
|
228
|
+
bandwidth_metrics_dict["VENC DCS RD"], bandwidth_metrics_dict["VENC DCS WR"],
|
|
229
|
+
bandwidth_metrics_dict["JPG DCS RD"], bandwidth_metrics_dict["JPG DCS WR"],
|
|
230
|
+
])
|
|
231
|
+
return bandwidth_metrics_dict
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def parse_cpu_metrics(powermetrics_parse):
|
|
235
|
+
e_core = []
|
|
236
|
+
p_core = []
|
|
237
|
+
cpu_metrics = powermetrics_parse["processor"]
|
|
238
|
+
cpu_metric_dict = {}
|
|
239
|
+
# cpu_clusters
|
|
240
|
+
cpu_clusters = cpu_metrics["clusters"]
|
|
241
|
+
e_total_idle_ratio = 0
|
|
242
|
+
e_core_count = 0
|
|
243
|
+
p_total_idle_ratio = 0
|
|
244
|
+
p_core_count = 0
|
|
245
|
+
for cluster in cpu_clusters:
|
|
246
|
+
name = cluster["name"]
|
|
247
|
+
cpu_metric_dict[name+"_freq_Mhz"] = int(cluster["freq_hz"]/(1e6))
|
|
248
|
+
cpu_metric_dict[name+"_active"] = int((1 - cluster["idle_ratio"])*100)
|
|
249
|
+
for cpu in cluster["cpus"]:
|
|
250
|
+
name = 'E-Cluster' if name[0] == 'E' else 'P-Cluster'
|
|
251
|
+
core = e_core if name[0] == 'E' else p_core
|
|
252
|
+
core.append(cpu["cpu"])
|
|
253
|
+
cpu_metric_dict[name + str(cpu["cpu"]) + "_freq_Mhz"] = int(cpu["freq_hz"] / (1e6))
|
|
254
|
+
cpu_metric_dict[name + str(cpu["cpu"]) + "_active"] = int((1 - cpu["idle_ratio"]) * 100)
|
|
255
|
+
if name[0] == 'E':
|
|
256
|
+
e_total_idle_ratio += cluster["down_ratio"] + (1 - cluster["down_ratio"]) * (cpu["idle_ratio"] + cpu["down_ratio"])
|
|
257
|
+
e_core_count += 1
|
|
258
|
+
else:
|
|
259
|
+
p_total_idle_ratio += cluster["down_ratio"] + (1 - cluster["down_ratio"]) * (cpu["idle_ratio"] + cpu["down_ratio"])
|
|
260
|
+
p_core_count += 1
|
|
261
|
+
|
|
262
|
+
cpu_metric_dict["E-Cluster_active"] = int((1 - e_total_idle_ratio/e_core_count)*100)
|
|
263
|
+
cpu_metric_dict["P-Cluster_active"] = int((1 - p_total_idle_ratio/p_core_count)*100)
|
|
264
|
+
cpu_metric_dict["e_core"] = e_core
|
|
265
|
+
cpu_metric_dict["p_core"] = p_core
|
|
266
|
+
if "E-Cluster_active" not in cpu_metric_dict:
|
|
267
|
+
# M1 Ultra
|
|
268
|
+
cpu_metric_dict["E-Cluster_active"] = int(
|
|
269
|
+
(cpu_metric_dict["E0-Cluster_active"] + cpu_metric_dict["E1-Cluster_active"])/2)
|
|
270
|
+
if "E-Cluster_freq_Mhz" not in cpu_metric_dict:
|
|
271
|
+
# M1 Ultra
|
|
272
|
+
cpu_metric_dict["E-Cluster_freq_Mhz"] = max(
|
|
273
|
+
cpu_metric_dict["E0-Cluster_freq_Mhz"], cpu_metric_dict["E1-Cluster_freq_Mhz"])
|
|
274
|
+
if "P-Cluster_active" not in cpu_metric_dict:
|
|
275
|
+
if "P2-Cluster_active" in cpu_metric_dict:
|
|
276
|
+
# M1 Ultra
|
|
277
|
+
cpu_metric_dict["P-Cluster_active"] = int((cpu_metric_dict["P0-Cluster_active"] + cpu_metric_dict["P1-Cluster_active"] +
|
|
278
|
+
cpu_metric_dict["P2-Cluster_active"] + cpu_metric_dict["P3-Cluster_active"]) / 4)
|
|
279
|
+
else:
|
|
280
|
+
cpu_metric_dict["P-Cluster_active"] = int(
|
|
281
|
+
(cpu_metric_dict["P0-Cluster_active"] + cpu_metric_dict["P1-Cluster_active"])/2)
|
|
282
|
+
if "P-Cluster_freq_Mhz" not in cpu_metric_dict:
|
|
283
|
+
if "P2-Cluster_freq_Mhz" in cpu_metric_dict:
|
|
284
|
+
# M1 Ultra
|
|
285
|
+
freqs = [
|
|
286
|
+
cpu_metric_dict["P0-Cluster_freq_Mhz"],
|
|
287
|
+
cpu_metric_dict["P1-Cluster_freq_Mhz"],
|
|
288
|
+
cpu_metric_dict["P2-Cluster_freq_Mhz"],
|
|
289
|
+
cpu_metric_dict["P3-Cluster_freq_Mhz"]]
|
|
290
|
+
cpu_metric_dict["P-Cluster_freq_Mhz"] = max(freqs)
|
|
291
|
+
else:
|
|
292
|
+
cpu_metric_dict["P-Cluster_freq_Mhz"] = max(
|
|
293
|
+
cpu_metric_dict["P0-Cluster_freq_Mhz"], cpu_metric_dict["P1-Cluster_freq_Mhz"])
|
|
294
|
+
# power
|
|
295
|
+
cpu_metric_dict["ane_W"] = cpu_metrics["ane_energy"]/1000
|
|
296
|
+
#cpu_metric_dict["dram_W"] = cpu_metrics["dram_energy"]/1000
|
|
297
|
+
cpu_metric_dict["cpu_W"] = cpu_metrics["cpu_energy"]/1000
|
|
298
|
+
cpu_metric_dict["gpu_W"] = cpu_metrics["gpu_energy"]/1000
|
|
299
|
+
cpu_metric_dict["package_W"] = cpu_metrics["combined_power"]/1000
|
|
300
|
+
return cpu_metric_dict
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def parse_gpu_metrics(powermetrics_parse):
|
|
304
|
+
gpu_metrics = powermetrics_parse["gpu"]
|
|
305
|
+
gpu_metrics_dict = {
|
|
306
|
+
"freq_MHz": int(gpu_metrics["freq_hz"]),
|
|
307
|
+
"active": int((1 - gpu_metrics["idle_ratio"])*100),
|
|
308
|
+
}
|
|
309
|
+
return gpu_metrics_dict
|
|
310
|
+
|
|
311
|
+
def parse_disk_metrics(powermetrics_parse):
|
|
312
|
+
disk_metrics = powermetrics_parse["disk"]
|
|
313
|
+
disk_metrics_dict = {
|
|
314
|
+
"read_iops": int(disk_metrics["rops_per_s"]),
|
|
315
|
+
"write_iops": int(disk_metrics["wops_per_s"]),
|
|
316
|
+
"read_Bps": int(disk_metrics["rbytes_per_s"]),
|
|
317
|
+
"write_Bps": int(disk_metrics["wbytes_per_s"]),
|
|
318
|
+
}
|
|
319
|
+
return disk_metrics_dict
|
|
320
|
+
|
|
321
|
+
def parse_network_metrics(powermetrics_parse):
|
|
322
|
+
network_metrics = powermetrics_parse["network"]
|
|
323
|
+
network_metrics_dict = {
|
|
324
|
+
"out_Bps": int(network_metrics["obyte_rate"]),
|
|
325
|
+
"in_Bps": int(network_metrics["ibyte_rate"]),
|
|
326
|
+
}
|
|
327
|
+
return network_metrics_dict
|
|
328
|
+
|
|
22
329
|
|
|
23
330
|
def main():
|
|
24
331
|
print("\nmacpm - Performance monitoring CLI tool for Apple Silicon")
|
|
@@ -27,7 +334,7 @@ def main():
|
|
|
27
334
|
print("P.S. You are recommended to run macpm with `sudo macpm`\n")
|
|
28
335
|
print("\n[1/3] Loading macpm\n")
|
|
29
336
|
print("\033[?25l")
|
|
30
|
-
|
|
337
|
+
global powermetrics_process
|
|
31
338
|
cpu1_gauge = HGauge(title="E-CPU Usage", val=0, color=args.color)
|
|
32
339
|
cpu2_gauge = HGauge(title="P-CPU Usage", val=0, color=args.color)
|
|
33
340
|
gpu_gauge = HGauge(title="GPU Usage", val=0, color=args.color)
|
|
@@ -158,7 +465,7 @@ def main():
|
|
|
158
465
|
usage_gauges.title = cpu_title
|
|
159
466
|
cpu_max_power = soc_info_dict["cpu_max_power"]
|
|
160
467
|
gpu_max_power = soc_info_dict["gpu_max_power"]
|
|
161
|
-
ane_max_power =
|
|
468
|
+
ane_max_power = 16.0
|
|
162
469
|
"""max_cpu_bw = soc_info_dict["cpu_max_bw"]
|
|
163
470
|
max_gpu_bw = soc_info_dict["gpu_max_bw"]
|
|
164
471
|
max_media_bw = 7.0"""
|
|
@@ -177,11 +484,24 @@ def main():
|
|
|
177
484
|
|
|
178
485
|
timecode = str(int(time.time()))
|
|
179
486
|
|
|
180
|
-
powermetrics_process = run_powermetrics_process(timecode,
|
|
181
|
-
|
|
487
|
+
#powermetrics_process = run_powermetrics_process(timecode,
|
|
488
|
+
# interval=args.interval * 1000)
|
|
489
|
+
|
|
490
|
+
command = " ".join([
|
|
491
|
+
"sudo nice -n",
|
|
492
|
+
str(10),
|
|
493
|
+
"powermetrics",
|
|
494
|
+
"--samplers cpu_power,gpu_power,thermal,network,disk",
|
|
495
|
+
"-f plist",
|
|
496
|
+
"-i",
|
|
497
|
+
str(args.interval * 1000)
|
|
498
|
+
])
|
|
499
|
+
process = subprocess.Popen(command.split(" "), stdin=PIPE, stdout=PIPE)
|
|
500
|
+
|
|
501
|
+
powermetrics_process = process
|
|
182
502
|
|
|
183
503
|
print("\n[3/3] Waiting for first reading...\n")
|
|
184
|
-
|
|
504
|
+
"""
|
|
185
505
|
def get_reading(wait=0.1):
|
|
186
506
|
ready = parse_powermetrics(timecode=timecode)
|
|
187
507
|
while not ready:
|
|
@@ -191,7 +511,7 @@ def main():
|
|
|
191
511
|
|
|
192
512
|
ready = get_reading()
|
|
193
513
|
last_timestamp = ready[-1]
|
|
194
|
-
|
|
514
|
+
"""
|
|
195
515
|
def get_avg(inlist):
|
|
196
516
|
avg = sum(inlist) / len(inlist)
|
|
197
517
|
return avg
|
|
@@ -202,24 +522,28 @@ def main():
|
|
|
202
522
|
|
|
203
523
|
clear_console()
|
|
204
524
|
|
|
205
|
-
count=0
|
|
206
525
|
try:
|
|
526
|
+
data = b''
|
|
207
527
|
while True:
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
cpu_metrics_dict
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
528
|
+
output = process.stdout.readline()
|
|
529
|
+
#output, stderr = process.communicate()
|
|
530
|
+
if process.poll() is not None:
|
|
531
|
+
break
|
|
532
|
+
data = data + output
|
|
533
|
+
str_output = output.decode()
|
|
534
|
+
if str_output.startswith('</plist>'):
|
|
535
|
+
data = data.replace(b'\x00',b'')
|
|
536
|
+
powermetrics_parse = plistlib.loads(data)
|
|
537
|
+
thermal_pressure = parse_thermal_pressure(powermetrics_parse)
|
|
538
|
+
cpu_metrics_dict = parse_cpu_metrics(powermetrics_parse)
|
|
539
|
+
gpu_metrics_dict = parse_gpu_metrics(powermetrics_parse)
|
|
540
|
+
disk_metrics_dict = parse_disk_metrics(powermetrics_parse)
|
|
541
|
+
network_metrics_dict = parse_network_metrics(powermetrics_parse)
|
|
542
|
+
#bandwidth_metrics = parse_bandwidth_metrics(powermetrics_parse)
|
|
543
|
+
bandwidth_metrics = None
|
|
544
|
+
timestamp = powermetrics_parse["timestamp"]
|
|
545
|
+
data = b''
|
|
546
|
+
if timestamp :
|
|
223
547
|
if thermal_pressure == "Nominal":
|
|
224
548
|
thermal_throttle = "no"
|
|
225
549
|
else:
|
|
@@ -285,14 +609,16 @@ def main():
|
|
|
285
609
|
])
|
|
286
610
|
gpu_gauge.value = gpu_metrics_dict["active"]
|
|
287
611
|
|
|
612
|
+
ane_power_W = cpu_metrics_dict["ane_W"] / args.interval
|
|
613
|
+
if ane_power_W > ane_max_power:
|
|
614
|
+
ane_max_power = ane_power_W
|
|
288
615
|
ane_util_percent = int(
|
|
289
|
-
|
|
616
|
+
ane_power_W / ane_max_power * 100)
|
|
290
617
|
ane_gauge.title = "".join([
|
|
291
618
|
"ANE Usage: ",
|
|
292
619
|
str(ane_util_percent),
|
|
293
620
|
"% @ ",
|
|
294
|
-
'{0:.1f}'.format(
|
|
295
|
-
cpu_metrics_dict["ane_W"] / args.interval),
|
|
621
|
+
'{0:.1f}'.format(ane_power_W),
|
|
296
622
|
" W"
|
|
297
623
|
])
|
|
298
624
|
ane_gauge.value = ane_util_percent
|
|
@@ -408,11 +734,13 @@ def main():
|
|
|
408
734
|
thermal_throttle,
|
|
409
735
|
])
|
|
410
736
|
|
|
411
|
-
cpu_power_percent = int(
|
|
412
|
-
cpu_metrics_dict["cpu_W"] / args.interval / cpu_max_power * 100)
|
|
413
737
|
cpu_power_W = cpu_metrics_dict["cpu_W"] / args.interval
|
|
414
738
|
if cpu_power_W > cpu_peak_power:
|
|
415
739
|
cpu_peak_power = cpu_power_W
|
|
740
|
+
if cpu_power_W > cpu_max_power:
|
|
741
|
+
cpu_max_power = cpu_power_W
|
|
742
|
+
cpu_power_percent = int(
|
|
743
|
+
cpu_power_W / cpu_max_power * 100)
|
|
416
744
|
avg_cpu_power_list.append(cpu_power_W)
|
|
417
745
|
avg_cpu_power = get_avg(avg_cpu_power_list)
|
|
418
746
|
cpu_power_chart.title = "".join([
|
|
@@ -426,11 +754,13 @@ def main():
|
|
|
426
754
|
])
|
|
427
755
|
cpu_power_chart.append(cpu_power_percent)
|
|
428
756
|
|
|
429
|
-
gpu_power_percent = int(
|
|
430
|
-
cpu_metrics_dict["gpu_W"] / args.interval / gpu_max_power * 100)
|
|
431
757
|
gpu_power_W = cpu_metrics_dict["gpu_W"] / args.interval
|
|
432
758
|
if gpu_power_W > gpu_peak_power:
|
|
433
759
|
gpu_peak_power = gpu_power_W
|
|
760
|
+
if gpu_power_W > gpu_max_power:
|
|
761
|
+
gpu_max_power = gpu_power_W
|
|
762
|
+
gpu_power_percent = int(
|
|
763
|
+
gpu_power_W / gpu_max_power * 100)
|
|
434
764
|
avg_gpu_power_list.append(gpu_power_W)
|
|
435
765
|
avg_gpu_power = get_avg(avg_gpu_power_list)
|
|
436
766
|
gpu_power_chart.title = "".join([
|
|
@@ -452,7 +782,7 @@ def main():
|
|
|
452
782
|
disk_read_iops_peak = disk_read_iops
|
|
453
783
|
disk_read_iops_charts.title = "Read iops: "+ f'{disk_read_iops} (peak: {disk_read_iops_peak})'
|
|
454
784
|
if disk_read_iops_charts.datapoints:
|
|
455
|
-
disk_read_iops_rate = int(disk_read_iops / disk_read_iops_peak * 100)
|
|
785
|
+
disk_read_iops_rate = int(disk_read_iops / disk_read_iops_peak * 100) if disk_read_iops_peak > 0 else 0
|
|
456
786
|
else:
|
|
457
787
|
disk_read_iops_rate = 100
|
|
458
788
|
disk_read_iops_charts.append(disk_read_iops_rate)
|
|
@@ -462,7 +792,7 @@ def main():
|
|
|
462
792
|
disk_write_iops_peak = disk_write_iops
|
|
463
793
|
disk_write_iops_charts.title = "Write iops: "+ f'{disk_write_iops} (peak: {disk_write_iops_peak})'
|
|
464
794
|
if disk_write_iops_charts.datapoints:
|
|
465
|
-
disk_write_iops_rate = int(disk_read_iops / disk_write_iops_peak * 100)
|
|
795
|
+
disk_write_iops_rate = int(disk_read_iops / disk_write_iops_peak * 100) if disk_write_iops_peak > 0 else 0
|
|
466
796
|
else:
|
|
467
797
|
disk_write_iops_rate = 100
|
|
468
798
|
disk_write_iops_charts.append(disk_write_iops_rate)
|
|
@@ -472,7 +802,7 @@ def main():
|
|
|
472
802
|
disk_read_bps_peak = disk_read_bps
|
|
473
803
|
disk_read_bps_charts.title = "Read : "+ f'{format_number(disk_read_bps)}/s (peak: {format_number(disk_read_bps_peak)}/s)'
|
|
474
804
|
if disk_read_bps_charts.datapoints:
|
|
475
|
-
disk_read_bps_rate = int(disk_read_bps / disk_read_bps_peak * 100)
|
|
805
|
+
disk_read_bps_rate = int(disk_read_bps / disk_read_bps_peak * 100) if disk_read_bps_peak > 0 else 0
|
|
476
806
|
else:
|
|
477
807
|
disk_read_bps_rate = 100
|
|
478
808
|
disk_read_bps_charts.append(disk_read_bps_rate)
|
|
@@ -482,7 +812,7 @@ def main():
|
|
|
482
812
|
disk_write_bps_peak = disk_write_bps
|
|
483
813
|
disk_write_bps_charts.title = "Write : "+ f'{format_number(disk_write_bps)}/s (peak: {format_number(disk_write_bps_peak)}/s)'
|
|
484
814
|
if disk_write_bps_charts.datapoints:
|
|
485
|
-
disk_write_bps_rate = int(disk_write_bps / disk_write_bps_peak * 100)
|
|
815
|
+
disk_write_bps_rate = int(disk_write_bps / disk_write_bps_peak * 100) if disk_write_bps_peak > 0 else 0
|
|
486
816
|
else:
|
|
487
817
|
disk_write_bps_rate = 100
|
|
488
818
|
disk_write_bps_charts.append(disk_write_bps_rate)
|
|
@@ -492,7 +822,7 @@ def main():
|
|
|
492
822
|
network_in_bps_peak = network_in_bps
|
|
493
823
|
network_in_bps_charts.title = "in : "+ f'{format_number(network_in_bps)}/s (peak: {format_number(network_in_bps_peak)}/s)'
|
|
494
824
|
if network_in_bps_charts.datapoints:
|
|
495
|
-
network_in_bps_rate = int(network_in_bps / network_in_bps_peak * 100)
|
|
825
|
+
network_in_bps_rate = int(network_in_bps / network_in_bps_peak * 100) if network_in_bps_peak > 0 else 0
|
|
496
826
|
else:
|
|
497
827
|
network_in_bps_rate = 100
|
|
498
828
|
network_in_bps_charts.append(network_in_bps_rate)
|
|
@@ -502,24 +832,25 @@ def main():
|
|
|
502
832
|
network_out_bps_peak = network_out_bps
|
|
503
833
|
network_out_bps_charts.title = "out : "+ f'{format_number(network_out_bps)}/s (peak: {format_number(network_out_bps_peak)}/s)'
|
|
504
834
|
if network_out_bps_charts.datapoints:
|
|
505
|
-
network_out_bps_rate = int(network_out_bps / network_out_bps_peak * 100)
|
|
835
|
+
network_out_bps_rate = int(network_out_bps / network_out_bps_peak * 100) if network_out_bps_peak > 0 else 0
|
|
506
836
|
else:
|
|
507
837
|
network_out_bps_rate = 100
|
|
508
838
|
network_out_bps_charts.append(network_out_bps_rate)
|
|
509
839
|
|
|
510
840
|
ui.display()
|
|
511
841
|
|
|
512
|
-
|
|
842
|
+
if str_output == '':
|
|
843
|
+
time.sleep(0.1)
|
|
513
844
|
|
|
514
845
|
except KeyboardInterrupt:
|
|
515
846
|
print("Stopping...")
|
|
516
847
|
print("\033[?25h")
|
|
517
848
|
|
|
518
|
-
return
|
|
849
|
+
return
|
|
519
850
|
|
|
520
851
|
|
|
521
852
|
if __name__ == "__main__":
|
|
522
|
-
|
|
853
|
+
main()
|
|
523
854
|
try:
|
|
524
855
|
powermetrics_process.terminate()
|
|
525
856
|
print("Successfully terminated powermetrics process")
|
|
@@ -527,3 +858,4 @@ if __name__ == "__main__":
|
|
|
527
858
|
print(e)
|
|
528
859
|
powermetrics_process.terminate()
|
|
529
860
|
print("Successfully terminated powermetrics process")
|
|
861
|
+
|
|
@@ -4,7 +4,7 @@ long_description = 'Performance monitoring CLI tool for Apple Silicon'
|
|
|
4
4
|
|
|
5
5
|
setup(
|
|
6
6
|
name='macpm',
|
|
7
|
-
version='0.
|
|
7
|
+
version='0.13',
|
|
8
8
|
author='Jinyu Chen',
|
|
9
9
|
author_email='visualcjy@mail.com',
|
|
10
10
|
url='https://github.com/visualcjy/macpm',
|
|
@@ -13,7 +13,6 @@ setup(
|
|
|
13
13
|
long_description_content_type="text/markdown",
|
|
14
14
|
license='MIT',
|
|
15
15
|
packages=find_packages(),
|
|
16
|
-
package_dir={'macpm':'macpm'},
|
|
17
16
|
entry_points={
|
|
18
17
|
'console_scripts': [
|
|
19
18
|
'macpm = macpm.macpm:main'
|
macpm-0.12/macpm/parsers.py
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
def parse_thermal_pressure(powermetrics_parse):
|
|
2
|
-
return powermetrics_parse["thermal_pressure"]
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def parse_bandwidth_metrics(powermetrics_parse):
|
|
6
|
-
bandwidth_metrics = powermetrics_parse["bandwidth_counters"]
|
|
7
|
-
bandwidth_metrics_dict = {}
|
|
8
|
-
data_fields = ["PCPU0 DCS RD", "PCPU0 DCS WR",
|
|
9
|
-
"PCPU1 DCS RD", "PCPU1 DCS WR",
|
|
10
|
-
"PCPU2 DCS RD", "PCPU2 DCS WR",
|
|
11
|
-
"PCPU3 DCS RD", "PCPU3 DCS WR",
|
|
12
|
-
"PCPU DCS RD", "PCPU DCS WR",
|
|
13
|
-
"ECPU0 DCS RD", "ECPU0 DCS WR",
|
|
14
|
-
"ECPU1 DCS RD", "ECPU1 DCS WR",
|
|
15
|
-
"ECPU DCS RD", "ECPU DCS WR",
|
|
16
|
-
"GFX DCS RD", "GFX DCS WR",
|
|
17
|
-
"ISP DCS RD", "ISP DCS WR",
|
|
18
|
-
"STRM CODEC DCS RD", "STRM CODEC DCS WR",
|
|
19
|
-
"PRORES DCS RD", "PRORES DCS WR",
|
|
20
|
-
"VDEC DCS RD", "VDEC DCS WR",
|
|
21
|
-
"VENC0 DCS RD", "VENC0 DCS WR",
|
|
22
|
-
"VENC1 DCS RD", "VENC1 DCS WR",
|
|
23
|
-
"VENC2 DCS RD", "VENC2 DCS WR",
|
|
24
|
-
"VENC3 DCS RD", "VENC3 DCS WR",
|
|
25
|
-
"VENC DCS RD", "VENC DCS WR",
|
|
26
|
-
"JPG0 DCS RD", "JPG0 DCS WR",
|
|
27
|
-
"JPG1 DCS RD", "JPG1 DCS WR",
|
|
28
|
-
"JPG2 DCS RD", "JPG2 DCS WR",
|
|
29
|
-
"JPG3 DCS RD", "JPG3 DCS WR",
|
|
30
|
-
"JPG DCS RD", "JPG DCS WR",
|
|
31
|
-
"DCS RD", "DCS WR"]
|
|
32
|
-
for h in data_fields:
|
|
33
|
-
bandwidth_metrics_dict[h] = 0
|
|
34
|
-
for l in bandwidth_metrics:
|
|
35
|
-
if l["name"] in data_fields:
|
|
36
|
-
bandwidth_metrics_dict[l["name"]] = l["value"]/(1e9)
|
|
37
|
-
bandwidth_metrics_dict["PCPU DCS RD"] = bandwidth_metrics_dict["PCPU DCS RD"] + \
|
|
38
|
-
bandwidth_metrics_dict["PCPU0 DCS RD"] + \
|
|
39
|
-
bandwidth_metrics_dict["PCPU1 DCS RD"] + \
|
|
40
|
-
bandwidth_metrics_dict["PCPU2 DCS RD"] + \
|
|
41
|
-
bandwidth_metrics_dict["PCPU3 DCS RD"]
|
|
42
|
-
bandwidth_metrics_dict["PCPU DCS WR"] = bandwidth_metrics_dict["PCPU DCS WR"] + \
|
|
43
|
-
bandwidth_metrics_dict["PCPU0 DCS WR"] + \
|
|
44
|
-
bandwidth_metrics_dict["PCPU1 DCS WR"] + \
|
|
45
|
-
bandwidth_metrics_dict["PCPU2 DCS WR"] + \
|
|
46
|
-
bandwidth_metrics_dict["PCPU3 DCS WR"]
|
|
47
|
-
bandwidth_metrics_dict["JPG DCS RD"] = bandwidth_metrics_dict["JPG DCS RD"] + \
|
|
48
|
-
bandwidth_metrics_dict["JPG0 DCS RD"] + \
|
|
49
|
-
bandwidth_metrics_dict["JPG1 DCS RD"] + \
|
|
50
|
-
bandwidth_metrics_dict["JPG2 DCS RD"] + \
|
|
51
|
-
bandwidth_metrics_dict["JPG3 DCS RD"]
|
|
52
|
-
bandwidth_metrics_dict["JPG DCS WR"] = bandwidth_metrics_dict["JPG DCS WR"] + \
|
|
53
|
-
bandwidth_metrics_dict["JPG0 DCS WR"] + \
|
|
54
|
-
bandwidth_metrics_dict["JPG1 DCS WR"] + \
|
|
55
|
-
bandwidth_metrics_dict["JPG2 DCS WR"] + \
|
|
56
|
-
bandwidth_metrics_dict["JPG3 DCS WR"]
|
|
57
|
-
bandwidth_metrics_dict["VENC DCS RD"] = bandwidth_metrics_dict["VENC DCS RD"] + \
|
|
58
|
-
bandwidth_metrics_dict["VENC0 DCS RD"] + \
|
|
59
|
-
bandwidth_metrics_dict["VENC1 DCS RD"] + \
|
|
60
|
-
bandwidth_metrics_dict["VENC2 DCS RD"] + \
|
|
61
|
-
bandwidth_metrics_dict["VENC3 DCS RD"]
|
|
62
|
-
bandwidth_metrics_dict["VENC DCS WR"] = bandwidth_metrics_dict["VENC DCS WR"] + \
|
|
63
|
-
bandwidth_metrics_dict["VENC0 DCS WR"] + \
|
|
64
|
-
bandwidth_metrics_dict["VENC1 DCS WR"] + \
|
|
65
|
-
bandwidth_metrics_dict["VENC2 DCS WR"] + \
|
|
66
|
-
bandwidth_metrics_dict["VENC3 DCS WR"]
|
|
67
|
-
bandwidth_metrics_dict["MEDIA DCS"] = sum([
|
|
68
|
-
bandwidth_metrics_dict["ISP DCS RD"], bandwidth_metrics_dict["ISP DCS WR"],
|
|
69
|
-
bandwidth_metrics_dict["STRM CODEC DCS RD"], bandwidth_metrics_dict["STRM CODEC DCS WR"],
|
|
70
|
-
bandwidth_metrics_dict["PRORES DCS RD"], bandwidth_metrics_dict["PRORES DCS WR"],
|
|
71
|
-
bandwidth_metrics_dict["VDEC DCS RD"], bandwidth_metrics_dict["VDEC DCS WR"],
|
|
72
|
-
bandwidth_metrics_dict["VENC DCS RD"], bandwidth_metrics_dict["VENC DCS WR"],
|
|
73
|
-
bandwidth_metrics_dict["JPG DCS RD"], bandwidth_metrics_dict["JPG DCS WR"],
|
|
74
|
-
])
|
|
75
|
-
return bandwidth_metrics_dict
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def parse_cpu_metrics(powermetrics_parse):
|
|
79
|
-
e_core = []
|
|
80
|
-
p_core = []
|
|
81
|
-
cpu_metrics = powermetrics_parse["processor"]
|
|
82
|
-
cpu_metric_dict = {}
|
|
83
|
-
# cpu_clusters
|
|
84
|
-
cpu_clusters = cpu_metrics["clusters"]
|
|
85
|
-
e_total_idle_ratio = 0
|
|
86
|
-
e_core_count = 0
|
|
87
|
-
p_total_idle_ratio = 0
|
|
88
|
-
p_core_count = 0
|
|
89
|
-
for cluster in cpu_clusters:
|
|
90
|
-
name = cluster["name"]
|
|
91
|
-
cpu_metric_dict[name+"_freq_Mhz"] = int(cluster["freq_hz"]/(1e6))
|
|
92
|
-
cpu_metric_dict[name+"_active"] = int((1 - cluster["idle_ratio"])*100)
|
|
93
|
-
for cpu in cluster["cpus"]:
|
|
94
|
-
name = 'E-Cluster' if name[0] == 'E' else 'P-Cluster'
|
|
95
|
-
core = e_core if name[0] == 'E' else p_core
|
|
96
|
-
core.append(cpu["cpu"])
|
|
97
|
-
cpu_metric_dict[name + str(cpu["cpu"]) + "_freq_Mhz"] = int(cpu["freq_hz"] / (1e6))
|
|
98
|
-
cpu_metric_dict[name + str(cpu["cpu"]) + "_active"] = int((1 - cpu["idle_ratio"]) * 100)
|
|
99
|
-
if name[0] == 'E':
|
|
100
|
-
e_total_idle_ratio += cluster["down_ratio"] + (1 - cluster["down_ratio"]) * (cpu["idle_ratio"] + cpu["down_ratio"])
|
|
101
|
-
e_core_count += 1
|
|
102
|
-
else:
|
|
103
|
-
p_total_idle_ratio += cluster["down_ratio"] + (1 - cluster["down_ratio"]) * (cpu["idle_ratio"] + cpu["down_ratio"])
|
|
104
|
-
p_core_count += 1
|
|
105
|
-
|
|
106
|
-
cpu_metric_dict["E-Cluster_active"] = int((1 - e_total_idle_ratio/e_core_count)*100)
|
|
107
|
-
cpu_metric_dict["P-Cluster_active"] = int((1 - p_total_idle_ratio/p_core_count)*100)
|
|
108
|
-
cpu_metric_dict["e_core"] = e_core
|
|
109
|
-
cpu_metric_dict["p_core"] = p_core
|
|
110
|
-
if "E-Cluster_active" not in cpu_metric_dict:
|
|
111
|
-
# M1 Ultra
|
|
112
|
-
cpu_metric_dict["E-Cluster_active"] = int(
|
|
113
|
-
(cpu_metric_dict["E0-Cluster_active"] + cpu_metric_dict["E1-Cluster_active"])/2)
|
|
114
|
-
if "E-Cluster_freq_Mhz" not in cpu_metric_dict:
|
|
115
|
-
# M1 Ultra
|
|
116
|
-
cpu_metric_dict["E-Cluster_freq_Mhz"] = max(
|
|
117
|
-
cpu_metric_dict["E0-Cluster_freq_Mhz"], cpu_metric_dict["E1-Cluster_freq_Mhz"])
|
|
118
|
-
if "P-Cluster_active" not in cpu_metric_dict:
|
|
119
|
-
if "P2-Cluster_active" in cpu_metric_dict:
|
|
120
|
-
# M1 Ultra
|
|
121
|
-
cpu_metric_dict["P-Cluster_active"] = int((cpu_metric_dict["P0-Cluster_active"] + cpu_metric_dict["P1-Cluster_active"] +
|
|
122
|
-
cpu_metric_dict["P2-Cluster_active"] + cpu_metric_dict["P3-Cluster_active"]) / 4)
|
|
123
|
-
else:
|
|
124
|
-
cpu_metric_dict["P-Cluster_active"] = int(
|
|
125
|
-
(cpu_metric_dict["P0-Cluster_active"] + cpu_metric_dict["P1-Cluster_active"])/2)
|
|
126
|
-
if "P-Cluster_freq_Mhz" not in cpu_metric_dict:
|
|
127
|
-
if "P2-Cluster_freq_Mhz" in cpu_metric_dict:
|
|
128
|
-
# M1 Ultra
|
|
129
|
-
freqs = [
|
|
130
|
-
cpu_metric_dict["P0-Cluster_freq_Mhz"],
|
|
131
|
-
cpu_metric_dict["P1-Cluster_freq_Mhz"],
|
|
132
|
-
cpu_metric_dict["P2-Cluster_freq_Mhz"],
|
|
133
|
-
cpu_metric_dict["P3-Cluster_freq_Mhz"]]
|
|
134
|
-
cpu_metric_dict["P-Cluster_freq_Mhz"] = max(freqs)
|
|
135
|
-
else:
|
|
136
|
-
cpu_metric_dict["P-Cluster_freq_Mhz"] = max(
|
|
137
|
-
cpu_metric_dict["P0-Cluster_freq_Mhz"], cpu_metric_dict["P1-Cluster_freq_Mhz"])
|
|
138
|
-
# power
|
|
139
|
-
cpu_metric_dict["ane_W"] = cpu_metrics["ane_energy"]/1000
|
|
140
|
-
#cpu_metric_dict["dram_W"] = cpu_metrics["dram_energy"]/1000
|
|
141
|
-
cpu_metric_dict["cpu_W"] = cpu_metrics["cpu_energy"]/1000
|
|
142
|
-
cpu_metric_dict["gpu_W"] = cpu_metrics["gpu_energy"]/1000
|
|
143
|
-
cpu_metric_dict["package_W"] = cpu_metrics["combined_power"]/1000
|
|
144
|
-
return cpu_metric_dict
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def parse_gpu_metrics(powermetrics_parse):
|
|
148
|
-
gpu_metrics = powermetrics_parse["gpu"]
|
|
149
|
-
gpu_metrics_dict = {
|
|
150
|
-
"freq_MHz": int(gpu_metrics["freq_hz"]),
|
|
151
|
-
"active": int((1 - gpu_metrics["idle_ratio"])*100),
|
|
152
|
-
}
|
|
153
|
-
return gpu_metrics_dict
|
|
154
|
-
|
|
155
|
-
def parse_disk_metrics(powermetrics_parse):
|
|
156
|
-
disk_metrics = powermetrics_parse["disk"]
|
|
157
|
-
disk_metrics_dict = {
|
|
158
|
-
"read_iops": int(disk_metrics["rops_per_s"]),
|
|
159
|
-
"write_iops": int(disk_metrics["wops_per_s"]),
|
|
160
|
-
"read_Bps": int(disk_metrics["rbytes_per_s"]),
|
|
161
|
-
"write_Bps": int(disk_metrics["wbytes_per_s"]),
|
|
162
|
-
}
|
|
163
|
-
return disk_metrics_dict
|
|
164
|
-
|
|
165
|
-
def parse_network_metrics(powermetrics_parse):
|
|
166
|
-
network_metrics = powermetrics_parse["network"]
|
|
167
|
-
network_metrics_dict = {
|
|
168
|
-
"out_Bps": int(network_metrics["obyte_rate"]),
|
|
169
|
-
"in_Bps": int(network_metrics["ibyte_rate"]),
|
|
170
|
-
}
|
|
171
|
-
return network_metrics_dict
|
macpm-0.12/macpm/utils.py
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import glob
|
|
3
|
-
import subprocess
|
|
4
|
-
from subprocess import PIPE
|
|
5
|
-
import psutil
|
|
6
|
-
from .parsers import *
|
|
7
|
-
import plistlib
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def parse_powermetrics(path='/tmp/asitop_powermetrics', timecode="0"):
|
|
11
|
-
data = None
|
|
12
|
-
try:
|
|
13
|
-
with open(path+timecode, 'rb') as fp:
|
|
14
|
-
data = fp.read()
|
|
15
|
-
data = data.split(b'\x00')
|
|
16
|
-
powermetrics_parse = plistlib.loads(data[-1])
|
|
17
|
-
thermal_pressure = parse_thermal_pressure(powermetrics_parse)
|
|
18
|
-
cpu_metrics_dict = parse_cpu_metrics(powermetrics_parse)
|
|
19
|
-
gpu_metrics_dict = parse_gpu_metrics(powermetrics_parse)
|
|
20
|
-
disk_metrics_dict = parse_disk_metrics(powermetrics_parse)
|
|
21
|
-
network_metrics_dict = parse_network_metrics(powermetrics_parse)
|
|
22
|
-
#bandwidth_metrics = parse_bandwidth_metrics(powermetrics_parse)
|
|
23
|
-
bandwidth_metrics = None
|
|
24
|
-
timestamp = powermetrics_parse["timestamp"]
|
|
25
|
-
return cpu_metrics_dict, gpu_metrics_dict, thermal_pressure, bandwidth_metrics, disk_metrics_dict, network_metrics_dict, timestamp
|
|
26
|
-
except Exception as e:
|
|
27
|
-
if data:
|
|
28
|
-
if len(data) > 1:
|
|
29
|
-
powermetrics_parse = plistlib.loads(data[-2])
|
|
30
|
-
thermal_pressure = parse_thermal_pressure(powermetrics_parse)
|
|
31
|
-
cpu_metrics_dict = parse_cpu_metrics(powermetrics_parse)
|
|
32
|
-
gpu_metrics_dict = parse_gpu_metrics(powermetrics_parse)
|
|
33
|
-
disk_metrics_dict = parse_disk_metrics(powermetrics_parse)
|
|
34
|
-
network_metrics_dict = parse_network_metrics(powermetrics_parse)
|
|
35
|
-
#bandwidth_metrics = parse_bandwidth_metrics(powermetrics_parse)
|
|
36
|
-
bandwidth_metrics = None
|
|
37
|
-
timestamp = powermetrics_parse["timestamp"]
|
|
38
|
-
return cpu_metrics_dict, gpu_metrics_dict, thermal_pressure, bandwidth_metrics, disk_metrics_dict, network_metrics_dict, timestamp
|
|
39
|
-
return False
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def clear_console():
|
|
43
|
-
command = 'clear'
|
|
44
|
-
os.system(command)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def convert_to_GB(value):
|
|
48
|
-
return round(value/1024/1024/1024, 1)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def run_powermetrics_process(timecode, nice=10, interval=1000):
|
|
52
|
-
#ver, *_ = platform.mac_ver()
|
|
53
|
-
#major_ver = int(ver.split(".")[0])
|
|
54
|
-
#for tmpf in glob.glob("/tmp/asitop_powermetrics*"):
|
|
55
|
-
# os.remove(tmpf)
|
|
56
|
-
output_file_flag = "-o"
|
|
57
|
-
command = " ".join([
|
|
58
|
-
"sudo nice -n",
|
|
59
|
-
str(nice),
|
|
60
|
-
"powermetrics",
|
|
61
|
-
"--samplers cpu_power,gpu_power,thermal,network,disk",
|
|
62
|
-
output_file_flag,
|
|
63
|
-
"/tmp/asitop_powermetrics"+timecode,
|
|
64
|
-
"-f plist",
|
|
65
|
-
"-i",
|
|
66
|
-
str(interval)
|
|
67
|
-
])
|
|
68
|
-
process = subprocess.Popen(command.split(" "), stdin=PIPE, stdout=PIPE)
|
|
69
|
-
return process
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def get_ram_metrics_dict():
|
|
73
|
-
ram_metrics = psutil.virtual_memory()
|
|
74
|
-
swap_metrics = psutil.swap_memory()
|
|
75
|
-
total_GB = convert_to_GB(ram_metrics.total)
|
|
76
|
-
free_GB = convert_to_GB(ram_metrics.available)
|
|
77
|
-
used_GB = convert_to_GB(ram_metrics.total-ram_metrics.available)
|
|
78
|
-
swap_total_GB = convert_to_GB(swap_metrics.total)
|
|
79
|
-
swap_used_GB = convert_to_GB(swap_metrics.used)
|
|
80
|
-
swap_free_GB = convert_to_GB(swap_metrics.total-swap_metrics.used)
|
|
81
|
-
if swap_total_GB > 0:
|
|
82
|
-
swap_free_percent = int(100-(swap_free_GB/swap_total_GB*100))
|
|
83
|
-
else:
|
|
84
|
-
swap_free_percent = None
|
|
85
|
-
ram_metrics_dict = {
|
|
86
|
-
"total_GB": round(total_GB, 1),
|
|
87
|
-
"free_GB": round(free_GB, 1),
|
|
88
|
-
"used_GB": round(used_GB, 1),
|
|
89
|
-
"free_percent": int(100-(ram_metrics.available/ram_metrics.total*100)),
|
|
90
|
-
"swap_total_GB": swap_total_GB,
|
|
91
|
-
"swap_used_GB": swap_used_GB,
|
|
92
|
-
"swap_free_GB": swap_free_GB,
|
|
93
|
-
"swap_free_percent": swap_free_percent,
|
|
94
|
-
}
|
|
95
|
-
return ram_metrics_dict
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def get_cpu_info():
|
|
99
|
-
cpu_info = os.popen('sysctl -a | grep machdep.cpu').read()
|
|
100
|
-
cpu_info_lines = cpu_info.split("\n")
|
|
101
|
-
data_fields = ["machdep.cpu.brand_string", "machdep.cpu.core_count"]
|
|
102
|
-
cpu_info_dict = {}
|
|
103
|
-
for l in cpu_info_lines:
|
|
104
|
-
for h in data_fields:
|
|
105
|
-
if h in l:
|
|
106
|
-
value = l.split(":")[1].strip()
|
|
107
|
-
cpu_info_dict[h] = value
|
|
108
|
-
return cpu_info_dict
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def get_core_counts():
|
|
112
|
-
cores_info = os.popen('sysctl -a | grep hw.perflevel').read()
|
|
113
|
-
cores_info_lines = cores_info.split("\n")
|
|
114
|
-
data_fields = ["hw.perflevel0.logicalcpu", "hw.perflevel1.logicalcpu"]
|
|
115
|
-
cores_info_dict = {}
|
|
116
|
-
for l in cores_info_lines:
|
|
117
|
-
for h in data_fields:
|
|
118
|
-
if h in l:
|
|
119
|
-
value = int(l.split(":")[1].strip())
|
|
120
|
-
cores_info_dict[h] = value
|
|
121
|
-
return cores_info_dict
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
def get_gpu_cores():
|
|
125
|
-
try:
|
|
126
|
-
cores = os.popen(
|
|
127
|
-
"system_profiler -detailLevel basic SPDisplaysDataType | grep 'Total Number of Cores'").read()
|
|
128
|
-
cores = int(cores.split(": ")[-1])
|
|
129
|
-
except:
|
|
130
|
-
cores = "?"
|
|
131
|
-
return cores
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def get_soc_info():
|
|
135
|
-
cpu_info_dict = get_cpu_info()
|
|
136
|
-
core_counts_dict = get_core_counts()
|
|
137
|
-
try:
|
|
138
|
-
e_core_count = core_counts_dict["hw.perflevel1.logicalcpu"]
|
|
139
|
-
p_core_count = core_counts_dict["hw.perflevel0.logicalcpu"]
|
|
140
|
-
except:
|
|
141
|
-
e_core_count = "?"
|
|
142
|
-
p_core_count = "?"
|
|
143
|
-
soc_info = {
|
|
144
|
-
"name": cpu_info_dict["machdep.cpu.brand_string"],
|
|
145
|
-
"core_count": int(cpu_info_dict["machdep.cpu.core_count"]),
|
|
146
|
-
"cpu_max_power": None,
|
|
147
|
-
"gpu_max_power": None,
|
|
148
|
-
"cpu_max_bw": None,
|
|
149
|
-
"gpu_max_bw": None,
|
|
150
|
-
"e_core_count": e_core_count,
|
|
151
|
-
"p_core_count": p_core_count,
|
|
152
|
-
"gpu_core_count": get_gpu_cores()
|
|
153
|
-
}
|
|
154
|
-
# TDP (power)
|
|
155
|
-
if soc_info["name"] == "Apple M1 Max":
|
|
156
|
-
soc_info["cpu_max_power"] = 30
|
|
157
|
-
soc_info["gpu_max_power"] = 60
|
|
158
|
-
elif soc_info["name"] == "Apple M1 Pro":
|
|
159
|
-
soc_info["cpu_max_power"] = 30
|
|
160
|
-
soc_info["gpu_max_power"] = 30
|
|
161
|
-
elif soc_info["name"] == "Apple M1":
|
|
162
|
-
soc_info["cpu_max_power"] = 20
|
|
163
|
-
soc_info["gpu_max_power"] = 20
|
|
164
|
-
elif soc_info["name"] == "Apple M1 Ultra":
|
|
165
|
-
soc_info["cpu_max_power"] = 60
|
|
166
|
-
soc_info["gpu_max_power"] = 120
|
|
167
|
-
elif soc_info["name"] == "Apple M2":
|
|
168
|
-
soc_info["cpu_max_power"] = 25
|
|
169
|
-
soc_info["gpu_max_power"] = 15
|
|
170
|
-
else:
|
|
171
|
-
soc_info["cpu_max_power"] = 20
|
|
172
|
-
soc_info["gpu_max_power"] = 20
|
|
173
|
-
# bandwidth
|
|
174
|
-
if soc_info["name"] == "Apple M1 Max":
|
|
175
|
-
soc_info["cpu_max_bw"] = 250
|
|
176
|
-
soc_info["gpu_max_bw"] = 400
|
|
177
|
-
elif soc_info["name"] == "Apple M1 Pro":
|
|
178
|
-
soc_info["cpu_max_bw"] = 200
|
|
179
|
-
soc_info["gpu_max_bw"] = 200
|
|
180
|
-
elif soc_info["name"] == "Apple M1":
|
|
181
|
-
soc_info["cpu_max_bw"] = 70
|
|
182
|
-
soc_info["gpu_max_bw"] = 70
|
|
183
|
-
elif soc_info["name"] == "Apple M1 Ultra":
|
|
184
|
-
soc_info["cpu_max_bw"] = 500
|
|
185
|
-
soc_info["gpu_max_bw"] = 800
|
|
186
|
-
elif soc_info["name"] == "Apple M2":
|
|
187
|
-
soc_info["cpu_max_bw"] = 100
|
|
188
|
-
soc_info["gpu_max_bw"] = 100
|
|
189
|
-
else:
|
|
190
|
-
soc_info["cpu_max_bw"] = 70
|
|
191
|
-
soc_info["gpu_max_bw"] = 70
|
|
192
|
-
return soc_info
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|