調優(yōu)數(shù)學庫是從HPC系統(tǒng)中提取最終性能的一種簡單而可靠的方法。 然而,對于長期存在的應用程序或需要在各種平臺上運行的應用程序來說,為每個供應商或庫版本調整庫調用可能是一個維護噩夢。
一個編譯器可以自動生成對調優(yōu)的數(shù)學庫的調用,這給您提供了兩個世界中最好的:易于移植和最終性能。 在這篇文章中,我展示了如何無縫地加速GPU上的許多標準Fortran數(shù)組intrinsic和語言構造。 nvfortran編譯器通過將Fortran語句映射到NVIDIA cu TEN SOR庫中可用的函數(shù)來自動實現(xiàn)這種加速,這是一種第一種GPU加速的張量線性代數(shù)庫,提供張量收縮、約簡和元素操作。
一個簡單的上車到NVIDIA GPU
下面是標準Fortran數(shù)組內在函數(shù)如何映射到GPU加速的數(shù)學庫。 在最簡單的層次上,只需要兩個Fortran語句就可以利用cut TEN SOR庫提供的出色性能:
use 卡頓索克斯 ... c = matmul(a,b)
使用的第一個語句 卡頓索克斯 預定義模塊以重載Fortran內部過程、數(shù)組表達式和重載賦值的形式包含cuTENSOR庫的接口。這些接口僅用于映射位于GPU設備內存中的陣列。在本文后面,我將從OpenACC和CUDA Fortran程序員的角度討論這意味著什么。定義了這些接口后,第二條語句包含 馬修() 內在調用自動映射到cuTEN SOR函數(shù)調用。
接口通過識別和匹配幾種常用模式來實現(xiàn)延遲執(zhí)行,這些模式可以映射到單個cu TEN SOR內核調用。 在所有情況下,調用多個cu TEN SOR函數(shù)來設置cu TEN SOR所需的句柄、描述符數(shù)據(jù)結構和工作緩沖區(qū)。
然而,只有一個內核被啟動到GPU上。 由于性能原因,必須映射整個語句,包括左側數(shù)組的賦值。 您不希望編譯器為右側操作的輸入或結果(中間或最終)創(chuàng)建臨時數(shù)組,這在Fortran中很常見。
支持標準Fortran操作
cut TEN SOR庫包含一般的置換和收縮操作。 置換的結果可以選擇由元素函數(shù)操作,也可以選擇縮放。
nvfortran編譯器可以識別和映射各種Fortran轉換intrinsic和元素intrinsic函數(shù),這些函數(shù)與通用數(shù)組語法相結合,用于cut TEN SOR功能。 一些比較直接的翻譯包括以下內容:
d = transpose(a) d = func(transpose(a)) d = alpha * func(transpose(a) d = reshape(a,shape=[...]) d = reshape(a,shape=[...],order=[...]) d = func(reshape(a,...)) d = alpha * func(reshape(a,...)) d = spread(a,dim=k,ncopies=n) d = func(spread(a,dim=k,ncopies=n)) d = alpha * func(spread(a,dim=k,ncopies=n))
的投入 馬修() 也可以在CuTEN SOR中置換,結果可以縮放和累積。 這導致了幾種可能的組合,例如以下陳述:
c = matmul(a,b) c = c + matmul(a,b) c = c - matmul(a,b) c = c + alpha * matmul(a,b) d = alpha * matmul(a,b) + beta * c c = matmul(transpose(a),b) c = matmul(reshape(a,shape=[...],order=[...]),b) c = matmul(a,transpose(b)) c = matmul(a,reshape(b,shape=[...],order=[...]))
使用來自標準Fortran的NVIDIA TensorCores
利用cuTEN SOR和NVIDIA TensorCores可以像下面的代碼示例一樣容易,當您使用包含在其中的隨機數(shù)生成特性時 卡頓索克斯 模塊:
program main use 卡頓索克斯 integer, parameter :: ni=5120, nj=5120, nk=5120, ntimes=10 真實的(8), allocatable, dimension(:,:) :: a, b, d allocate(a(ni,nk),b(nk,nj),d(ni,nj)) call random_number(a) call random_number(b) d = 0.0d0 print *,"cutensor" call cpu_time(t1) do nt = 1, ntimes d = d + matmul(a,b) end do call cpu_time(t2) flops = 2.0*ni*nj*nk flops = flops*ntimes print *,"times",t2,t1,t2-t1 print *,"GFlops",flops/(t2-t1)/1.e9 end program
The 馬修() 內在調用映射到cuTENSOR調用,在可能的情況下無縫地使用Tensor Cores。我將在本文后面展示一些性能結果。
用nvfortran編譯程序
你可能會問這個程序是如何使用cuTEN SOR的,當我早些時候說的 cutensorex 接口只將GPU設備陣列上的操作映射到CuTEN SOR調用。 答案在于程序是如何編譯的:
% nvfortran -acc -gpu=managed -cuda -cudalib main.f90
在這里,我將程序編譯為Open ACC程序,并利用OpenACC管理內存模式,其中所有可分配數(shù)組都在CUDA統(tǒng)一內存中分配。 加上了 -cuda 這也支持CUDAFortran擴展,數(shù)組本質上是CUDAFortran– 托管數(shù)組。 CUDA Fortran通用接口匹配的一個規(guī)則是,當主機和設備接口都存在時,對于托管的實際參數(shù)更喜歡設備接口。
當聲明、分配和使用在同一個程序單元中時,nvfortran編譯器提供了一些快捷方式。 一般來說,最好使用OpenACC指令來指示編譯器傳遞設備地址,如下面的代碼示例:
!$acc host_data use_device(a, b, d) do nt = 1, ntimes d = d + matmul(a,b) end do !$acc end host_data
在這種情況下 -cuda 不需要編譯器選項。
使用CUDAFortran的CuTEN SOR
對于CUDAFortran用戶,the cutensorex 模塊和Fortran轉換本質成為高性能和完全可移植代碼的快速路徑。 使用這個 !@cuf 哨兵添加由nvfortranCUDAFortran編譯器解釋和編譯的代碼行,或被標準Fortran編譯器忽略為注釋:
program main !@cuf use cutensorex !@cuf use cudafor integer, parameter :: ni=5120, nj=5120, nk=5120, ntimes=10 real(8), allocatable, dimension(:,:) :: a, b, d !@cuf attributes(device) :: a, b, d allocate(a(ni,nk),b(nk,nj),d(ni,nj)) call random_number(a) call random_number(b) d = 0.0d0 print *,"cutensor" call cpu_time(t1) do nt = 1, ntimes d = d + matmul(a,b) end do call cpu_time(t2) flops = 2.0*ni*nj*nk flops = flops*ntimes print *,"times",t2,t1,t2-t1 print *,"GFlops",flops/(t2-t1)/1.e9 end program
在第6行,我用設備屬性聲明了數(shù)組,它將它們放在GPU設備內存中。 但是,它們也可以用托管屬性來聲明。 本程序可編譯并鏈接如下命令:
% nvfortran -Mcudalib main.cuf
在真實(8)數(shù)據(jù)上測量的性能
下面是性能,從前面示例中使用的真實(8)(雙精度)數(shù)據(jù)開始。 你可以用幾種方式來衡量矩陣乘性能:
單線程CPU實現(xiàn)
多線程或多核CPU實現(xiàn)
樸素編碼矩陣乘用指令卸載
The 馬修() 內在映射到CuTEN SOR
To get the best threaded-CPU performance, use the basic linear algebra subprogram (BLAS) library routine DGEMM. The equivalent DGEMM call to the earlier operation is the following command:
call dgemm('n','n',ni,nj,nk,1.0d0,a,ni,b,nk,1.0d0,d,ni)
為了了解調優(yōu)庫在天真的實現(xiàn)中可以提供什么,請使用下面的Open ACC循環(huán)結構在GPU上運行。 回路結構采用無特殊平鋪或硬件指令。
!$acc kernels do j = 1, nj do i = 1, ni do k = 1, nk d(i,j) = d(i,j) + a(i,k) * b(k,j) end do end do end do !$acc end kernels
實施/處理器 | TFLOP |
NVFORTRAN單CPU核上的Matmul | 0.010 |
在64個CPU核心上的MKLDGEMM | 1.674 |
天真開放ACC在V100 | 0.235 |
天真開放ACC在A100 | 0.447 |
NVFORTRAN Matmul on V100 | 6.866 |
A100上的NVFORTRAN Matmul | 一十七點六六 |
您不僅得到自動GPU加速在V100和A100GPU使用 馬修() 內在的,但在A100上的映射 馬修() 對于cuTensor調用,您可以自動使用FP64TensorCores。
在真實(4)和真實(2)數(shù)據(jù)上測量的性能
您可以使用相同的運行集執(zhí)行 真實的(4) (單一精度)數(shù)據(jù)和調用SGEMM而不是DGEMM。 此外,CUDA11.0cut Tensor Fortran包裝器可以利用A100TF32數(shù)據(jù)類型和TensorCores。 表2顯示了這些運行的性能。
實施/處理器 | TFLOP |
NVFORTRAN單CPU核上的Matmul | 0.025 |
在64個CPU核心上的MKLSGEMM | 3.017 |
天真開放ACC在V100 | 0.460 |
天真開放ACC在A100 | 0.946 |
NVFORTRAN Matmul on V100 | 一十點七零六 |
A100上的NVFORTRAN Matmul | 一十四點六二一 |
NVFORTRAN Matmul on A100 using TF32 | 六十點三五八 |
為什么停在那里? nvfortran編譯器支持16位浮點格式(FP16 真實的(2) 數(shù)據(jù)類型。 您可以在前面的測試中更改數(shù)組的類型,并在半精度上運行時間。
在V100上引入了半精度數(shù)據(jù)的TensorCore操作,然后在A100GPU上擴展,以支持TF32和全雙精度DP64TensorCores。 而nvfortran支持 真實的(2) 而TensorCores在V100和A100上,它不支持完整和優(yōu)化 真實的(2) 在CPU上,標準的BLAS庫也沒有。 在這種情況下,比較GPU加速版本的性能是有意義的(表3)。
實施/處理器 | TFLOP |
天真開放ACC在V100 | 0.490 |
天真開放ACC在A100 | 2.058 |
NVFORTRAN Matmul on V100 | 六十八點二四二 |
A100上的NVFORTRAN Matmul | 九十二點八一 |
雖然A100的性能令人印象深刻,代碼是完全可移植的,但對于TF32和FP16來說,它明顯低于峰值。 有固定的開銷:在每次調用時,創(chuàng)建和銷毀cutTEN SOR張量描述符并創(chuàng)建收縮計劃。 您還必須查詢和管理收縮中使用的工作區(qū)需求,這最終可能會調用 古達·馬洛克 and 無庫達 。 如果開銷是5– 對于FP64,這變得更接近25%的TF32和大約35%的FP16,對于這個大小的問題。
對于需要最終性能的開發(fā)人員,nvfortran確實直接支持Fortran接口到FortranCutensor模塊中的CcuTEN SORAPI,也是在HPCSDK中提供的。 您可以自己管理張量描述符、計劃和工作區(qū)。
結局推論
在這篇文章中,我展示了一些簡單的程序和Fortran intrinsic調用的類型以及可以在GPU上自動加速的代碼模式。 他們甚至可以通過cuTEN SOR自動利用TensorCores。 使用幾乎完全標準的Fortran和完全可移植到其他編譯器和系統(tǒng)的程序,您可以在NVIDIA GPU上實現(xiàn)矩陣乘法、矩陣轉置、元素數(shù)組本質和數(shù)組語法的多個組合上的近峰性能。
不可能預測你可以用這些新特性做些什么或實現(xiàn)什么。 我期待著看到你的反饋和結果。 NVIDIA繼續(xù)添加更多的特性,允許您使用標準Fortran結構以最大性能編程NVIDIA GPU。
關于作者
關于布倫特·萊克
Brent Leback管理NVIDIA HPC編譯器客戶支持和高級服務,并與HPC社區(qū)一起移植和優(yōu)化GPU計算應用程序。 他是CUDAFortran編程語言的共同創(chuàng)造者,并繼續(xù)積極參與新的CUDAFortran功能的設計。 他是開放ACC GPU黑客馬拉松的??停彩荂UDA Fortran的專家。
審核編輯 黃昊宇
發(fā)布評論請先 登錄
求Labview 下調用Fortran dll的詳細教程
時間域控制系統(tǒng)分析及拉普拉斯變換Fortran程序解答
Arm Fortran編譯器開發(fā)人員和參考指南
Arm Fortran編譯器22.1版開發(fā)人員和參考指南
Fortran函數(shù)大全
獲得英特爾Fortran編譯器的支持
FORTRAN教程Fortran語言程序設計詳細課件資料免費下載

評論