OCIチュートリアル
タグ検索 トップページへ戻る

線形代数演算ライブラリインストール・利用方法

タグ: #hpc

0. 概要

BLAS は、ベクトルや行列の基本的な線形代数演算を行うサブルーチンを集めたライブラリで、インターフェース互換を維持してこれを高速化したものが OpenBLAS です。
このため、 BLAS 用に作成されたプログラムであれば、再コンパイル・リンクを行うだけでソースプログラムを修正することなく OpenBLAS を使用してアプリケーションを高速化することが可能です。

また OpenBLAS は、pthreadを使用するスレッド並列実行に対応しており、 BLAS のサブルーチンを並列化で更に高速実行することが可能です。

以降では、 BLASOpenBLAS をHPCワークロード向け Intel Ice Lake プロセッサを搭載するベアメタルシェイプ BM.Optimized3.36 にインストール・セットアップし、 BLAS の倍精度行列・行列積サブルーチン(DGEMM)を使用するFortranのサンプルプログラムをコンパイル後、 BLAS とスレッド数を変化させたときの OpenBLAS の実行性能を比較・検証します。
この性能比較詳細は、 3-0. 概要 に記載していますが、これを抜粋している下表からも性能は圧倒的に OpenBLAS が良いことがわかり、特に本テクニカルTipsで使用している BM.Optimized3.36 の全コアを利用して線形代数演算を実行するようなワークロードでは、 OpenBLAS を利用するメリットが大きいと言えます。

ライブラリ スレッド数 速度向上比
BLAS 1 1
OpenBLAS 1 34.6
36 742.7

本テクニカルTipsでは、各ソフトウェアに以下のバージョンを使用しています。

なお、本テクニカルTipsで使用するインスタンスを作成する手順は、 OCIチュートリアルその3 - インスタンスを作成する を参照してください。
またこのインスタンスは、スレッド並列実行時の性能を最大化するためSMTを無効化して作成しますが、BIOS設定でこれを適用する場合は OCI HPCパフォーマンス関連情報パフォーマンスに関連するベアメタルインスタンスのBIOS設定方法 を参照してください。

1. BLAS・OpenBLASインストール・セットアップ

本章は、 BLASOpenBLAS をインストールします。

以下コマンドをopcユーザで実行し、 BLAS をインストールします。

$ sudo yum-config-manager --enable ol9_codeready_builder
$ sudo dnf install -y blas blas-devel

次に、以下コマンドをopcユーザで実行し、 OpenBLAS/opt/OpenBLAS ディレクトリにインストールします。

$ mkdir ~/`hostname` && cd ~/`hostname` && wget https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.30/OpenBLAS-0.3.30.tar.gz
$ tar -xvf ./OpenBLAS-0.3.30.tar.gz
$ cd OpenBLAS-0.3.30 && make -j 36 TARGET=SKYLAKEX && sudo make install TARGET=SKYLAKEX

2. サンプルプログラムコンパイル

本章は、 BLAS の倍精度行列・行列積サブルーチン(DGEMM)を使用するFortranのサンプルプログラムを BLASOpenBLAS を使用してコンパイルし、実行バイナリを作成します。

以下のファイルを dgemm_timer.f90 で作成します。
このFortranプログラムは、サイズが5,000x5,000の正方行列を乱数で初期化してその行列積をサブルーチンdgemmを使用して求め、その結果を標準出力に出力します。またdgemmの所要時間をタイマーで計測し、これを標準エラー出力に出力します。

program main
    implicit none
    external dgemm
    integer*8 i, j, l, m, n
    integer*8 lda, ldb, ldc
    integer t1, t2, t_rate, t_max, diff
    double precision, allocatable :: a(:,:), b(:,:), c(:,:)
    double precision alpha, beta

    l=5000; m=l; n=l
    lda=l; ldb=n; ldc=l
    alpha=1.0; beta=0.0
    allocate(a(lda,n), b(ldb,m), c(ldc,m))
    call random_number(a)
    call random_number(b)
    a = a - 0.5d0
    b = b - 0.5d0

    call system_clock(t1)
    call dgemm('n','n',l,m,n,alpha,a,lda,b,ldb,beta,c,ldc)
    call system_clock(t2, t_rate, t_max)

    if ( t2 < t1 ) then
        diff = (t_max - t1) + t2 + 1
    else
        diff = t2 - t1
    endif
    write(0,'(a,f10.3)') "Elapse time(sec):", diff/dble(t_rate)

    do i = lbound(c,1), ubound(c,1)
        write(*,*) (c(i,j), j=lbound(c,2), ubound(c,2))
    end do
end program main

次に、以下コマンドをopcユーザで実行し、 BLAS を使用してサンプルプログラムをコンパイルします。

$ gfortran -O3 -lblas -o blas ./dgemm_timer.f90

次に、以下コマンドをopcユーザで実行し、 OpenBLAS を使用してサンプルプログラムをコンパイルします。

$ gfortran -O3 -L/opt/OpenBLAS/lib -lopenblas -o openblas ./dgemm_timer.f90

3. サンプルプログラム実行

3-0. 概要

本章は、先に作成した実行バイナリを使用し、 BLASOpenBLAS を使用するサンプルプログラムをそれぞれ実行、その性能を比較します。

下表は、この実行結果をまとめています。

No. ライブラリ スレッド数 所要時間 速度向上比
(※1)
並列化効率
(※1)
GFLOPS
(※2, 3)
1 BLAS 1 87.637 秒 0.029 - 2.9
2 OpenBLAS 1 2.530 秒 1 - 99.1
3 2 1.285 秒 1.969 98.4 % 195.1
4 4 0.650 秒 3.892 97.3 % 385.7
5 8 0.339 秒 7.463 93.3 % 739.5
6 16 0.178 秒 14.213 88.8 % 1,408.4
7 32 0.128 秒 19.766 61.8 % 1,958.6
8 36 0.118 秒 21.441 59.6 % 2,124.6

※1)No.2のテストケースをベースに算出しています。
※2)算出に必要な浮動小数点演算数( 250.7 GFLOP )は、本サンプルプログラムのdgemm部分を PAPI で計測して求めています。
※3)BM.Optimized3.36 の倍精度浮動小数点演算の理論性能は、ベースクロックの3.0GHz動作時でコア当たり 96 GFLOPS 、ノード当たり 3,456 GFLOPS です。

3-1. BLASを使用するサンプルプログラム実行

以下コマンドをopcユーザで実行し、 BLAS 版実行バイナリでdgemmの所要時間を計測します。

$ ./blas > /dev/null
Elapse time(sec):    87.637
$

3-2. OpenBLASを使用するサンプルプログラム実行

以下コマンドをopcユーザで実行し、 OpenBLAS 版実行バイナリでdgemmの所要時間を計測します。
ここでは、環境変数 OMP_NUM_THREADS の値を BM.Optimized3.36 の搭載コア数(36)の範囲で変化させて、その所要時間の変化を確認しています。なお、環境変数 OMP_NUM_THREADS の指定が無い場合は、実行するインスタンスの搭載コア数と同じスレッド数で実行します。

$ export LD_LIBRARY_PATH=/opt/OpenBLAS/lib:$LD_LIBRARY_PATH
$ for nt in `echo 1 2 4 8 16 32 36`; do echo $nt; export OMP_NUM_THREADS=$nt; ./openblas > /dev/null; done
1
Elapse time(sec):     2.530
2
Elapse time(sec):     1.285
4
Elapse time(sec):     0.650
8
Elapse time(sec):     0.339
16
Elapse time(sec):     0.178
32
Elapse time(sec):     0.128
36
Elapse time(sec):     0.118
$