本篇笔记重点记录如何在各类硬件平台上获得CPU、内存、GPU等动态数据,以验证各类算法的性能表现。之前零零散散介绍过一些,但是不太全面,本篇笔记加以扩展、梳理。
1.PC平台
主要包含如笔记本、台式机、服务器等电脑,运行Windows或Linux(Ubuntu)系统。核心是基于Python的platform库获取平台相关基础信息、基于psutil库实现对CPU和内存信息的获取、基于Nvidia提供的nvidia-smi
命令获取GPU相关信息。platform库为Python自带无需额外安装,psutil使用pip install psutil
命令安装,nvidia-smi
则是安装CUDA后自动安装。关于psutil库的详细使用可参考官方文档。安装CUDA则可参考之前这篇笔记。
1.1 平台基础信息获取
核心利用Python的platform库,可以获取包括系统类型、架构、名称、版本、CPU型号等一系列信息。代码如下。
import platform
fout = open("info_platform.txt", "w")
# 返回平台架构
arch = platform.architecture()
arch_str = "architecture:"+str(arch)+"\n"
fout.write(arch_str)
print(arch_str)
# 返回平台CPU型号
cpu = platform.processor()
cpu_str = "cpu:"+cpu+"\n"
fout.write(cpu_str)
print(cpu_str)
# 返回平台型号
mcn = platform.machine()
mcn_str = "machine:"+mcn+"\n"
fout.write(mcn_str)
print(mcn_str)
# 返回平台系统名称
plm = platform.platform()
plm_str = "platform:"+plm+"\n"
fout.write(plm_str)
print(plm_str)
# 返回平台系统类型
sys = platform.system()
sys_str = "system:"+sys+"\n"
fout.write(sys_str)
print(sys_str)
# 返回系统精确版本
ver = platform.version()
ver_str = "version:"+ver+"\n"
fout.write(ver_str)
print(ver_str)
# 返回平台网络名称
node = platform.node()
node_str = "node:"+node+"\n"
fout.write(node_str)
print(node_str)
# 返回系统详细信息
uname = platform.uname()
uname_str = "uname:"+str(uname)+"\n"
fout.write(uname_str)
print(uname_str)
fout.close()
代码上传到了Github,点击查看。如下是在Windows电脑上运行脚本的效果。
1.2 CPU静态信息获取
当然你可以直接通过查看属性的方式查看相关内容。或者利用psutil库获取,如下。
import platform
import psutil
# 返回平台CPU型号
cpu = platform.processor()
cpu_str = "cpu:"+cpu
print(cpu_str)
# 返回平台CPU逻辑和物理核心数
core_num_logical = psutil.cpu_count()
core_num_physical = psutil.cpu_count(logical=False)
print("logical core:", core_num_logical)
print("physical core:", core_num_physical)
代码上传到了Github,点击查看。这样就能获取到CPU基本的信息,如下。
1.3 CPU动态信息监控
对于CPU的动态监控,我们重点是关注CPU的使用率。还是利用psutil库实现,代码如下。
import platform
import psutil
import time
import numpy as np
# 返回平台CPU型号
cpu = platform.processor()
cpu_str = "cpu:"+cpu
print(cpu_str)
# 返回平台CPU逻辑和物理核心数
core_num_logical = psutil.cpu_count()
core_num_physical = psutil.cpu_count(logical=False)
print("logical core:", core_num_logical)
print("physical core:", core_num_physical)
# 启动记录
fout = open("CPUlog.txt", "w")
fout.write(cpu_str+"\n")
fout.write("logical core:" + str(core_num_logical) + "\n")
fout.write("physical core:" + str(core_num_physical) + "\n")
tip_content = "#timestamp(sec), mean cpu percent"
for i in range(core_num_logical):
tip_content += ", core_"+str(i)
tip_content += "\n"
fout.write(tip_content)
while True:
cur_stats = psutil.cpu_percent(interval=0.5, percpu=True)
cur_time = time.time()
mean_stats = np.mean(cur_stats)
fout.write(str(cur_time)+","+str(mean_stats))
for i in range(len(cur_stats)):
fout.write(","+str(cur_stats[i]))
fout.write("\n")
print(cur_time, mean_stats, cur_stats)
fout.close()
代码上传到了Github,点击查看。这样就能获取到CPU的使用信息,如下。
1.4 内存静态信息获取
利用psutil,主要获取内存大小信息,如下。
import psutil
GB = 1024*1024*1024
# 返回内存
vm = psutil.virtual_memory()
vm_total = vm.total/GB
print("total memory(GB):", vm_total)
# 返回交换内存
sm = psutil.swap_memory()
sm_total = sm.total/GB
print("swap memory(GB):", sm_total)
代码上传到了Github,点击查看。这样就能获取到内存基本的信息,如下。
1.5 内存动态信息监控
核心还是psutil,代码如下。
import psutil
import time
GB = 1024*1024*1024
fout = open("./MEMlog.txt", "w")
tip_content = "#timestamp(sec), total memory(GB), used memory(GB), percent, total swap memory(GB), used swap memory(GB), percent\n"
fout.write(tip_content)
while True:
# 返回内存
vm = psutil.virtual_memory()
sm = psutil.swap_memory()
cur_time = time.time()
vm_total = vm.total/GB
vm_used = vm.used/GB
vm_percent = vm.percent
sm_total = sm.total/GB
sm_used = sm.used/GB
sm_percent = sm.percent
fout.write(str(cur_time)+","+str(vm_total)+","+str(vm_used)+","+str(vm_percent)+","+str(sm_total)+","+str(sm_used)+","+str(sm_percent)+"\n")
print(str(cur_time)+":"+str(vm_used)+"GB/"+str(vm_total)+"GB", str(vm_percent)+"%")
time.sleep(0.5)
fout.close()
代码上传到了Github,点击查看。获取到的内存使用信息如下。
1.6 GPU静态信息获取
对于GPU信息的获取,主要是通过Nvidia提供的nvidia-smi
工具实现。其实在之前这篇笔记中已经介绍过了。需要注意的是,你应该先确保在终端或控制台中输入nvidia-smi
命令可以正常使用,否则无法获得相关信息。获得信息的核心代码如下:
import os
def parseSMIVersion(text_content):
lines = text_content.split("\n")
target_line = lines[2]
parts = target_line.split("NVIDIA-SMI")[1].split("Driver Version:")
smi_version = parts[0].strip()
driver_version = parts[1].split("CUDA Version:")[0].strip()
cuda_version = parts[1].split("CUDA Version:")[1].split("|")[0].strip()
return smi_version, driver_version, cuda_version
str_command = "nvidia-smi"
out = os.popen(str_command)
text_content = out.read()
out.close()
smi_ver, driver_ver, cuda_ver = parseSMIVersion(text_content)
print("smi version", smi_ver)
print("driver version", driver_ver)
print("cuda driver", cuda_ver)
代码上传到了Github,点击查看。获取到的GPU信息如下。
当然,还有第二种方式,利用Nvidia提供的pynvml库进行信息获取。首先,需要安装pip install pynvml
库,然后执行以下代码即可:
import pynvml
# 初始化 pynvml
pynvml.nvmlInit()
# 获取 GPU 数量
deviceCount = pynvml.nvmlDeviceGetCount()
print("GPU number:", pynvml.nvmlDeviceGetCount())
# 获取GPU信息
for i in range(deviceCount):
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
gpu_name = pynvml.nvmlDeviceGetName(handle)
print("GPU name:", gpu_name)
mem_info = pynvml.nvmlDeviceGetMemoryInfo(handle)
print("GPU Memory:", mem_info.total/(1024*1024*1024),"GB")
# 清理和释放资源
pynvml.nvmlShutdown()
代码也上传到了Github,点击查看。获取到的GPU信息如下。
1.7 GPU动态信息监控
对于GPU的动态信息,主要是GPU的使用率和显存占用情况。首先是nvidia-smi方法,代码如下:
代码上传到了Github,点击查看。获取到的GPU信息如下。
第二种基于pynvml的方法,代码如下。
import time
import pynvml
fout = open("GPUlog.txt", "w")
fout.write("# timestamp(sec), total gpu memory(GB), used gpu memory(GB), GPU percent\n")
# 初始化 pynvml
pynvml.nvmlInit()
# 获取 GPU 数量
deviceCount = pynvml.nvmlDeviceGetCount()
print("GPU number:", pynvml.nvmlDeviceGetCount())
handle = pynvml.nvmlDeviceGetHandleByIndex(0)
while True:
mem_info = pynvml.nvmlDeviceGetMemoryInfo(handle)
gpu_info = pynvml.nvmlDeviceGetUtilizationRates(handle)
cur_time = time.time()
mem_used = mem_info.used/(1024*1024*1024)
mem_total = mem_info.total/(1024*1024*1024)
gpu_percent = gpu_info.gpu
print("used memory:", mem_used, "GB","percnet:", gpu_percent)
fout.write(str(cur_time)+","+str(mem_total)+","+str(mem_used)+","+str(gpu_percent)+"\n")
time.sleep(0.5)
# 清理和释放资源
pynvml.nvmlShutdown()
fout.close()
代码上传到了Github,点击查看。获取到的GPU信息如下。
2.Nvidia Jetson平台
在Nvidia Jetson平台,主要是指Jetson的TX系列、Orin系列、Xavier系列等开发板。CPU、内存等信息的获取方式和上面PC平台可以互通,但GPU相关信息获取方式则有一些差异。信息获取的核心方式是利用Nvidia提供的jetson-stats工具,Github网页是这里。安装方式非常简单,如下:
sudo apt-get install python3-dev
sudo apt-get install python3-pip
sudo pip3 install -U jetson-stats
官方也提供了很多示例可供参考。
2.1 平台基础信息获取
直接运行1.1部分的代码,效果如下。 与PC平台通用。
或者,也可以使用jetson-stats提供的接口获得详细信息。主要参考这个官方示例,如下。
from jtop import jtop
if __name__ == "__main__":
print("Simple jtop hardware reader")
with jtop() as jetson:
# jetson.ok() will provide the proper update frequency
if jetson.ok():
# Read hardware, platform and libraries list
# Print all values
for name_category, category in jetson.board.items():
print("{name}:".format(name=name_category))
# Print all category
for name, value in category.items():
print(" - {name}: {value}".format(name=name, value=value))
代码上传到了Github,点击查看。获取到的信息如下。
2.2 CPU静态信息获取
直接运行1.2部分的代码,效果如下。
与PC平台通用。但由于此类嵌入式开发板的硬件比较特殊,因此还可以通过其他方式获得更详细的信息,例如在这篇笔记中提到的,通过cat /proc/cpuinfo
可以获得更丰富的内容,如下。
2.3 CPU动态信息监控
直接运行1.3部分的代码,效果如下。 与PC平台通用。
或者,通过jetson-stats获得,参考官方示例,如下。
from jtop import jtop
if __name__ == "__main__":
print("Simple jtop cpu reader")
with jtop() as jetson:
# jetson.ok() will provide the proper update frequency
if jetson.ok():
# Print all cpu
for idx, cpu in enumerate(jetson.cpu['cpu']):
print("------ CPU{idx} ------".format(idx=idx))
for key, value in cpu.items():
print("{key}: {value}".format(key=key, value=value))
# read aggregate CPU status
total = jetson.cpu['total']
print("------ TOTAL ------")
for key, value in total.items():
print("{key}: {value}".format(key=key, value=value))
代码上传到了Github,点击查看。获取到的信息如下。
2.4 内存静态信息获取
直接运行1.4部分的代码,效果如下。 与PC平台通用。
2.5 内存动态信息监控
直接运行1.5部分的代码,效果如下。 与PC平台通用。
或者,通过jetson-stats获得,参考官方示例,如下。
from jtop import jtop
if __name__ == "__main__":
print("Simple jtop memory reader")
with jtop() as jetson:
# jetson.ok() will provide the proper update frequency
if jetson.ok():
# Print all cpu
for name, data in jetson.memory.items():
print("------ {name} ------".format(name=name))
print(data)
代码上传到了Github,点击查看。获取到的信息如下。
2.6 GPU静态信息获取
Jetson平台的GPU信息无法通过前面的命令获得。不过,Jetson平台提供了jtop
命令,可以获得关于GPU硬件的详细信息,可以参考这篇笔记。参考官方文档示例,我们也可以很容易获得相关信息:
from jtop import jtop
if __name__ == "__main__":
print("All accessible jtop properties")
with jtop() as jetson:
# boards
print('*** board ***')
print(jetson.board)
# jetson.ok() will provide the proper update frequency
while jetson.ok():
# CPU
print('*** CPUs ***')
print(jetson.cpu)
# CPU
print('*** Memory ***')
print(jetson.memory)
# GPU
print('*** GPU ***')
print(jetson.gpu)
# Engines
print('*** engine ***')
print(jetson.engine)
# nvpmodel
print('*** NV Power Model ***')
print(jetson.nvpmodel)
# jetson_clocks
print('*** jetson_clocks ***')
print(jetson.jetson_clocks)
# Status disk
print('*** disk ***')
print(jetson.disk)
# Status fans
print('*** fan ***')
print(jetson.fan)
# uptime
print('*** uptime ***')
print(jetson.uptime)
# local interfaces
print('*** local interfaces ***')
print(jetson.local_interfaces)
# Temperature
print('*** temperature ***')
print(jetson.temperature)
# Power
print('*** power ***')
print(jetson.power)
代码上传到了Github,点击查看。获取到的信息如下。 可以看到,事实上除了GPU,还输出了非常丰富的软硬件信息。
2.7 GPU动态信息监控
对于GPU动态监控,官方示例提供了一个很好的logger,我们直接拿过来用即可。
from jtop import jtop, JtopException
import csv
import argparse
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Simple jtop logger')
# Standard file to store the logs
parser.add_argument('--file', action="store", dest="file", default="GPUlog.csv")
args = parser.parse_args()
print("Simple jtop logger")
print("Saving log on {file}".format(file=args.file))
try:
with jtop() as jetson:
# Make csv file and setup csv
with open(args.file, 'w') as csvfile:
stats = jetson.stats
# Initialize cws writer
writer = csv.DictWriter(csvfile, fieldnames=stats.keys())
# Write header
writer.writeheader()
# Write first row
writer.writerow(stats)
# Start loop
while jetson.ok():
stats = jetson.stats
# Write row
writer.writerow(stats)
print("Log at {time}".format(time=stats['time']))
except JtopException as e:
print(e)
except KeyboardInterrupt:
print("Closed with CTRL-C")
except IOError:
print("I/O error")
代码上传到了Github,点击查看。获取到的信息如下。 事实上,这里不仅仅保存了GPU使用信息,还保存了CPU的动态使用信息等一系列你关心的数据,比如温度等,使用起来十分方便。
3.树莓派Raspberry Pi平台
对于树莓派平台而言,部分CPU和内存信息可以以通用方式获得。其余则需要有专门的方式。
3.1 平台基础信息获取
直接运行1.1部分的代码,效果如下。 与PC平台通用。
3.2 CPU静态信息获取
直接运行1.2部分的代码,效果如下。 与PC平台通用。
当然,还是可以通过cat /proc/cpuinfo
可以获得更丰富的内容,如下。
3.3 CPU动态信息监控
直接运行1.3部分的代码,效果如下。 与PC平台通用。
3.4 内存静态信息获取
直接运行1.4部分的代码,效果如下。 与PC平台通用。
3.5 内存动态信息监控
直接运行1.5部分的代码,效果如下。 与PC平台通用。
3.6 GPU静态信息获取
某种程度来说,树莓派并没有真正的GPU,不过,我们可以通过如下命令查看相关硬件信息。
sudo /opt/vc/bin/vcdbg reloc stats
效果如下。
3.7 GPU动态信息监控
和上面类似的,树莓派并没有真正的GPU,只有VideoCore。不过通过上面的命令依然可以获得GPU内存的占用情况。此外,还可以通过一些命令查看CPU和GPU的温度,如下。
# CPU温度
cat /sys/class/thermal/thermal_zone0/temp | awk '{print "CPU Temp:"(int($0) / 1000)}'
# GPU温度
vcgencmd measure_temp | cut -c6-9 | awk '{print "GPU Temp:"$0}'
效果如下。
4.小结
最后,我们对在上面三个平台上获取动态信息的方式进行总结,如下。
本文中所有代码均上传到了Github,点击查看。最后,我们利用2.7部分提供的代码,对Jeton AGX Orin平台运行YoLoV5网络的资源占用情况进行测试,效果如下图所示。 测试时前后30秒为空白。可以看到,当网络启动的时候,首先CPU短暂“拉满”,这主要是利用CPU在进行模型的加载,之后主要就是CPU在执行运算了。同时也可以看到,温度、占用率等数据也都是同步变化的。
5.参考资料
- [1] https://pypi.org/project/psutil/
- [2] https://www.jb51.net/article/281902.htm
- [3] https://www.jb51.net/python/290893r3m.htm
- [4] https://blog.csdn.net/mouday/article/details/134476278
- [5] https://github.com/rbonghi/jetson_stats
- [6] https://shumeipai.nxez.com/2014/10/04/get-raspberry-the-current-status-and-data.html
- [7] http://129.226.226.195/post/21019.html
本文作者原创,未经许可不得转载,谢谢配合