深度学习、图像渲染、科学计算、挖矿这些复杂计算的场景都需要使用GPU进行大量计算,但是当你拿到一台GPU服务器以后,你应该如何入手学习呢,如何进行调试呢。本文主要讲解一些GPU相关的知识,从GPU简单介绍开始,进而到linux下如何查看GPU相关指标,最后讲解如何调试调用GPU,并使用GPU运行简单程序。
注:本文讲解使用的GPU是NVIDIA GPU。
GPU全称graphics processing unit,中文译名图形处理器,又称显示核心、视觉处理器、显示芯片。通常一般的程序任务直接是由CPU完成,但是对于密集型计算任务,就需要借助GPU来完成了。我们对CPU结构非常熟悉,一颗处理器其实由几个或几十个运算核心组合而成的,而GPU却拥有上百颗甚至上千个运算核心,所以GPU具有强大的计算能力。
要使用GPU进行计算,就需要有接口来调用GPU,CUDA就实现了完整的GPU调度方案。CUDA是NVIDIA公司推出的一种基于GPU的通用并行计算平台,提供了硬件的直接访问接口。CUDA采用C语言作为编程语言提供大量的高性能计算指令开发能力,使开发者能够在GPU的强大计算能力的基础上建立起一种效率更高的密集数据计算解决方案。
上面简要对GPU做了个介绍,下面直接进入实操部分吧。
查看GPU简略信息
[root@gpu-node ~]# lspci | grep -i vga | grep -i nvidia
可以看到服务器有8块NVIDIA的显卡
查看某一块显卡的具体详细信息
[root@gpu-node ~]# lspci -v -s 04:00.0
直接查看所有显卡详细信息-1
[root@gpu-node ~]# lspci -vnn | grep -i vga -A 12
直接查看所有显卡详细信息-2
[root@gpu-node ~]# lshw -C display
查看系统所使用的显卡驱动名称
[root@gpu-node ~]# lshw -c video | grep configuration
首先从NVIDIA官网:https://www.nvidia.com/Download/Find.aspx 下载对应显卡版本的驱动安装版本包。
[root@gpu-node ~]# wget https://us.download.nvidia.com/XFree86/Linux-x86_64/460.56/NVIDIA-Linux-x86_64-460.56.run [root@gpu-node ~]# chmod +x NVIDIA-Linux-x86_64-460.56.run 安装系统对应的gcc和kernel-devel,驱动在安装过程种需要编译kernel module [root@gpu-node ~]# yum install -y gcc kernel-devel-$(uname -r) 安装dkms,注册nvidia驱动到dkms中,通过dkms管理,当内核更新的时候,会自动build新的nvidia内核模块 [root@gpu-node ~]# yum install -y dkms [root@gpu-node ~]# ./NVIDIA-Linux-x86_64-460.56.run --dkms --silent --silent 静默安装,不弹出图形化UI界面 安装成功后可以执行 nvidia-smi 如果要卸载可以执行 [root@gpu-node ~]# ./NVIDIA-Linux-x86_64-460.56.run --uninstall --silent 查看是否有nvidia软件包,可以yum remove卸载干净 [root@gpu-node ~]# rpm -qa | grep -i nvidia
安装后验证
查看系统已安装的NVIDIA module
[root@gpu-node ~]# lsmod|grep nvidia
查看nvidia的路径与版本等信息
[root@gpu-node ~]# modinfo nvidia
nvidia-smi可以直接查看GPU当前使用情况
[root@gpu-node ~]# nvidia-smi
表头释义:
Fan:显示风扇转速,数值在0到100%之间,是计算机的期望转速,如果计算机不是通过风扇冷却或者风扇坏了,显示出来就是N/A;
Temp:显卡内部的温度,单位是摄氏度;
Perf:表征性能状态,从P0到P12,P0表示最大性能,P12表示状态最小性能;
Pwr:能耗表示;
Bus-Id:涉及GPU总线的相关信息;
Disp.A:是Display Active的意思,表示GPU的显示是否初始化;
Memory Usage:显存的使用率;
Volatile GPU-Util:浮动的GPU利用率;
Compute M:计算模式;
下边的Processes显示每块GPU上每个进程所使用的显存情况。
结合watch命令动态监控GPU使用情况
[root@gpu-node ~]# watch -n 1 nvidia-smi
cuda下载地址:https://developer.nvidia.com/cuda-toolkit-archive
[root@gpu-node ~]# wget https://developer.download.nvidia.com/compute/cuda/11.2.0/local_installers/cuda-repo-rhel7-11-2-local-11.2.0_460.27.04-1.x86_64.rpm [root@gpu-node ~]# rpm -ivh cuda-repo-rhel7-11-2-local-11.2.0_460.27.04-1.x86_64.rpm [root@gpu-node ~]# yum install -y cuda
查看安装信息
[root@gpu-node ~]# /usr/local/cuda/bin/nvcc -V
下面讲解如何使用python程序调用GPU
pycuda是一个可以访问NVIDIA的CUDA的python库
[root@gpu-node ~]# pip3 install pycuda==2018.1.1 -i https://pypi.mirrors.ustc.edu.cn/simple/
可能会出现如下错误信息:
gcc -pthread -Wno-unused-result -Wsign-compare -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -O3 -DNDEBUG -fPIC -DBOOST_ALL_NO_LIB=1 -DBOOST_THREAD_BUILD_DLL=1 -DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION=1 -DBOOST_PYTHON_SOURCE=1 -Dboost=pycudaboost -DBOOST_THREAD_DONT_USE_CHRONO=1 -DPYGPU_PACKAGE=pycuda -DPYGPU_PYCUDA=1 -DHAVE_CURAND=1 -Isrc/cpp -Ibpl-subset/bpl_subset -I/usr/local/lib64/python3.6/site-packages/numpy/core/include -I/usr/include/python3.6m -c src/cpp/cuda.cpp -o build/temp.linux-x86_64-3.6/src/cpp/cuda.o In file included from src/cpp/cuda.cpp:4:0: src/cpp/cuda.hpp:14:18: fatal error: cuda.h: No such file or directory #include <cuda.h> ^ 编译中断。 error: command 'gcc' failed with exit status 1 ---------------------------------------- Command "/usr/bin/python3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-slw8h082/pycuda/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-ig9vl5ig-record/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-build-slw8h082/pycuda/
出现上面报错是因为cuda的相关的命令没有加入到环境变量
添加环境变量即可 [root@gpu-node ~]# export PATH=/usr/local/cuda-11.2/bin:/usr/local/cuda/bin:$PATH
我的第一个GPU调用程序小例子
vim gpu.py
import pycuda.autoinit from pycuda.compiler import SourceModule import time mod = SourceModule(""" #include <stdio.h> __global__ void work() { printf("Manage GPU success!\\n"); } """) func = mod.get_function("work") func(block=(1,1,1)) time.sleep(30)
使用 nvidia-smi 查看可以发现Process里面有进程使用GPU显卡,说明我们的程序调用GPU成功
默认是使用第0个GPU,如果要使用其他GPU:
1.可以使用CUDA_VISIBLE_DEVICES=1 python3 gpu.py表示使用第一个1块显卡;
2.可以使用CUDA_DEVICE=0,1,2 python3 gpu.py表示使用第0块、1块、2块显卡,当第0块显卡显存使用完毕后,会自动使用第1块,以此类推;
3.或者直接将调用的设置写在程序里
import time,os
os.environ["CUDA_VISIBLE_DEVICES"] = "2"
主要必须写在 import pycuda.autoinit 前面
进化版本,同时使用多个GPU
work.py
import time,os os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,2,3,4,5,6,7" import pycuda.autoinit from pycuda.compiler import SourceModule mod = SourceModule(""" #include <stdio.h> __global__ void work() { printf("Manage GPU success!\\n"); } """) func = mod.get_function("work") func(block=(1,1,1)) time.sleep(60)
mul_gpu.py
import os,threading cmd = "export PATH=/usr/local/cuda-11.2/bin:/usr/local/cuda/bin:$PATH;/usr/bin/python3 /root/mul_gpu.py" threads = [] def test(): os.system(cmd) for i in range(80): t = threading.Thread(target=test,args=()) t.start() threads.append(t) for i in threads: i.join()
可以看到跑多个任务时,第0块GPU跑满后,会接着调度第1块GPU。