New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

macpm

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

macpm - pypi Package Compare versions

Comparing version
0.12
to
0.13
+1
-1
macpm.egg-info/PKG-INFO
Metadata-Version: 2.1
Name: macpm
Version: 0.12
Version: 0.13
Summary: Performance monitoring CLI tool for Apple Silicon

@@ -5,0 +5,0 @@ Home-page: https://github.com/visualcjy/macpm

@@ -6,4 +6,2 @@ LICENSE

macpm/macpm.py
macpm/parsers.py
macpm/utils.py
macpm.egg-info/PKG-INFO

@@ -10,0 +8,0 @@ macpm.egg-info/SOURCES.txt

@@ -1,2 +0,1 @@

import time
import argparse

@@ -6,6 +5,10 @@ import humanize

from dashing import VSplit, HSplit, HGauge, HChart, VGauge, HBrailleChart, HBrailleFilledChart
from .utils import *
import os, time
import subprocess
from subprocess import PIPE
import psutil
import plistlib
parser = argparse.ArgumentParser(
description='macpm: Performance monitoring CLI tool for Apple Silicon')
description='macpm v0.13: Performance monitoring CLI tool for Apple Silicon')
parser.add_argument('--interval', type=int, default=1,

@@ -19,7 +22,311 @@ help='Display interval and sampling interval for powermetrics (seconds)')

