GPU信息提取与可视化

方法简介

**nvidia-smi**简称NVSMI,提供监控GPU使用情况和更改GPU状态的功能,是一个跨平台工具,它支持所有标准的NVIDIA驱动程序支持的Linux发行版以及从WindowsServer 2008 R2开始的64位的系统。该工具是N卡驱动附带的,只要安装好驱动后就会有它

​ 调用nvidia-smi,将输出存至本地,解析并获取当前GPU状态信息,使用Flask模板传入Echarts来可视化。

一些知识

实现

  • 首先第一步是构造函数调用 nvidia-smi,存储命令输出结果,构造函数:
1
2
3
4
5
6
7
8
# 每次调用,更新状态,加到存储,对此函数定时调用【一小时一调用】
def ontime_check_util():
if os.path.exists('info.xml'):
os.system('rm info.xml')

os.system('nvidia-smi -q -x>> info.xml')
#add new state to csv
add_util() #这里是提取信息加入存储(csv表格存储信息)的函数
  • 然后构造函数定时调用,即定时更新状态并存储

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def re_exe(cmd, inc = 3600):
    while True:
    #os.system(cmd)
    cmd()
    time.sleep(inc)
    ...

    if __name__ == '__main__':
    #data = get_data_util('info.xml', 'gpu_util')
    #print(data)
    re_exe(ontime_check_util, 3600)
  • 构造函数解析GPU状态信息——info.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #GPU资源利用率
    def get_data_util(xml_fname, util_name):
    data_util = []
    xmlfilepath = os.path.abspath( xml_fname )
    print ("xml path:", xmlfilepath)

    # Get the document object
    domobj = xmldom.parse(xml_fname)
    print("xmldom.parse:", type(domobj))
    # Get the element object
    elementobj = domobj.documentElement
    print ("domobj.documentElement:", type(elementobj))

    #1========================Get gpu_util==========================================
    subElementObj1 = elementobj.getElementsByTagName( util_name )
    for i in range(len(subElementObj1)):
    #print ("subElementObj1[i]:", type(subElementObj1[i]))
    data_util.append(int(str(subElementObj1[i].firstChild.data)[:-1])) #Displays data between tag pairs

    print(util_name,data_util)
    avg_data_util = sum(data_util)/len(data_util)
    highest_data_util = max(data_util)

    #return avg_gpu_util
    return highest_data_util,avg_data_util,data_util
  • 调用解析函数,将结果加入存储(csv表格)。csv表格记存储了各个时间的状态信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 获取数据,更新存储
    def add_util():
    data = pd.DataFrame(columns=['gpu_util', 'time'])
    #data = pd.read_csv('gpu.csv')
    highest_data_util,avg_data_util,data_util = get_data_util('info.xml', 'gpu_util') # 若想获取内存信息,第二参数改为'memory_util'即可
    data['gpu_util'] = [highest_data_util]
    t = time.gmtime()
    t = time.strftime("%Y/%m/%d:%H",t)
    data['time'] = [t]
    data.to_csv('gpu.csv', mode='a', header=False, index=None)
  • 构建函数将值传入Flask模板,用于Echarts图表展示

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class show_gpu_utils:
    def __init__(self,g,t):
    self.gpu_utils = g
    self.times = t

    #for echarts
    def gpu_utils_echarts():
    data = pd.read_csv('gpu.csv', encoding='utf-8')
    # ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
    # [50.0, 55, 60, 54, 52, 61, 58, 54, 50, 49, 54, 60]
    gpu_utils = list(data['gpu_utils'])
    times = list(data['time'].apply(lambda x: int(x.split(':')[-1])))

    highest_data_util = memory_gpu_util()
    return show_gpu_utils(gpu_utils, times), str(highest_data_util)+' %'
  • Flask调用

    1
    2
    3
    4
    @app.route('/echarts1')
    def echarts1():
    infos,now = GPU.gpu_utils_echarts()
    return render_template('echarts1.html', infos=[infos], now=now)

结果展示

折线图为近期GPU负载占比记录,右上角为当前GPU负载占比

show_GPU

以下提供一些样例下载:

PS

  • 若在Ubuntu里使用脚本执行os.system(' xxx ')命令,得先加一个cd命令进入工作台,因为os.system(‘ xxx ‘)命令在Ubuntu内等于重新开一个Shell窗口。

​ 比如之前做了一个数据一键生成和一键训练的,核心语句如下:

1
2
3
4
# Generate Data
os.system('cd ~/rjb && nohup python ./train/generate.py>> generate.txt 2>&1 &')
# Train Model
os.system('cd ~/rjb && python ./train/train.py')
  • 还有一点,若函数脚本所在文件夹是通过sys.append(os.getcwd() + 'xxx/')这样的方式import的,或者使用Python命令执行子目录的脚本 ,则脚本的工作台仍在根目录,举个栗子:上面的python ./train/generate.py执行后shell仍在根目录,并不在train/文件夹,因此train.py内所有相对目录得加上./train/,表示是train/子目录下的文件.