PGIトップ PGI技術情報・TIPS コンパイラ・オプションの使用方法 BLAS/LAPACK
OpenBLAS BLAS LAPACK PGIコンパイラ オプション
PGI 16.1 以降から OpenBLAS project sourceに基づいた最適化 BLAS/LAPACK を提供しました。これは、予め PGI コンパイラを用いてプリコンパイルされているライブラリで、-lblas -llapack リンク・オプションを付けてリンクできます。また、マルチスレッド・モードでも動作します。この方法を以下に説明します。なお、PGI 15.10 までのバージョンでは ACML ライブラリ内の BLAS/LAPACK をご利用ください。
PGIコンパイルシステムから参照可能な OpenBLAS ライブラリは、PGIコンパイラでビルドされたものです。 OpenBLAS project source に基づいた性能最適化が施されております。シングルスレッド、マルチスレッドのどちらにも対応できます。以下のリンクオプションを指定して、当該 BLAS あるいは LAPACK ルーチンをリンクしてください。
PGI 16.1 以降の BLAS/LAPACK ライブラリをリンクする方法
● Linux/Windows/OS X 版シングルスレッド
【Fortran】 pgf77 -fastsse -Minfo test.f -lblas -llapack pgfortran -fastsse -Minfo test.f90 -lblas -llapack 【C/C++】 pgcc -fastsse -Minfo test.c -lblas -llapack -pgf90libs pgc++ -fastsse -Minfo test.cpp -lblas -llapack -pgf90libs (Windows版には C++ コマンドはありません) ※C/C++ コンパイラ使用時は-pgf90libsオプションを加えて下さい。
● OpenMPマルチスレッド並列用コンパイル (Windows版の OpenBLAS は、マルチスレッド対応ではありません)
【Fortran】 (Linux / OS X only) pgf77 -fastsse -Minfo test.f -lblas -llapack -mp pgfortran -fastsse -Minfo test.f90 -lblas -llapack -mp 【C/C++】 (Linux / OS X only) pgcc -fastsse -Minfo test.c -lblas -llapack -pgf90libs -mp pgc++ -fastsse -Minfo test.cpp -lblas -llapack -pgf90libs -mp ※C/C++ コンパイラ使用時は-pgf90libsオプションを加えて下さい。
Fortranでの使用例 (matrix multiply BLASを使用)
● ソースプログラム例
program matmul_time c integer i, j, k integer size, ntimes, m, n, p parameter (size=1000) parameter (m=size,n=size,p=size) parameter (ntimes=20) real*8 a, b, c, arow dimension a(m,n), b(n,p), c(n,p), arow(n) integer l real*8 walltime, mflops integer hz, clock0, clock1, clock11, clock2 integer t real*8 second real*8 time0, time1, time11, time2 #if defined (OMPTIME) real*8 omp_get_wtime, omp_get_wtick print *, "OMP_Wtime resolution: ", omp_get_wtick() #endif #if defined (SYSCLK) call system_clock(count_rate=hz) print *, "system_clock resolution: ", real(1.d0/hz) #endif c call random_number(a) call random_number(b) #if defined (SYSCLK) ! Elapsed time : Using F90 system_clock : Milli second call system_clock(count=clock0) #elif defined (OMPTIME) ! Elapsed time : OpenMP build-in function: Micro second time0 = omp_get_wtime() #else ! Elapsed time : SECOND() C function : Micro second time0 = second() #endif do l = 1, ntimes #if defined MATMUL ! F90 Intrinsic function (MATMUL) c = matmul(a, b) #elif defined BLAS ! AMD ACML(LAPACK) Library call dgemm('N','N', m, p, n, 1.0d0, a, m, b, n, 0.0d0, c, n) #else ! Source coding !$omp parallel default(shared) !$omp do do j = 1, p do i = 1, m c(i,j) = 0.0 enddo enddo do i = 1, m !$omp do do ii = 1, n arow(ii) = a(i,ii) enddo !$omp do schedule(runtime) do j = 1, p do k = 1, n c(i,j) = c(i,j) + arow(k) * b(k,j) enddo enddo enddo !$omp end parallel #endif call dummy(c) enddo #if defined (SYSCLK) call system_clock(count=clock1) call system_clock(count=clock11) #elif defined (OMPTIME) time1 = omp_get_wtime() time11= omp_get_wtime() #else time1 = second() time11= second() #endif do i = 1, ntimes call dummy(c) enddo #if defined (SYSCLK) call system_clock(count=clock2) #elif defined (OMPTIME) time2 = omp_get_wtime() #else time2 = second() #endif #if defined (SYSCLK) t = (clock1 - clock0) - (clock2 - clock11) walltime = real(t) / real(hz) / real(ntimes) mflops = (m*p*(2*n-1)) / (walltime * 1.0d+06) print *,"Elapsed time =", walltime , " (sec)" #else walltime = ((time1 - time0) - (time2 - time11)) / real(ntimes) mflops = (m*p*(2*n-1)) / (walltime * 1.0d+06) print *,"Elapsed time =", walltime ," (sec)" #endif c print *, "M =",M,", N =",N,", P =",P print *, "MFLOPS = ", mflops print *, "c(10,10) = ", c(10,10) c end c subroutine dummy(c) return end
● コンパイル・リンク
BLAS/LAPACKルーチンを使用するため -DBLAS オプションを入れて、マルチスレッド(-mp)
$ pgf90 -fastsse -Minfo -DBLAS -DOMPTIME matmul.F -lblas -llapack -mp matmul_time: 29, Loop interchange produces reordered loop nest: 30,29 2 loops fused Generated an alternate version of the loop Generated vector sse code for the loop 30, Loop not fused: function call before adjacent loop 2 loops fused 34, Loop interchange produces reordered loop nest: 35,34 52, Loop not vectorized/parallelized: contains call 100, Loop not vectorized/parallelized: contains call
● 実行
Intel(R) Core i5-4690(Haswell Refresh 第4世代)CPU @ 3.50GHz 4コアを使用
$ export OMP_NUM_THREADS=1 $ ./a.out OMP_Wtime resolution: 9.9999999999999995E-007 Elapsed time = 4.1460651159286502E-002 (sec) M = 1000 , N = 1000 , P = 1000 MFLOPS = 48214.38988789874 (48GFLOPS) c(10,10) = 244.1990574713752 $ export OMP_NUM_THREADS=2 $ ./a.out OMP_Wtime resolution: 9.9999999999999995E-007 Elapsed time = 2.2754621505737305E-002 (sec) M = 1000 , N = 1000 , P = 1000 MFLOPS = 87850.28568794150 (87GFLOPS) c(10,10) = 244.1990574713752 $ export OMP_NUM_THREADS=3 $ ./a.out OMP_Wtime resolution: 9.9999999999999995E-007 Elapsed time = 1.7555427551269532E-002 (sec) M = 1000 , N = 1000 , P = 1000 MFLOPS = 113867.9188622462 (113GFLOPS) c(10,10) = 244.1990574713752 $ export OMP_NUM_THREADS=4 $ ./a.out OMP_Wtime resolution: 9.9999999999999995E-007 Elapsed time = 1.3460004329681398E-002 (sec) M = 1000 , N = 1000 , P = 1000 MFLOPS = 148514.0681264043 (148GFLOPS) c(10,10) = 244.1990574713752
● BLASを使わず OpenMP プログラムで実行した場合(性能比較)
Intel(R) Core i5-4690(Haswell Refresh 第4世代)CPU @ 3.50GHz 4コアを使用
$ pgf90 -fastsse -Minfo -DOMPTIME matmul.F -mp -Mvect=simd:256 (-DBLASを除く) matmul_time: 44, Loop not vectorized/parallelized: too deeply nested 56, Parallel region activated 58, Parallel loop activated with static block schedule 59, Memory zero idiom, loop replaced by call to __c_mzero8 63, Barrier Loop not vectorized/parallelized: too deeply nested 65, Parallel loop activated with static block schedule Loop not vectorized: may not be beneficial Unrolled inner loop 4 times Generated 3 prefetches in scalar loop 69, Barrier 70, Parallel loop activated with runtime schedule schedule Loop not vectorized/parallelized: contains call Generated 1 prefetches in scalar loop 71, Generated vector sse code for the loop Generated 2 prefetch instructions for the loop 75, Barrier Parallel region terminated 92, Loop not vectorized/parallelized: contains call $ export OMP_NUM_THREADS=1 $ ./a.out OMP_Wtime resolution: 9.9999999999999995E-007 Elapsed time = 0.3339718699455261 (sec) M = 1000 , N = 1000 , P = 1000 MFLOPS = 5985.534052092637 (5.9GFLOPS) c(10,10) = 244.1990574713752 $ export OMP_NUM_THREADS=2 $ ./a.out OMP_Wtime resolution: 9.9999999999999995E-007 Elapsed time = 0.1942952513694763 (sec) M = 1000 , N = 1000 , P = 1000 MFLOPS = 10288.46554874702 (10.2GFLOPS) c(10,10) = 244.1990574713752 $ export OMP_NUM_THREADS=4 $ ./a.out OMP_Wtime resolution: 9.9999999999999995E-007 Elapsed time = 0.1415630519390106 (sec) M = 1000 , N = 1000 , P = 1000 MFLOPS = 14120.91624629021 (14.1GFLOPS) c(10,10) = 244.1990574713752
C++ での使用例 (LAPACKを使用)、Linux and OS X only
● ソースプログラム例
// LAPACK dgetrs test code #include <iostream> #include <vector> using namespace std; extern "C" void dgetrf_(int *M, int *N, double *A, int *LDA, int *IPIV, int *INFO ); extern "C" void dgetrs_(char *TRANS, int *N, int *NRHS, double *A, int *LDA, int *IPIV, double *B, int *LDB, int *INFO ); int main() { char trans = 'N'; int dim = 3; int info= 3; int LDA = dim; int LDB = dim; int n = 3; int nrhs = 1; // c++11 list initialization vectora { 1, 2, 3, 2, 3, 4, 3, 4, 1 }; vector<double> b { -4, -1, -2 }; int ipiv[3]; std::cout << "compute the LU factorization..." << endl << endl; dgetrf_(&n, &n, & *a.begin(), &LDA, ipiv, &info); dgetrs_(&trans, &n, &nrhs, & *a.begin(), &LDA, ipiv, &*b.begin(), &LDB, &info); std::cout << "Result is :"; std::cout << "{" << " "; int i; for (i=0;i<n;i++) { std::cout << b[i] << " "; } std::cout << "}" << endl << endl; std::cout << "Info flag = " << info << std::endl; return(0); }
● コンパイル・リンク&実行 (マルチスレッド用 -mp オプション付き)
$ pgc++ -w -fastsse main.cpp -std=c++11 -mp -lblas -llapack -pgf90libs $ a.out compute the LU factorization... Result is :{ 11 -9 1 } Info flag = 0
上記のコンパイルの方法において、-mp オプションを付加することにより、スレッド実行モードのモジュールが生成されます。BLAS/LAPACK ライブラリの中で OpenMP 並列対応となっているサブルーチンは、このライブラリ・モジュールの中で自動的に並列実行されます(全てのライブラリ・ルーチンが並列対応とはなっていませんのでご注意ください)。
並列実行での環境変数 OMP_NUM_THREADS を予め、以下のように設定してから実行してください(4スレッドの例)。
$ export OMP_NUM_THREADS=4 $ 実行 ------------------------------------------------------------------------------------ スタックサイズの不足等のエラーがある場合、スタックサイズの指定を行ってください。