help='Choose show cores mode')
parser.add_argument('--max_count', type=int, default=0,
help='Max show count to restart powermetrics')
args = parser.parse_args()
powermetrics_process = None
def clear_console():
command = 'clear'
os.system(command)
def convert_to_GB(value):
return round(value/1024/1024/1024, 1)
def get_ram_metrics_dict():
ram_metrics = psutil.virtual_memory()
swap_metrics = psutil.swap_memory()
total_GB = convert_to_GB(ram_metrics.total)
free_GB = convert_to_GB(ram_metrics.available)
used_GB = convert_to_GB(ram_metrics.total-ram_metrics.available)
swap_total_GB = convert_to_GB(swap_metrics.total)
swap_used_GB = convert_to_GB(swap_metrics.used)
swap_free_GB = convert_to_GB(swap_metrics.total-swap_metrics.used)
if swap_total_GB > 0:
swap_free_percent = int(100-(swap_free_GB/swap_total_GB*100))
else:
swap_free_percent = None
ram_metrics_dict = {
"total_GB": round(total_GB, 1),
"free_GB": round(free_GB, 1),
"used_GB": round(used_GB, 1),
"free_percent": int(100-(ram_metrics.available/ram_metrics.total*100)),
"swap_total_GB": swap_total_GB,
"swap_used_GB": swap_used_GB,
"swap_free_GB": swap_free_GB,
"swap_free_percent": swap_free_percent,
}
return ram_metrics_dict
def get_cpu_info():
cpu_info = os.popen('sysctl -a | grep machdep.cpu').read()
cpu_info_lines = cpu_info.split("\n")
data_fields = ["machdep.cpu.brand_string", "machdep.cpu.core_count"]
cpu_info_dict = {}
for l in cpu_info_lines:
for h in data_fields:
if h in l:
value = l.split(":")[1].strip()
cpu_info_dict[h] = value
return cpu_info_dict
def get_core_counts():
cores_info = os.popen('sysctl -a | grep hw.perflevel').read()
cores_info_lines = cores_info.split("\n")
data_fields = ["hw.perflevel0.logicalcpu", "hw.perflevel1.logicalcpu"]
cores_info_dict = {}
for l in cores_info_lines:
for h in data_fields:
if h in l:
value = int(l.split(":")[1].strip())
cores_info_dict[h] = value
return cores_info_dict
def get_gpu_cores():
try:
cores = os.popen(
"system_profiler -detailLevel basic SPDisplaysDataType | grep 'Total Number of Cores'").read()
cores = int(cores.split(": ")[-1])
except:
cores = "?"
return cores
def get_soc_info():
cpu_info_dict = get_cpu_info()
core_counts_dict = get_core_counts()
try:
e_core_count = core_counts_dict["hw.perflevel1.logicalcpu"]
p_core_count = core_counts_dict["hw.perflevel0.logicalcpu"]
except:
e_core_count = "?"
p_core_count = "?"
soc_info = {
"name": cpu_info_dict["machdep.cpu.brand_string"],
"core_count": int(cpu_info_dict["machdep.cpu.core_count"]),
"cpu_max_power": None,
"gpu_max_power": None,
"cpu_max_bw": None,
"gpu_max_bw": None,
"e_core_count": e_core_count,
"p_core_count": p_core_count,
"gpu_core_count": get_gpu_cores()
}
# TDP (power)
if soc_info["name"] == "Apple M1 Max":
soc_info["cpu_max_power"] = 30
soc_info["gpu_max_power"] = 60
elif soc_info["name"] == "Apple M1 Pro":
soc_info["cpu_max_power"] = 30
soc_info["gpu_max_power"] = 30
elif soc_info["name"] == "Apple M1":
soc_info["cpu_max_power"] = 20
soc_info["gpu_max_power"] = 20
elif soc_info["name"] == "Apple M1 Ultra":
soc_info["cpu_max_power"] = 60
soc_info["gpu_max_power"] = 120
elif soc_info["name"] == "Apple M2":
soc_info["cpu_max_power"] = 25
soc_info["gpu_max_power"] = 15
else:
soc_info["cpu_max_power"] = 20
soc_info["gpu_max_power"] = 20
# bandwidth
if soc_info["name"] == "Apple M1 Max":
soc_info["cpu_max_bw"] = 250
soc_info["gpu_max_bw"] = 400
elif soc_info["name"] == "Apple M1 Pro":
soc_info["cpu_max_bw"] = 200
soc_info["gpu_max_bw"] = 200
elif soc_info["name"] == "Apple M1":
soc_info["cpu_max_bw"] = 70
soc_info["gpu_max_bw"] = 70
elif soc_info["name"] == "Apple M1 Ultra":
soc_info["cpu_max_bw"] = 500
soc_info["gpu_max_bw"] = 800
elif soc_info["name"] == "Apple M2":
soc_info["cpu_max_bw"] = 100
soc_info["gpu_max_bw"] = 100
else:
soc_info["cpu_max_bw"] = 70
soc_info["gpu_max_bw"] = 70
return soc_info
def parse_thermal_pressure(powermetrics_parse):
return powermetrics_parse["thermal_pressure"]
def parse_bandwidth_metrics(powermetrics_parse):
bandwidth_metrics = powermetrics_parse["bandwidth_counters"]
bandwidth_metrics_dict = {}
data_fields = ["PCPU0 DCS RD", "PCPU0 DCS WR",
"PCPU1 DCS RD", "PCPU1 DCS WR",
"PCPU2 DCS RD", "PCPU2 DCS WR",
"PCPU3 DCS RD", "PCPU3 DCS WR",
"PCPU DCS RD", "PCPU DCS WR",
"ECPU0 DCS RD", "ECPU0 DCS WR",
"ECPU1 DCS RD", "ECPU1 DCS WR",
"ECPU DCS RD", "ECPU DCS WR",
"GFX DCS RD", "GFX DCS WR",
"ISP DCS RD", "ISP DCS WR",
"STRM CODEC DCS RD", "STRM CODEC DCS WR",
"PRORES DCS RD", "PRORES DCS WR",
"VDEC DCS RD", "VDEC DCS WR",
"VENC0 DCS RD", "VENC0 DCS WR",
"VENC1 DCS RD", "VENC1 DCS WR",
"VENC2 DCS RD", "VENC2 DCS WR",
"VENC3 DCS RD", "VENC3 DCS WR",
"VENC DCS RD", "VENC DCS WR",
"JPG0 DCS RD", "JPG0 DCS WR",
"JPG1 DCS RD", "JPG1 DCS WR",
"JPG2 DCS RD", "JPG2 DCS WR",
"JPG3 DCS RD", "JPG3 DCS WR",
"JPG DCS RD", "JPG DCS WR",
"DCS RD", "DCS WR"]
for h in data_fields:
bandwidth_metrics_dict[h] = 0
for l in bandwidth_metrics:
if l["name"] in data_fields:
bandwidth_metrics_dict[l["name"]] = l["value"]/(1e9)
bandwidth_metrics_dict["PCPU DCS RD"] = bandwidth_metrics_dict["PCPU DCS RD"] + \
bandwidth_metrics_dict["PCPU0 DCS RD"] + \
bandwidth_metrics_dict["PCPU1 DCS RD"] + \
bandwidth_metrics_dict["PCPU2 DCS RD"] + \
bandwidth_metrics_dict["PCPU3 DCS RD"]
bandwidth_metrics_dict["PCPU DCS WR"] = bandwidth_metrics_dict["PCPU DCS WR"] + \
bandwidth_metrics_dict["PCPU0 DCS WR"] + \
bandwidth_metrics_dict["PCPU1 DCS WR"] + \
bandwidth_metrics_dict["PCPU2 DCS WR"] + \
bandwidth_metrics_dict["PCPU3 DCS WR"]
bandwidth_metrics_dict["JPG DCS RD"] = bandwidth_metrics_dict["JPG DCS RD"] + \
bandwidth_metrics_dict["JPG0 DCS RD"] + \
bandwidth_metrics_dict["JPG1 DCS RD"] + \
bandwidth_metrics_dict["JPG2 DCS RD"] + \
bandwidth_metrics_dict["JPG3 DCS RD"]
bandwidth_metrics_dict["JPG DCS WR"] = bandwidth_metrics_dict["JPG DCS WR"] + \
bandwidth_metrics_dict["JPG0 DCS WR"] + \
bandwidth_metrics_dict["JPG1 DCS WR"] + \
bandwidth_metrics_dict["JPG2 DCS WR"] + \
bandwidth_metrics_dict["JPG3 DCS WR"]
bandwidth_metrics_dict["VENC DCS RD"] = bandwidth_metrics_dict["VENC DCS RD"] + \
bandwidth_metrics_dict["VENC0 DCS RD"] + \
bandwidth_metrics_dict["VENC1 DCS RD"] + \
bandwidth_metrics_dict["VENC2 DCS RD"] + \
bandwidth_metrics_dict["VENC3 DCS RD"]
bandwidth_metrics_dict["VENC DCS WR"] = bandwidth_metrics_dict["VENC DCS WR"] + \
bandwidth_metrics_dict["VENC0 DCS WR"] + \
bandwidth_metrics_dict["VENC1 DCS WR"] + \
bandwidth_metrics_dict["VENC2 DCS WR"] + \
bandwidth_metrics_dict["VENC3 DCS WR"]
bandwidth_metrics_dict["MEDIA DCS"] = sum([
bandwidth_metrics_dict["ISP DCS RD"], bandwidth_metrics_dict["ISP DCS WR"],
bandwidth_metrics_dict["STRM CODEC DCS RD"], bandwidth_metrics_dict["STRM CODEC DCS WR"],
bandwidth_metrics_dict["PRORES DCS RD"], bandwidth_metrics_dict["PRORES DCS WR"],
bandwidth_metrics_dict["VDEC DCS RD"], bandwidth_metrics_dict["VDEC DCS WR"],
bandwidth_metrics_dict["VENC DCS RD"], bandwidth_metrics_dict["VENC DCS WR"],
bandwidth_metrics_dict["JPG DCS RD"], bandwidth_metrics_dict["JPG DCS WR"],
])
return bandwidth_metrics_dict
def parse_cpu_metrics(powermetrics_parse):
e_core = []
p_core = []
cpu_metrics = powermetrics_parse["processor"]
cpu_metric_dict = {}
# cpu_clusters
cpu_clusters = cpu_metrics["clusters"]
e_total_idle_ratio = 0
e_core_count = 0
p_total_idle_ratio = 0
p_core_count = 0
for cluster in cpu_clusters:
name = cluster["name"]
cpu_metric_dict[name+"_freq_Mhz"] = int(cluster["freq_hz"]/(1e6))
cpu_metric_dict[name+"_active"] = int((1 - cluster["idle_ratio"])*100)
for cpu in cluster["cpus"]:
name = 'E-Cluster' if name[0] == 'E' else 'P-Cluster'
core = e_core if name[0] == 'E' else p_core
core.append(cpu["cpu"])
cpu_metric_dict[name + str(cpu["cpu"]) + "_freq_Mhz"] = int(cpu["freq_hz"] / (1e6))
cpu_metric_dict[name + str(cpu["cpu"]) + "_active"] = int((1 - cpu["idle_ratio"]) * 100)
if name[0] == 'E':
e_total_idle_ratio += cluster["down_ratio"] + (1 - cluster["down_ratio"]) * (cpu["idle_ratio"] + cpu["down_ratio"])
e_core_count += 1
else:
p_total_idle_ratio += cluster["down_ratio"] + (1 - cluster["down_ratio"]) * (cpu["idle_ratio"] + cpu["down_ratio"])
p_core_count += 1
cpu_metric_dict["E-Cluster_active"] = int((1 - e_total_idle_ratio/e_core_count)*100)
cpu_metric_dict["P-Cluster_active"] = int((1 - p_total_idle_ratio/p_core_count)*100)
cpu_metric_dict["e_core"] = e_core
cpu_metric_dict["p_core"] = p_core
if "E-Cluster_active" not in cpu_metric_dict:
# M1 Ultra
cpu_metric_dict["E-Cluster_active"] = int(
(cpu_metric_dict["E0-Cluster_active"] + cpu_metric_dict["E1-Cluster_active"])/2)
if "E-Cluster_freq_Mhz" not in cpu_metric_dict:
# M1 Ultra
cpu_metric_dict["E-Cluster_freq_Mhz"] = max(
cpu_metric_dict["E0-Cluster_freq_Mhz"], cpu_metric_dict["E1-Cluster_freq_Mhz"])
if "P-Cluster_active" not in cpu_metric_dict:
if "P2-Cluster_active" in cpu_metric_dict:
# M1 Ultra
cpu_metric_dict["P-Cluster_active"] = int((cpu_metric_dict["P0-Cluster_active"] + cpu_metric_dict["P1-Cluster_active"] +
cpu_metric_dict["P2-Cluster_active"] + cpu_metric_dict["P3-Cluster_active"]) / 4)
else:
cpu_metric_dict["P-Cluster_active"] = int(
(cpu_metric_dict["P0-Cluster_active"] + cpu_metric_dict["P1-Cluster_active"])/2)
if "P-Cluster_freq_Mhz" not in cpu_metric_dict:
if "P2-Cluster_freq_Mhz" in cpu_metric_dict:
# M1 Ultra
freqs = [
cpu_metric_dict["P0-Cluster_freq_Mhz"],
cpu_metric_dict["P1-Cluster_freq_Mhz"],
cpu_metric_dict["P2-Cluster_freq_Mhz"],
cpu_metric_dict["P3-Cluster_freq_Mhz"]]
cpu_metric_dict["P-Cluster_freq_Mhz"] = max(freqs)
else:
cpu_metric_dict["P-Cluster_freq_Mhz"] = max(
cpu_metric_dict["P0-Cluster_freq_Mhz"], cpu_metric_dict["P1-Cluster_freq_Mhz"])
# power
cpu_metric_dict["ane_W"] = cpu_metrics["ane_energy"]/1000
#cpu_metric_dict["dram_W"] = cpu_metrics["dram_energy"]/1000
cpu_metric_dict["cpu_W"] = cpu_metrics["cpu_energy"]/1000
cpu_metric_dict["gpu_W"] = cpu_metrics["gpu_energy"]/1000
cpu_metric_dict["package_W"] = cpu_metrics["combined_power"]/1000
return cpu_metric_dict
def parse_gpu_metrics(powermetrics_parse):
gpu_metrics = powermetrics_parse["gpu"]
gpu_metrics_dict = {
"freq_MHz": int(gpu_metrics["freq_hz"]),
"active": int((1 - gpu_metrics["idle_ratio"])*100),
}
return gpu_metrics_dict
def parse_disk_metrics(powermetrics_parse):
disk_metrics = powermetrics_parse["disk"]
disk_metrics_dict = {
"read_iops": int(disk_metrics["rops_per_s"]),
"write_iops": int(disk_metrics["wops_per_s"]),
"read_Bps": int(disk_metrics["rbytes_per_s"]),
"write_Bps": int(disk_metrics["wbytes_per_s"]),
}
return disk_metrics_dict
def parse_network_metrics(powermetrics_parse):
network_metrics = powermetrics_parse["network"]
network_metrics_dict = {
"out_Bps": int(network_metrics["obyte_rate"]),
"in_Bps": int(network_metrics["ibyte_rate"]),
}
return network_metrics_dict
def main():

