目录CUDAFortran环境的搭建和第一个CUDAFortran程序前言背景什么是CUDA编译器CUDAFortran环境的搭建确定设备环境CUDAToolkitHPC_SDK第
目录
- CUDA Fortran环境的搭建和第一个CUDA Fortran程序
- 前言
- 背景
- CUDA Fortran环境的搭建
- 确定设备环境
- CUDA Toolkit
- HPC_SDK
- 第一个CUDA Fortran程序
CUDA Fortran环境的搭建和第一个CUDA Fortran程序
前言
工作中需要用到CUDA Fortran对原有的Fortran程序做并行化,那么第一步就是要完成环境的搭建,总体来说过程并不是特别繁琐,但初次安装还是会遇到一些问题,因而在此概要性地做一下总结和整理.
背景
什么是CUDA
CUDA(Comute Unified Device Architecture),统一计算架构,是由NVIDIA公司所推出的一种结合CPU与GPU进行计算的架构.CUDA给程序开发人员提供直接访问CUDA GPU中虚拟指令集和存储器的接口.利用CUDA,GPU可以实现通用处理,而不仅仅是图形,这种方法被称为GPGPU(General-Purpose Graphic Processing Unit),与CPU不同的是,GPU侧重以较慢的速度执行大量并发的线程,而非快速执行单一线程,因而CUDA近些年来在并行计算中大放异彩.
详细内容请阅:
https://zh.wikipedia.org/wiki/CUDA
编译器
一开始NVIDIA官方只提供了CUDA C/C++ 的接口和编译器,因此可以很方便地将C/C++代码移植到GPU上,但对于科学与工程即使算中的重要编程语言Fortran,无法直接改写为CUDA C/C++,为了使Fortran应用能够使用GPU进行加速,与NVIDIA公司合作的PGI(The Portland Group)小组设计了CUDA Fortran语言,并在自家的PGI Fortran编译器中支持了CUDA Fortran程序的编译.直到2013年,NVIDIA收购了PGI,并在2020年将PGI Fortran编译器整合到了NVIDIA官方推出的HPC_SDK中,其编译器名称也有了统一的命名.
现在CUDA架构中常见的编译器有:
- nvc: 可以编译CUDA C程序
- nvc++: 可以编译CUDA C++程序
- nvfortran: 可以编译CUDA Fortran程序
- nvcc: 可以编译CUDA C/C++程序
CUDA Fortran环境的搭建
确定设备环境
截至目前,CUDA Fortran尚且不支持Windows,因此以下所有内容均基于Linux操作系统进行:
操作系统
首先用cat /etc/os-release
的方式来查看操作系统的版本并记录下来,后面会用到,我这里用的是ubuntu 20.04.
查找可用GPU
用lspci | grep -i nvidia
来查找是否有可用的NVIDIA GPU,AMD的显卡是无法安装CUDA环境的.
当完成第一步的准备工作后,我们就可以开始安装CUDA环境了,CUDA Toolkit是一个整合了CUDA C/C++编译器,cuda-gdb调试器,nvprof性能监测工具,NVIDIA显卡闭源驱动,各种库文件的一个集成工具包.因此我们无需从安装驱动开始,而是直接安装CUDA Toolkit.
首先我们需要访问CUDA Toolkit下载页面,然后逐层选择适配自己设备环境的安装方式.我的环境所选内容如下图:
需要注意的是此页面是目前最新版的CUDA Toolkit下载页面,如果你所用的发行版没有被支持,可以寻找更早的CUDA Toolkit release版本.
选择完成后,按照其下方给出的 installation instructions 进行安装即可.
安装过程中只需要按照提示进行一些简单的操作即可,但需要注意的是,安装过程最好在非图形化界面下进行,否则可能会引发一些不必要的错误,图形界面用户可以用sudo init 3
的方式进入纯命令行界面进行安装.另外,有些发行版中可能会默认安装了NVIDIA开源版本的显卡驱动nouveau,在安装前需要将其禁用,比较新的CUDA Toolkit会自行将其禁用而不需要我们手动进行,但若是安装一些比较古早的版本时,可能需要手动进行这一操作.
等待一段时间,当你安装完成后,屏幕上会给出提示,让你将bin包和库文件添加到环境变量中.选择你喜欢的编辑器编辑/home/'username'/.bashrc
文件,(用你的用户名替换'username'),在文件的末尾加上以下内容:
如果你安装的不是CUDA 11.7,那么你需要进入/usr/local
目录中,查看相应的cuda目录名,并将与第一行中的cuda-11.7进行替换.
完成之后source /home/'username'/.bashrc
或者重新打开一个shell进行一些测试.
检测驱动
用nvidia-smi
命令来检测驱动是否存在.若存在,会显示出详细的显卡信息,如下图:
编译器检查
在安装完CUDA Toolkit之后,事实上我们已经可以进行CUDA C/C++的 开发了,我们可以输入nvcc --version
命令来检查CUDA C/C++编译器的版本,或者用which nvcc
来查看PATH中是否能找到nvcc编译器.然后我们可以简单地编写一个CUDA C程序cudahello.cu
来验证编译器是否能够正常运行,注意文件名需要命名为.cu后缀,否则需要在编译时添加编译选项告诉编译器这是一个cuda程序,否则会在链接时因为找不到运行时库而报错:
#include
#include
__global__ void cuda_hello()
{
printf("hello world from GPU!\n");
}
int main()
{
cuda_hello<<<1,10>>>();
cudaDeviceReset();
return 0;
}
退出编辑器后输入nvcc cudahello.cu -o cudahello.out
,观察是否能够编译成功.若成功,再./cudahello.out
查看运行结果是否正确,若没有错误的话,会输出10条' hello world from GPU!'
- 检查调试器和性能监视器是否存在
which cuda-gdb
或者cuda-gdb --version
来查看调试器是否存在, which nvprof
或者nvprof --version
查看性能监测工具是否存在.
若以上步骤都没有什么问题,那么我们就可以进行到下一步,进行CUDA Fortran的环境安装了.
HPC_SDK
首先需要根据你所安装的CUDA版本选择合适的HPC_SDK,然后在下载页面按照它的installation instruction进行安装.另外还有一些预先的准备事项和安装完成后配置环境变量等工作,其流程在官方安装指导中给出了详细的描述.按照官方文档中的方式进行安装.安装完成后,此时若是用which nvfortran
命令会发现无法找到nvfortran编译器.是因为需要加载module文件.如果没有修改安装路径,那么sdk默认会安装到/opt/nvidia/hpc_sdk
目录下,modulefile文件位于/opt/nvidia/hpc_sdk/modulefiles/nvhpc
目录下,其中会有一个以你所安装的sdk版本命名的modulefile,我这里是22.5,然后需要module load ./22.5
,这时再用which nvfortran
发现已经可以找到nvfortran编译器了.
当然这样会存在一些麻烦,因为这样每次打开一个新的终端窗口,都需要重新输入这一长串的路径来加载module,为方便期间,我们可以给在usr/share/modules/modulefiles
目录下给我们刚刚安装的module文件创建一个软链接文件,命令为:
sudo ln -s /opt/nvidia/hpc_sdk/modulefiles/nvhpc/22.5 /usr/share/modules/modulefiles/name
其中22.5需要根据你所安装的版本进行替换,最后的name则可以按照你的想法自定义一个名字.
完成以上的步骤后,我们可以用module avail
查看可用的module,你所定义的name也会出现在列表中,此时我们可以直接module load name
,就可以完成module的加载,而不用输入之前的一长串路径.
检查
完成以上步骤后,分别用nvfortran --version
和man nvforrtran
进行测试,若能够正确显示其版本及手册,说明配置无误.若不能,或者仅手册不能,则说明环境变量没有配置好,可以详读官方安装指导进行配置.若没有问题,则进入/opt/nvidia/hpc_sdk/Linux_x86_64/22.5/examples/CUDA-Fortran
中,将SDK
目录复制到你的家目录下.然后make
,若结果显示为:
则说明环境没有问题,配置完成!
第一个CUDA Fortran程序
hello world
当我们搭建好环境,就需要写一个程序来测试一下功能了,新建一个hello.cuf
文件,同样要注意后缀名,若后缀名不是.cuf,则需要在编译选项中指定.在文件中添加一个简单的hello world代码块:
module hello_m
contains
attributes(global) subroutine hello()
implicit none
print*, 'hello world from GPU!'
end subroutine hello
end module hello_m
program main
use cudafor
use hello_m
implicit none
integer :: ierr
call hello<<<1,10>>>()
ierr = cudaDeviceReset()
end program main
然后进行编译:
nvfortran hello.cuf -o hello.out
然后./hello.out
执行一下,若执行结果能正确显示十个hello world from GPU!,则说明没有问题,CPU和GPU之间可以正常通信.
以上