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