@@ -32,3 +339,3 @@ print("\nmacpm - Performance monitoring CLI tool for Apple Silicon")

print("\033[?25l")
global powermetrics_process
cpu1_gauge = HGauge(title="E-CPU Usage", val=0, color=args.color)

@@ -164,3 +471,3 @@ cpu2_gauge = HGauge(title="P-CPU Usage", val=0, color=args.color)

gpu_max_power = soc_info_dict["gpu_max_power"]
ane_max_power = 8.0
ane_max_power = 16.0
"""max_cpu_bw = soc_info_dict["cpu_max_bw"]

@@ -184,7 +491,20 @@ max_gpu_bw = soc_info_dict["gpu_max_bw"]

powermetrics_process = run_powermetrics_process(timecode,
interval=args.interval * 1000)
#powermetrics_process = run_powermetrics_process(timecode,
# interval=args.interval * 1000)
command = " ".join([
"sudo nice -n",
str(10),
"powermetrics",
"--samplers cpu_power,gpu_power,thermal,network,disk",
"-f plist",
"-i",
str(args.interval * 1000)
])
process = subprocess.Popen(command.split(" "), stdin=PIPE, stdout=PIPE)
powermetrics_process = process
print("\n[3/3] Waiting for first reading...\n")
"""
def get_reading(wait=0.1):

@@ -199,3 +519,3 @@ ready = parse_powermetrics(timecode=timecode)

last_timestamp = ready[-1]
"""
def get_avg(inlist):

@@ -211,20 +531,24 @@ avg = sum(inlist) / len(inlist)

count=0
try:
data = b''
while True:
if args.max_count > 0:
if count >= args.max_count:
count = 0
powermetrics_process.terminate()
timecode = str(int(time.time()))
powermetrics_process = run_powermetrics_process(
timecode, interval=args.interval * 1000)
count += 1
ready = parse_powermetrics(timecode=timecode)
if ready:
cpu_metrics_dict, gpu_metrics_dict, thermal_pressure, bandwidth_metrics, disk_metrics_dict, network_metrics_dict, timestamp = ready
if timestamp > last_timestamp:
last_timestamp = timestamp
output = process.stdout.readline()
#output, stderr = process.communicate()
if process.poll() is not None:
break
data = data + output
str_output = output.decode()
if str_output.startswith('</plist>'):
data = data.replace(b'\x00',b'')
powermetrics_parse = plistlib.loads(data)
thermal_pressure = parse_thermal_pressure(powermetrics_parse)
cpu_metrics_dict = parse_cpu_metrics(powermetrics_parse)
gpu_metrics_dict = parse_gpu_metrics(powermetrics_parse)
disk_metrics_dict = parse_disk_metrics(powermetrics_parse)
network_metrics_dict = parse_network_metrics(powermetrics_parse)
#bandwidth_metrics = parse_bandwidth_metrics(powermetrics_parse)
bandwidth_metrics = None
timestamp = powermetrics_parse["timestamp"]
data = b''
if timestamp :
if thermal_pressure == "Nominal":

@@ -295,4 +619,7 @@ thermal_throttle = "no"

ane_power_W = cpu_metrics_dict["ane_W"] / args.interval
if ane_power_W > ane_max_power:
ane_max_power = ane_power_W
ane_util_percent = int(
cpu_metrics_dict["ane_W"] / args.interval / ane_max_power * 100)
ane_power_W / ane_max_power * 100)
ane_gauge.title = "".join([

@@ -302,4 +629,3 @@ "ANE Usage: ",

"% @ ",
'{0:.1f}'.format(
cpu_metrics_dict["ane_W"] / args.interval),
'{0:.1f}'.format(ane_power_W),
" W"

@@ -420,7 +746,9 @@ ])

cpu_power_percent = int(
cpu_metrics_dict["cpu_W"] / args.interval / cpu_max_power * 100)
cpu_power_W = cpu_metrics_dict["cpu_W"] / args.interval
if cpu_power_W > cpu_peak_power:
cpu_peak_power = cpu_power_W
if cpu_power_W > cpu_max_power:
cpu_max_power = cpu_power_W
cpu_power_percent = int(
cpu_power_W / cpu_max_power * 100)
avg_cpu_power_list.append(cpu_power_W)

@@ -439,7 +767,9 @@ avg_cpu_power = get_avg(avg_cpu_power_list)

gpu_power_percent = int(
cpu_metrics_dict["gpu_W"] / args.interval / gpu_max_power * 100)
gpu_power_W = cpu_metrics_dict["gpu_W"] / args.interval
if gpu_power_W > gpu_peak_power:
gpu_peak_power = gpu_power_W
if gpu_power_W > gpu_max_power:
gpu_max_power = gpu_power_W
gpu_power_percent = int(
gpu_power_W / gpu_max_power * 100)
avg_gpu_power_list.append(gpu_power_W)

@@ -466,3 +796,3 @@ avg_gpu_power = get_avg(avg_gpu_power_list)

if disk_read_iops_charts.datapoints:
disk_read_iops_rate = int(disk_read_iops / disk_read_iops_peak * 100)
disk_read_iops_rate = int(disk_read_iops / disk_read_iops_peak * 100) if disk_read_iops_peak > 0 else 0
else:

@@ -477,3 +807,3 @@ disk_read_iops_rate = 100

if disk_write_iops_charts.datapoints:
disk_write_iops_rate = int(disk_read_iops / disk_write_iops_peak * 100)
disk_write_iops_rate = int(disk_read_iops / disk_write_iops_peak * 100) if disk_write_iops_peak > 0 else 0
else:

@@ -488,3 +818,3 @@ disk_write_iops_rate = 100

if disk_read_bps_charts.datapoints:
disk_read_bps_rate = int(disk_read_bps / disk_read_bps_peak * 100)
disk_read_bps_rate = int(disk_read_bps / disk_read_bps_peak * 100) if disk_read_bps_peak > 0 else 0
else:

@@ -499,3 +829,3 @@ disk_read_bps_rate = 100

if disk_write_bps_charts.datapoints:
disk_write_bps_rate = int(disk_write_bps / disk_write_bps_peak * 100)
disk_write_bps_rate = int(disk_write_bps / disk_write_bps_peak * 100) if disk_write_bps_peak > 0 else 0
else:

@@ -510,3 +840,3 @@ disk_write_bps_rate = 100

if network_in_bps_charts.datapoints:
network_in_bps_rate = int(network_in_bps / network_in_bps_peak * 100)
network_in_bps_rate = int(network_in_bps / network_in_bps_peak * 100) if network_in_bps_peak > 0 else 0
else:

@@ -521,3 +851,3 @@ network_in_bps_rate = 100

if network_out_bps_charts.datapoints:
network_out_bps_rate = int(network_out_bps / network_out_bps_peak * 100)
network_out_bps_rate = int(network_out_bps / network_out_bps_peak * 100) if network_out_bps_peak > 0 else 0
else:

@@ -529,3 +859,4 @@ network_out_bps_rate = 100

time.sleep(args.interval)
if str_output == '':
time.sleep(0.1)

@@ -536,7 +867,7 @@ except KeyboardInterrupt:

return powermetrics_process
return
if __name__ == "__main__":
powermetrics_process = main()
main()
try:

@@ -549,1 +880,2 @@ powermetrics_process.terminate()

print("Successfully terminated powermetrics process")
Metadata-Version: 2.1
Name: macpm
Version: 0.12
Version: 0.13
Summary: Performance monitoring CLI tool for Apple Silicon

@@ -5,0 +5,0 @@ Home-page: https://github.com/visualcjy/macpm

# macpm
![PyPI - Downloads](https://pypi.org/project/macpm/#files)
PyPI - Downloads (https://pypi.org/project/macpm/#files)
or: pip install macpm

@@ -18,2 +19,4 @@ Performance monitoring CLI tool for Apple Silicon

2. add "Disk IO" and "Network IO" info
3. adjust the hard coded max power in CPU/GPU/ANE
4. change the way to call powermetrics, no temp files in /tmp

@@ -20,0 +23,0 @@ A Python-based `nvtop`-inspired command line tool for Apple Silicon (aka M1) Macs.

@@ -7,3 +7,3 @@ from setuptools import setup, find_packages

name='macpm',
version='0.12',
version='0.13',
author='Jinyu Chen',

@@ -17,3 +17,2 @@ author_email='visualcjy@mail.com',

packages=find_packages(),
package_dir={'macpm':'macpm'},
entry_points={

@@ -20,0 +19,0 @@ 'console_scripts': [

def parse_thermal_pressure(powermetrics_parse):
return powermetrics_parse["thermal_pressure"]
def parse_bandwidth_metrics(powermetrics_parse):
bandwidth_metrics = powermetrics_parse["bandwidth_counters"]
bandwidth_metrics_dict = {}
data_fields = ["PCPU0 DCS RD", "PCPU0 DCS WR",
"PCPU1 DCS RD", "PCPU1 DCS WR",
"PCPU2 DCS RD", "PCPU2 DCS WR",
"PCPU3 DCS RD", "PCPU3 DCS WR",
"PCPU DCS RD", "PCPU DCS WR",
"ECPU0 DCS RD", "ECPU0 DCS WR",
"ECPU1 DCS RD", "ECPU1 DCS WR",
"ECPU DCS RD", "ECPU DCS WR",
"GFX DCS RD", "GFX DCS WR",
"ISP DCS RD", "ISP DCS WR",
"STRM CODEC DCS RD", "STRM CODEC DCS WR",
"PRORES DCS RD", "PRORES DCS WR",
"VDEC DCS RD", "VDEC DCS WR",
"VENC0 DCS RD", "VENC0 DCS WR",
"VENC1 DCS RD", "VENC1 DCS WR",
"VENC2 DCS RD", "VENC2 DCS WR",
"VENC3 DCS RD", "VENC3 DCS WR",
"VENC DCS RD", "VENC DCS WR",
"JPG0 DCS RD", "JPG0 DCS WR",
"JPG1 DCS RD", "JPG1 DCS WR",
"JPG2 DCS RD", "JPG2 DCS WR",
"JPG3 DCS RD", "JPG3 DCS WR",
"JPG DCS RD", "JPG DCS WR",
"DCS RD", "DCS WR"]
for h in data_fields:
bandwidth_metrics_dict[h] = 0
for l in bandwidth_metrics:
if l["name"] in data_fields:
bandwidth_metrics_dict[l["name"]] = l["value"]/(1e9)
bandwidth_metrics_dict["PCPU DCS RD"] = bandwidth_metrics_dict["PCPU DCS RD"] + \
bandwidth_metrics_dict["PCPU0 DCS RD"] + \
bandwidth_metrics_dict["PCPU1 DCS RD"] + \
bandwidth_metrics_dict["PCPU2 DCS RD"] + \
bandwidth_metrics_dict["PCPU3 DCS RD"]
bandwidth_metrics_dict["PCPU DCS WR"] = bandwidth_metrics_dict["PCPU DCS WR"] + \
bandwidth_metrics_dict["PCPU0 DCS WR"] + \
bandwidth_metrics_dict["PCPU1 DCS WR"] + \
bandwidth_metrics_dict["PCPU2 DCS WR"] + \
bandwidth_metrics_dict["PCPU3 DCS WR"]
bandwidth_metrics_dict["JPG DCS RD"] = bandwidth_metrics_dict["JPG DCS RD"] + \
bandwidth_metrics_dict["JPG0 DCS RD"] + \
bandwidth_metrics_dict["JPG1 DCS RD"] + \
bandwidth_metrics_dict["JPG2 DCS RD"] + \
bandwidth_metrics_dict["JPG3 DCS RD"]
bandwidth_metrics_dict["JPG DCS WR"] = bandwidth_metrics_dict["JPG DCS WR"] + \
bandwidth_metrics_dict["JPG0 DCS WR"] + \
bandwidth_metrics_dict["JPG1 DCS WR"] + \
bandwidth_metrics_dict["JPG2 DCS WR"] + \
bandwidth_metrics_dict["JPG3 DCS WR"]
bandwidth_metrics_dict["VENC DCS RD"] = bandwidth_metrics_dict["VENC DCS RD"] + \
bandwidth_metrics_dict["VENC0 DCS RD"] + \
bandwidth_metrics_dict["VENC1 DCS RD"] + \
bandwidth_metrics_dict["VENC2 DCS RD"] + \
bandwidth_metrics_dict["VENC3 DCS RD"]
bandwidth_metrics_dict["VENC DCS WR"] = bandwidth_metrics_dict["VENC DCS WR"] + \
bandwidth_metrics_dict["VENC0 DCS WR"] + \
bandwidth_metrics_dict["VENC1 DCS WR"] + \
bandwidth_metrics_dict["VENC2 DCS WR"] + \
bandwidth_metrics_dict["VENC3 DCS WR"]
bandwidth_metrics_dict["MEDIA DCS"] = sum([
bandwidth_metrics_dict["ISP DCS RD"], bandwidth_metrics_dict["ISP DCS WR"],
bandwidth_metrics_dict["STRM CODEC DCS RD"], bandwidth_metrics_dict["STRM CODEC DCS WR"],
bandwidth_metrics_dict["PRORES DCS RD"], bandwidth_metrics_dict["PRORES DCS WR"],
bandwidth_metrics_dict["VDEC DCS RD"], bandwidth_metrics_dict["VDEC DCS WR"],
bandwidth_metrics_dict["VENC DCS RD"], bandwidth_metrics_dict["VENC DCS WR"],
bandwidth_metrics_dict["JPG DCS RD"], bandwidth_metrics_dict["JPG DCS WR"],
])
return bandwidth_metrics_dict
def parse_cpu_metrics(powermetrics_parse):
e_core = []
p_core = []
cpu_metrics = powermetrics_parse["processor"]
cpu_metric_dict = {}
# cpu_clusters
cpu_clusters = cpu_metrics["clusters"]
e_total_idle_ratio = 0
e_core_count = 0
p_total_idle_ratio = 0
p_core_count = 0
for cluster in cpu_clusters:
name = cluster["name"]
cpu_metric_dict[name+"_freq_Mhz"] = int(cluster["freq_hz"]/(1e6))
cpu_metric_dict[name+"_active"] = int((1 - cluster["idle_ratio"])*100)
for cpu in cluster["cpus"]:
name = 'E-Cluster' if name[0] == 'E' else 'P-Cluster'
core = e_core if name[0] == 'E' else p_core
core.append(cpu["cpu"])
cpu_metric_dict[name + str(cpu["cpu"]) + "_freq_Mhz"] = int(cpu["freq_hz"] / (1e6))
cpu_metric_dict[name + str(cpu["cpu"]) + "_active"] = int((1 - cpu["idle_ratio"]) * 100)
if name[0] == 'E':
e_total_idle_ratio += cluster["down_ratio"] + (1 - cluster["down_ratio"]) * (cpu["idle_ratio"] + cpu["down_ratio"])
e_core_count += 1
else:
p_total_idle_ratio += cluster["down_ratio"] + (1 - cluster["down_ratio"]) * (cpu["idle_ratio"] + cpu["down_ratio"])
p_core_count += 1
cpu_metric_dict["E-Cluster_active"] = int((1 - e_total_idle_ratio/e_core_count)*100)
cpu_metric_dict["P-Cluster_active"] = int((1 - p_total_idle_ratio/p_core_count)*100)
cpu_metric_dict["e_core"] = e_core
cpu_metric_dict["p_core"] = p_core
if "E-Cluster_active" not in cpu_metric_dict:
# M1 Ultra
cpu_metric_dict["E-Cluster_active"] = int(
(cpu_metric_dict["E0-Cluster_active"] + cpu_metric_dict["E1-Cluster_active"])/2)
if "E-Cluster_freq_Mhz" not in cpu_metric_dict:
# M1 Ultra
cpu_metric_dict["E-Cluster_freq_Mhz"] = max(
cpu_metric_dict["E0-Cluster_freq_Mhz"], cpu_metric_dict["E1-Cluster_freq_Mhz"])
if "P-Cluster_active" not in cpu_metric_dict:
if "P2-Cluster_active" in cpu_metric_dict:
# M1 Ultra
cpu_metric_dict["P-Cluster_active"] = int((cpu_metric_dict["P0-Cluster_active"] + cpu_metric_dict["P1-Cluster_active"] +
cpu_metric_dict["P2-Cluster_active"] + cpu_metric_dict["P3-Cluster_active"]) / 4)
else:
cpu_metric_dict["P-Cluster_active"] = int(
(cpu_metric_dict["P0-Cluster_active"] + cpu_metric_dict["P1-Cluster_active"])/2)
if "P-Cluster_freq_Mhz" not in cpu_metric_dict:
if "P2-Cluster_freq_Mhz" in cpu_metric_dict:
# M1 Ultra
freqs = [
cpu_metric_dict["P0-Cluster_freq_Mhz"],
cpu_metric_dict["P1-Cluster_freq_Mhz"],
cpu_metric_dict["P2-Cluster_freq_Mhz"],
cpu_metric_dict["P3-Cluster_freq_Mhz"]]
cpu_metric_dict["P-Cluster_freq_Mhz"] = max(freqs)
else:
cpu_metric_dict["P-Cluster_freq_Mhz"] = max(
cpu_metric_dict["P0-Cluster_freq_Mhz"], cpu_metric_dict["P1-Cluster_freq_Mhz"])
# power
cpu_metric_dict["ane_W"] = cpu_metrics["ane_energy"]/1000
#cpu_metric_dict["dram_W"] = cpu_metrics["dram_energy"]/1000
cpu_metric_dict["cpu_W"] = cpu_metrics["cpu_energy"]/1000
cpu_metric_dict["gpu_W"] = cpu_metrics["gpu_energy"]/1000
cpu_metric_dict["package_W"] = cpu_metrics["combined_power"]/1000
return cpu_metric_dict
def parse_gpu_metrics(powermetrics_parse):
gpu_metrics = powermetrics_parse["gpu"]
gpu_metrics_dict = {
"freq_MHz": int(gpu_metrics["freq_hz"]),
"active": int((1 - gpu_metrics["idle_ratio"])*100),
}
return gpu_metrics_dict
def parse_disk_metrics(powermetrics_parse):
disk_metrics = powermetrics_parse["disk"]
disk_metrics_dict = {
"read_iops": int(disk_metrics["rops_per_s"]),
"write_iops": int(disk_metrics["wops_per_s"]),
"read_Bps": int(disk_metrics["rbytes_per_s"]),
"write_Bps": int(disk_metrics["wbytes_per_s"]),
}
return disk_metrics_dict
def parse_network_metrics(powermetrics_parse):
network_metrics = powermetrics_parse["network"]
network_metrics_dict = {
"out_Bps": int(network_metrics["obyte_rate"]),
"in_Bps": int(network_metrics["ibyte_rate"]),
}
return network_metrics_dict
import os
import glob
import subprocess
from subprocess import PIPE
import psutil
from .parsers import *
import plistlib
def parse_powermetrics(path='/tmp/asitop_powermetrics', timecode="0"):
data = None
try:
with open(path+timecode, 'rb') as fp:
data = fp.read()
data = data.split(b'\x00')
powermetrics_parse = plistlib.loads(data[-1])
thermal_pressure = parse_thermal_pressure(powermetrics_parse)
cpu_metrics_dict = parse_cpu_metrics(powermetrics_parse)
gpu_metrics_dict = parse_gpu_metrics(powermetrics_parse)
disk_metrics_dict = parse_disk_metrics(powermetrics_parse)
network_metrics_dict = parse_network_metrics(powermetrics_parse)
#bandwidth_metrics = parse_bandwidth_metrics(powermetrics_parse)
bandwidth_metrics = None
timestamp = powermetrics_parse["timestamp"]
return cpu_metrics_dict, gpu_metrics_dict, thermal_pressure, bandwidth_metrics, disk_metrics_dict, network_metrics_dict, timestamp
except Exception as e:
if data:
if len(data) > 1:
powermetrics_parse = plistlib.loads(data[-2])
thermal_pressure = parse_thermal_pressure(powermetrics_parse)
cpu_metrics_dict = parse_cpu_metrics(powermetrics_parse)
gpu_metrics_dict = parse_gpu_metrics(powermetrics_parse)
disk_metrics_dict = parse_disk_metrics(powermetrics_parse)
network_metrics_dict = parse_network_metrics(powermetrics_parse)
#bandwidth_metrics = parse_bandwidth_metrics(powermetrics_parse)
bandwidth_metrics = None
timestamp = powermetrics_parse["timestamp"]
return cpu_metrics_dict, gpu_metrics_dict, thermal_pressure, bandwidth_metrics, disk_metrics_dict, network_metrics_dict, timestamp
return False
def clear_console():
command = 'clear'
os.system(command)
def convert_to_GB(value):
return round(value/1024/1024/1024, 1)
def run_powermetrics_process(timecode, nice=10, interval=1000):
#ver, *_ = platform.mac_ver()
#major_ver = int(ver.split(".")[0])
#for tmpf in glob.glob("/tmp/asitop_powermetrics*"):
# os.remove(tmpf)
output_file_flag = "-o"
command = " ".join([
"sudo nice -n",
str(nice),
"powermetrics",
"--samplers cpu_power,gpu_power,thermal,network,disk",
output_file_flag,
"/tmp/asitop_powermetrics"+timecode,
"-f plist",
"-i",
str(interval)
])
process = subprocess.Popen(command.split(" "), stdin=PIPE, stdout=PIPE)
return process
def get_ram_metrics_dict():
ram_metrics = psutil.virtual_memory()
swap_metrics = psutil.swap_memory()
total_GB = convert_to_GB(ram_metrics.total)
free_GB = convert_to_GB(ram_metrics.available)
used_GB = convert_to_GB(ram_metrics.total-ram_metrics.available)
swap_total_GB = convert_to_GB(swap_metrics.total)
swap_used_GB = convert_to_GB(swap_metrics.used)
swap_free_GB = convert_to_GB(swap_metrics.total-swap_metrics.used)
if swap_total_GB > 0:
swap_free_percent = int(100-(swap_free_GB/swap_total_GB*100))
else:
swap_free_percent = None
ram_metrics_dict = {
"total_GB": round(total_GB, 1),
"free_GB": round(free_GB, 1),
"used_GB": round(used_GB, 1),
"free_percent": int(100-(ram_metrics.available/ram_metrics.total*100)),
"swap_total_GB": swap_total_GB,
"swap_used_GB": swap_used_GB,
"swap_free_GB": swap_free_GB,
"swap_free_percent": swap_free_percent,
}
return ram_metrics_dict
def get_cpu_info():
cpu_info = os.popen('sysctl -a | grep machdep.cpu').read()
cpu_info_lines = cpu_info.split("\n")
data_fields = ["machdep.cpu.brand_string", "machdep.cpu.core_count"]
cpu_info_dict = {}
for l in cpu_info_lines:
for h in data_fields:
if h in l:
value = l.split(":")[1].strip()
cpu_info_dict[h] = value
return cpu_info_dict
def get_core_counts():
cores_info = os.popen('sysctl -a | grep hw.perflevel').read()
cores_info_lines = cores_info.split("\n")
data_fields = ["hw.perflevel0.logicalcpu", "hw.perflevel1.logicalcpu"]
cores_info_dict = {}
for l in cores_info_lines:
for h in data_fields:
if h in l:
value = int(l.split(":")[1].strip())
cores_info_dict[h] = value
return cores_info_dict
def get_gpu_cores():
try:
cores = os.popen(
"system_profiler -detailLevel basic SPDisplaysDataType | grep 'Total Number of Cores'").read()
cores = int(cores.split(": ")[-1])
except:
cores = "?"
return cores
def get_soc_info():
cpu_info_dict = get_cpu_info()
core_counts_dict = get_core_counts()
try:
e_core_count = core_counts_dict["hw.perflevel1.logicalcpu"]
p_core_count = core_counts_dict["hw.perflevel0.logicalcpu"]
except:
e_core_count = "?"
p_core_count = "?"
soc_info = {
"name": cpu_info_dict["machdep.cpu.brand_string"],
"core_count": int(cpu_info_dict["machdep.cpu.core_count"]),
"cpu_max_power": None,
"gpu_max_power": None,
"cpu_max_bw": None,
"gpu_max_bw": None,
"e_core_count": e_core_count,
"p_core_count": p_core_count,
"gpu_core_count": get_gpu_cores()
}
# TDP (power)
if soc_info["name"] == "Apple M1 Max":
soc_info["cpu_max_power"] = 30
soc_info["gpu_max_power"] = 60
elif soc_info["name"] == "Apple M1 Pro":
soc_info["cpu_max_power"] = 30
soc_info["gpu_max_power"] = 30
elif soc_info["name"] == "Apple M1":
soc_info["cpu_max_power"] = 20
soc_info["gpu_max_power"] = 20
elif soc_info["name"] == "Apple M1 Ultra":
soc_info["cpu_max_power"] = 60
soc_info["gpu_max_power"] = 120
elif soc_info["name"] == "Apple M2":
soc_info["cpu_max_power"] = 25
soc_info["gpu_max_power"] = 15
else:
soc_info["cpu_max_power"] = 20
soc_info["gpu_max_power"] = 20
# bandwidth
if soc_info["name"] == "Apple M1 Max":
soc_info["cpu_max_bw"] = 250
soc_info["gpu_max_bw"] = 400
elif soc_info["name"] == "Apple M1 Pro":
soc_info["cpu_max_bw"] = 200
soc_info["gpu_max_bw"] = 200
elif soc_info["name"] == "Apple M1":
soc_info["cpu_max_bw"] = 70
soc_info["gpu_max_bw"] = 70
elif soc_info["name"] == "Apple M1 Ultra":
soc_info["cpu_max_bw"] = 500
soc_info["gpu_max_bw"] = 800
elif soc_info["name"] == "Apple M2":
soc_info["cpu_max_bw"] = 100
soc_info["gpu_max_bw"] = 100
else:
soc_info["cpu_max_bw"] = 70
soc_info["gpu_max_bw"] = 70
return soc_info