本ライブラリルーチンで用いた各反復法アルゴリズムについて紹介する. 以下では,nnの実行列Aを係数行列に持つ連立一次方程式 を解くものとする.ここでは,適当な前処理行列を,初期値ベクトルをとする.
共役勾配法(CG法)は対称行列向けのクリロフ部分空間法である.
安定化双共役勾配法(Bi-CGSTAB)は非対称行列向けのクリロフ部分空間法である.
一般化最小残差法(GMRES(m))は非対称行列向けのクリロフ部分空間法である.リスタート周期m回の反復計算で解が収束しない場合はm回の反復で得られた解を初期値として反復を再開する.PARCELでは直交化手法として古典グラムシュミット法と修正グラムシュミット法が整備されている.
はを要素に持つ上三角行列,はベクトルの最初のi成分からなるベクトルである.
通信削減型一般化最小残差法(CA-GMRES(s,t))は非対称行列向けのクリロフ部分空間法である. GMRES(m)のs回反復に相当する計算を1反復で行う. t回の反復で収束しない場合はt回の反復で得られた近似解を初期解として反復を再開する. m = t sがGMRES(m)のリスタート周期に相当する. 数学的にはCA-GMRES(s,t)とGMRES(m)の収束性は同等であり,通信削減型のQR分解を適用することでGMRES(m)よりも集団通信の回数を削減する. ただし,一度にs本の基底ベクトルを生成するため,sが過大な場合には,丸め誤差によって基底ベクトルの直交性が崩れることでGMRESよりも収束性が悪くなる.PARCELでは基底ベクトルの直交性改善のために単基底に加えてNewton基底が整備されている.
ここで,は単位ベクトル, はのs行s列要素, は反復の過程で得られるヘッセンベルグ行列から求めた固有値である.
はを要素に持つ行列.
はを要素に持つ行列.
一般に反復解法では,となるように前処理行列を選ぶと,収束に必要な反復回数が減少する. アルゴリズムに見られる 「」型の計算は 「 を について近似的に解く」ことに相当する. この近似の精度を上げれば反復回数が減少するが,逆にこの部分の計算のオーバーヘッドが増加する. 並列計算でない場合には,この近似計算に不完全LU 分解を用いることが多いが,並列計算の場合には,前処理計算の並列処理手法が必要となる. 本ライブラリルーチンでは並列前処理法としてポイントヤコビ法,ブロックヤコビ法,加法的シュワルツ法,ヤコビ法を採用している.
前処理行列Kとして係数行列Aの対角成分のみを用いる.不完全LU分解など他の前処理法と比べると効果は小さいが, 点ヤコビ法は並列に処理され,プロセッサ間通信も不要である.
正方行列を下三角行列と上三角行列の積の形に分解することをLU分解と呼ぶ. LU分解は元の行列が疎行列であっても,分解後の行列の零要素位置に値が入る.これはフィルインと呼ばれる. フィルインが発生することでLU分解後の行列が密行列になるためメモリ使用量が増大する問題がある. PARCELではフィルインを考慮しない不完全LU分解(ILU(0))を前処理として採用することでメモリ使用量の増大を防いでいる.
係数行列をその対角行列,下三角行列,上三角行列を用いて と分解する.この,および対角行列 ()を用いて,前処理行列を の形に決定する.ここでは,対角行列は対角成分が一致するように決定する.対角行列の具体的な計算方法を次に示す.
前処理行列K として係数行列A のブロック対角成分をとり,ブロック内で不完全LU 分解を用いる. 各ブロックの境界を係数行列の各PE への分割と一致させることにより,通信が不要となり,完全に並列に処理できる.
ヤコビ前処理は次の反復法により近似的に解く前処理である.1反復内で依存性がないためGPU向けの前処理である.
本ライブラリルーチンで利用可能なQR分解のアルゴリズムについて説明する.
グラムシュミットの直交化によるQR分解.並列性は高いが直交性が悪い.
誤差の低減を目的に古典グラムシュミット法のアルゴリズムを修正したQR分解. 古典グラムシュミット法よりも直交性が高いが集団通信の回数が多い.
コレスキーQRは行列積とコレスキー分解で構成されるQR分解である.演算密度が高く1回の集団通信で計算可能であるが直交性が悪い.
一般に疎行列反復解法のプログラムでは,メモリ節約のため,非零要素についての情報(値,行位置,列位置) のみを格納するデータ構造を採用する.ここでは,本ライブラリルーチンで用いている疎行列格納法について説明する.
CRS形式(圧縮行格納形式)は,非ゼロ要素を行方向に圧縮した後,列方向にデータを並べて格納する方法である. 非ゼロ要素の列位置・値ともに全体を1 次元配列に格納する.そのため.1次元配列中での各行の開始位置を記録したポインタテーブルを用いる. 並列処理の場合には列方向に行列を分割して格納する. 列方向のポインターの並びは昇順を想定している.
行列の非ゼロ要素 ::
ポインタテーブル ::
非ゼロ要素の列番号 ::
行列の非ゼロ要素 ::
ポインタテーブル ::
非ゼロ要素の列番号 ::
行列の非ゼロ要素 ::
ポインタテーブル ::
非ゼロ要素の列番号 ::
SYCL版PARCELの導入方法について説明する.
ヘッダーファイル./Include/parcel_sycl.hppをインクルードしてSYCL対応コンパイラでコンパイルすれば利用可能である. 以下では SGI8600 (Intel Xeon Gold 6248R + NVIDIA V100) における例を示す.
module purge
module load gnu/9.5.0
module load openmpi/cur
. ~/spack/share/spack/setup-env.sh
spack load hipsycl
export sycl_root=`spack location -i hipsycl`
export llvm_root=`spack location -i llvm`
export LD_LIBRARY_PATH=$sycl_root/lib/:$llvm_root/lib/:${LD_LIBRARY_PATH}
export MPICXX_CXX=${compiler_base}
export OMPI_CXX=${compiler_base}
src_name=sample.cpp
compiler_base="acpp"
compiler_option=" -O3 --acpp-targets=omp -mlong-double-128 -march=native -mtune=native -Wpass-failed=transform-warning"
compiler=mpicxx
${compiler} ${compiler_option} -o a.out ${src_name}
module purge
module load gnu/9.5.0
module load cuda/12.6
module load openmpi/cur
. ~/spack/share/spack/setup-env.sh
spack load hipsycl
export sycl_root=`spack location -i hipsycl`
export llvm_root=`spack location -i llvm`
export cuda_root=/home/app/cuda/12.6
export ACPP_CUDA_PATH=$cuda_root
export LD_LIBRARY_PATH=$sycl_root/lib/:$llvm_root/lib/:$cuda_root/lib64:${LD_LIBRARY_PATH}
export MPICXX_CXX=${compiler_base}
export OMPI_CXX=${compiler_base}
src_name=sample.cpp
compiler_base="acpp"
compiler_option=" -O3 --acpp-targets=cuda:sm_70 -march=native -mtune=native -v"
compiler=mpicxx
${compiler} ${compiler_option} -o a.out ${src_name}
ソースコードからインストールする場合の詳細は下記のページを参照.
https://github.com/AdaptiveCpp/AdaptiveCpp
spackによるインストールも可能である. 以下では SGI8600 (Intel Xeon Gold 6248R + NVIDIA V100) における例を示す.
module purge module load gnu/9.5.0 module load openmpi/cur . ~/spack/share/spack/setup-env.sh spack compiler find spack external find spack install llvm@18 spack install hipsycl % llvm@18
富岳やWisteria Odysseyのようにログインノードと計算ノードでCPUアーキテクチャが異なる場合には計算ノード上でインストールを行う.
module purge module load gnu/9.5.0 module load cuda/12.6 module load openmpi/cur . ~/spack/share/spack/setup-env.sh spack compiler find spack external find spack external find cuda spack install llvm@18 spack install hipsycl +cuda % llvm@18
SYCL版PARCELに整備されているクラスについて説明する.
SYCL版PARCELはデータ型として次のデータ型(parceltype)を利用する.
SYCL版PARCEL用MPIコミュニケータクラス.
| 定義 | 引数 |
|---|---|
| parcel::comm(MPI_Comm comm,sycl::queue* q) class parcel_comm; | comm:MPIコミュニケータ q:sycl::queueポインタ |
SYCL版PARCELの疎行列を操作するクラス.
| 定義 | 引数 |
|---|---|
| template< class parceltype > matrix(sycl::queue* q) class parcel_matrix; |
parceltype:CRS行列のデータ精度 q:sycl::queueポインタ |
| 関数名 | 説明 | 引数 |
|---|---|---|
| set_crsMat<T>(comm,nstart,nend,n,nnz,rowptr,crsCol,mem) | MPI並列用CRS形式の行列を定義 | T:浮動小数点型 parcel::comm* comm:SYCL版PARCEL用MPIコミュニケータ PARCEL_INT nstart:各プロセスが担当する行列の開始行 PARCEL_INT nend:各プロセスが担当する行列の終了行 size_t n:各プロセスが担当するベクトルの大きさ size_t nnz:各プロセスが担当する係数行列の非零要素数 PARCEL_INT* rowptr:CRS 形式のポインタテーブル PARCEL_INT* crsCol:CRS 形式に格納された分割行列の非零要素の列番号 T* mem:係数行列の非零要素 |
SYCL版PARCELのベクトルを操作するクラス.
| 定義 | 引数 |
|---|---|
| template< class parceltype > vector(size_t n,sycl::queue* q) class parcel_vector; |
parceltype : ベクトルのデータ精度 n:配列要素数 q:sycl::queueポインタ |
| 関数名 | 説明 | 引数 |
|---|---|---|
| queue() | sycl::queueポインタを取得する | |
| resize(n,q) | 配列要素数とsycl::queueを変更する | size_t n:配列要素数 sycl::queue* q:sycl::queueポインタ |
| setValue<T>(mem) | 配列要素をコピーする | T:浮動小数点型 T* mem:配列要素ポインタ |
| setValue_hi(mem) | double-double型の上位配列要素に配列要素をコピーする | double* mem:配列要素ポインタ |
| setValue_lo(mem) | double-double型の下位配列要素に配列要素をコピーする | double* mem:配列要素ポインタ |
| getValue<T>(mem) | 配列要素を取得する | T:浮動小数点型 T* mem:配列要素ポインタ |
| getValue<T>(mem_hi,mem_lo) | double-double型の配列要素を取得する | T:浮動小数点型 T* mem_hi:double-double型の上位配列要素ポインタ T* mem_lo:double-double型の下位配列要素ポインタ |
| getValue_hi<T>(T* mem) | double-double型の上位配列要素を取得する | T:浮動小数点型 T* mem:配列要素ポインタ |
| getValue_lo<T>(T* mem) | double-double型の下位配列要素を取得する | T:浮動小数点型 T* mem:配列要素ポインタ |
| size() | 配列要素数を取得する | |
| data() | 配列の先頭ポインタを取得する | |
| data_hi() | double-double型の上位配列の先頭ポインタを取得する | |
| data_lo() | double-double型の下位配列の先頭ポインタを取得する |
前処理付き共役勾配法クラス.
| 定義 | 引数 |
|---|---|
| template< class Tspmv = parcel_double, class Tprecon = parcel_double, class Taxpy = parcel_double, class Tdot = parcel_double > class pcg; |
parceltype Tspmv:SpMV計算精度 parceltype Tprecon:前処理計算精度 parceltype Taxpy:Axpy計算精度 parceltype Tdot:Dot計算精度 |
| 関数名 | 説明 | 引数 |
|---|---|---|
| solver< Tmat, Tvecx, Tvecb, Tvec, Tprecon_mat, Tprecon_vec >(Mat,x,b) |
共役勾配法を実行 | parceltype Tmat:係数行列データ精度 parceltype Tvecx:解ベクトルデータ精度 parceltype Tvecb:右辺ベクトルデータ精度 parceltype Tvec:クリロフ部分空間法内部データ精度 parceltype Tprecon_mat:前処理行列データ精度 parceltype Tprecon_vec:前処ベクトルデータ精度 parcel::matrix < Tmat > Mat:CRS行列 parcel::vector < Tvecx > x:解ベクトル parcel::vector < Tvecb > b:右辺ベクトル |
| set_precon_algo(algo) | クリロフ部分空間法の前処理を設定 (0:前処理無し,1:ポイントヤコビ法,2:ブロックヤコビ法(CPU向け実装),4:ヤコビ法(GPU向け実装) |
PARCEL_INT algo |
| set_jacobi(iter) | ヤコビ法の反復回数を設定. | PARCEL_INT iter |
| set_blockjacobi(nblock) | ブロックヤコビ法のブロック数を指定 | PARCEL_INT nblock |
| set_scaling_matrix(flag) | 前処理行列のスケーリング有無 (false:無,true:有) |
bool flag |
| set_scaling_vector(flag) | 前処理ベクトルのスケーリング有無 (false:無,true:有) |
bool flag |
| set_tolerance(tol) | 相対残差ノルムの収束判定値を設定 | double tol |
| set_max_iteration(itr) | クリロフ部分空間法の最大反復回数を設定 | PARCEL_INT itr |
前処理付安定化双共役勾配法クラス.
| 定義 | 引数 |
|---|---|
| template< classTspmv = parcel_double, classTprecon = parcel_double, classTaxpy = parcel_double, classTdot = parcel_double > class pbicgstab; |
parceltype Tspmv:SpMV計算精度 parceltype Tprecon:前処理計算精度 parceltype Taxpy:Axpy計算精度 parceltype Tdot:Dot計算精度 |
| 関数名 | 説明 | 引数 |
|---|---|---|
| solver< Tmat, Tvecx, Tvecb, Tvec, Tprecon_mat, Tprecon_vec >(Mat,x,b) |
前処理付安定化双共役勾配法を実行 | parceltype Tmat:係数行列データ精度 parceltype Tvecx:解ベクトルデータ精度 parceltype Tvecb:右辺ベクトルデータ精度 parceltype Tvec:クリロフ部分空間法内部データ精度 parceltype Tprecon_mat:前処理行列データ精度 parceltype Tprecon_vec:前処ベクトルデータ精度 parcel::matrix < Tmat > Mat:CRS行列 parcel::vector < Tvecx > x:解ベクトル parcel::vector < Tvecb > b:右辺ベクトル |
| set_precon_algo(algo) | クリロフ部分空間法の前処理を設定 (0:前処理無し,1:ポイントヤコビ法,2:ブロックヤコビ法(CPU向け実装),4:ヤコビ法(GPU向け実装) |
PARCEL_INT algo |
| set_jacobi(iter) | ヤコビ法の反復回数を設定. | PARCEL_INT iter |
| set_blockjacobi(nblock) | ブロックヤコビ法のブロック数を指定 | PARCEL_INT nblock |
| set_scaling_matrix(flag) | 前処理行列のスケーリング有無 (false:無,true:有) |
bool flag |
| set_scaling_vector(flag) | 前処理ベクトルのスケーリング有無 (false:無,true:有) |
bool flag |
| set_tolerance(tol) | 相対残差ノルムの収束判定値を設定 | double tol |
| set_max_iteration(itr) | クリロフ部分空間法の最大反復回数を設定 | PARCEL_INT itr |
前処理付一般化最小残差法クラス.
| 定義 | 引数 |
|---|---|
| template< classTspmv = parcel_double, classTprecon = parcel_double, classTaxpy = parcel_double, classTdot = parcel_double > class pgmres; |
parceltype Tspmv SpMV:計算精度 parceltype Tprecon:前処理計算精度 parceltype Taxpy:Axpy計算精度 parceltype Tdot:Dot計算精度 |
| 関数名 | 説明 | 引数 |
|---|---|---|
| solver< Tmat, Tvecx, Tvecb, Tvec, Tprecon_mat, Tprecon_vec, Tgs, Thess_mat >(Mat,x,b) |
前処理付一般化最小残差法を実行 | parceltype Tmat:係数行列データ精度 parceltype Tvecx:解ベクトルデータ精度 parceltype Tvecb:右辺ベクトルデータ精度 parceltype Tvec:クリロフ部分空間法内部データ精度 parceltype Tprecon_mat:前処理行列データ精度 parceltype Tprecon_vec:前処ベクトルデータ精度 parceltype Tgs:グラムシュミット直交化精度 parceltype Thess_mat:ヘッセンベルグ行列データ精度 parcel::matrix < Tmat > Mat:CRS行列 parcel::vector < Tvecx > x:解ベクトル parcel::vector < Tvecb > b:右辺ベクトル |
| set_precon_algo(algo) | クリロフ部分空間法の前処理を設定 (0:前処理無し,1:ポイントヤコビ法,2:ブロックヤコビ法(CPU向け実装),4:ヤコビ法(GPU向け実装) |
PARCEL_INT algo |
| set_jacobi(iter) | ヤコビ法の反復回数を設定. | PARCEL_INT iter |
| set_blockjacobi(nblock) | ブロックヤコビ法のブロック数を指定 | PARCEL_INT nblock |
| set_scaling_matrix(flag) | 前処理行列のスケーリング有無 (false:無,true:有) |
bool flag |
| set_scaling_vector(flag) | 前処理ベクトルのスケーリング有無 (false:無,true:有) |
bool flag |
| set_tolerance(tol) | 相対残差ノルムの収束判定値を設定 | double tol |
| set_max_iteration(itr) | クリロフ部分空間法の最大反復回数を設定 | PARCEL_INT itr |
前処理付き通信削減型一般化最小残差法クラス.
| 定義 | 引数 |
|---|---|
| template< class Tspmv = parcel_double, class Tprecon = parcel_double, class Taxpy = parcel_double, class Tdot = parcel_double > class pcagmres; |
parceltype Tspmv:SpMV計算精度 parceltype Tprecon:前処理計算精度 parceltype Taxpy:Axpy計算精度 parceltype Tdot:Dot計算精度 |
| 関数名 | 説明 | 引数 |
|---|---|---|
| solver< Tmat, Tvecx, Tvecb, Tvec, Tprecon_mat, Tprecon_vec, Tbasis, TQR, Thess_mat >(Mat,x,b) |
通信削減型一般化最小残差法を実行 | parceltype Tmat:係数行列データ精度 parceltype Tvecx:解ベクトルデータ精度 parceltype Tvecb:右辺ベクトルデータ精度 parceltype Tvec:クリロフ部分空間法内部データ精度 parceltype Tprecon_mat:前処理行列データ精度 parceltype Tprecon_vec:前処ベクトルデータ精度 parceltype Tbasis:基底ベクトルデータ精度 parceltype TQR:QR分解計算精度 parceltype Thess_mat:ヘッセンベルグ行列データ精度 parcel::matrix < Tmat > Mat:CRS行列 parcel::vector < Tvecx > x:解ベクトル parcel::vector < Tvecb > b:右辺ベクトル |
| set_precon_algo(algo) | クリロフ部分空間法の前処理を設定 (0:前処理無し,1:ポイントヤコビ法,2:ブロックヤコビ法(CPU向け実装),4:ヤコビ法(GPU向け実装) |
PARCEL_INT algo |
| set_jacobi(iter) | ヤコビ法の反復回数を設定. | PARCEL_INT iter |
| set_blockjacobi(nblock) | ブロックヤコビ法のブロック数を指定 | PARCEL_INT nblock |
| set_scaling_matrix(flag) | 前処理行列のスケーリング有無 (false:無,true:有) |
bool flag |
| set_scaling_vector(flag) | 前処理ベクトルのスケーリング有無 (false:無,true:有) |
bool flag |
| set_tolerance(tol) | 相対残差ノルムの収束判定値を設定 | double tol |
| set_max_iteration(itr) | クリロフ部分空間法の最大反復回数を設定 | PARCEL_INT itr |
SYCL版PARCELのサンプルプログラムを示す.
#include <mpi.h>
#include "./Include/parcel_sycl.hpp"
#include "./parcel_default.hpp"
void run_parcel_sycl_main(
MPI_Comm mpi_comm_c, // In:MPIコミュニケータ
int n, // In:CRS行列行数
int nnz, // In:CRS行列非零要素数
double* crsA, // In:CRS行列要素
int* crsCol, // In:CRS形式列番号
int* crsRow_ptr, // In:CRS行列ポインタテーブル
double* vecx, // In:初期ベクトル,out:解ベクトル
double* vecb // In:右辺ベクトル
) {
sycl::device device;
sycl::property::queue::in_order property;
sycl::queue q{device,property};
q = sycl::default_selector{};
parcel::comm comm(mpi_comm_c,&q);
int myrank = comm.mpi_rank();
int nprocess = comm.mpi_size();
if(myrank == 0)std::cout << q.get_device().get_info() << std::endl;
parcel::matrix parcel_matrix(&q);
PARCEL_INT nlocal = n;
PARCEL_INT nstart = nlocal*myrank;
PARCEL_INT nend = nlocal*(myrank+1)-1;
q.wait();
parcel_matrix.set_crsMat(
&comm,nstart,nend,
n,nnz,
crsRow_ptr,
crsCol,
crsA
);
q.wait();
parcel::vector vx(n,&q);
parcel::vector vb(n,&q);
vx.setValue(vecx);
vb.setValue(vecb);
parcel::krylov::pcg<
parcel_solver_calc_type,
parcel_solver_calc_precon_type,
parcel_solver_calc_type,
parcel_solver_calc_type
> solver;
solver.set_tolerance( 1.0e-9 );
solver.set_max_iteration( MAX_ITERATION );
PARCEL_INT precon_algo = parcel_solver_precon_algo;
switch (precon_algo) {
case parcel::PRECON_NONE:
// none
solver.set_precon_algo(parcel::PRECON_NONE);
break;
case parcel::PRECON_POINTJACOBI:
// point jacobi precon
solver.set_precon_algo(parcel::PRECON_POINTJACOBI);
break;
case parcel::PRECON_BLOCKJACOBI:
// block jacobi precon
solver.set_precon_algo(parcel::PRECON_BLOCKJACOBI);
solver.set_scaling_matrix(true);
solver.set_scaling_vector(true);
solver.set_blockjacobi(BLOCKJACOBI_BLOCK);
break;
case parcel::PRECON_JACOBI:
// jacobi precon
solver.set_precon_algo(parcel::PRECON_JACOBI);
solver.set_scaling_matrix(true);
solver.set_scaling_vector(true);
solver.set_jacobi(JACOBI_ITER);
break;
}
q.wait();
solver.solver<
parcel_solver_data_type,
parcel_solver_data_type,
parcel_solver_data_type,
parcel_solver_data_type,
parcel_solver_data_precon_mat_type,
parcel_solver_data_precon_vec_type
>(parcel_matrix,vx,vb);
vx.getValue(vecx); q.wait();
q.wait();
return ;
}
extern "C" {
void run_parcel_sycl_f(
int* mpi_comm_f,
int n, int nnz,
double* crsA,
int* crsCol,
int* crsRow_ptr,
double* vecx,
double* vecb
) {
MPI_Comm mpi_comm_c = MPI_Comm_f2c(mpi_comm_f[0]);
run_parcel_sycl_main(
mpi_comm_c,
n, nnz,
crsA,
crsCol,
crsRow_ptr,
vecx,
vecb );
return ;
}
}
make_poisson3d_crs_get_nnz,make_poisson3d_crsは行列分割に対応したCRS形式の行列を生成するサブルーチンとする.
module parcel_sycl_wrapper interface subroutine run_parcel_sycl( & mpi_comm_f, & n,nnz, & crsA, & crsCol, & crsRow_ptr, & vecx, & vecb & ) & bind(c,name="run_parcel_sycl_f") implicit none integer mpi_comm_f integer(kind=4),value :: n integer(kind=4),value :: nnz real*8 crsA(*) integer(kind=4) crsCol(*) integer(kind=4) crsRow_ptr(*) real*8 vecx(*) real*8 vecb(*) end subroutine run_parcel_sycl end interface contains end module parcel_sycl_wrapper program main use mpi use parcel_sycl_wrapper implicit none integer(kind=4) nx,ny,nz integer(kind=4) nx0,ny0,nz0 integer(kind=4),parameter :: gnx = 16 integer(kind=4),parameter :: gny = 16 integer(kind=4),parameter :: gnz = 16 integer(kind=4) gn,n integer(kind=4) nnz integer(kind=4) istart real*8,allocatable :: crsA(:) integer(kind=4),allocatable :: crsCol(:) integer(kind=4),allocatable :: crsRow_ptr(:) real*8,allocatable :: vecx(:) real*8,allocatable :: vecb(:) integer ierr integer npes,myrank integer i integer mpi_comm_f mpi_comm_f = MPI_COMM_WORLD ! MPI Init call MPI_Init(ierr) call MPI_Comm_size(mpi_comm_f,npes,ierr) call MPI_Comm_rank(mpi_comm_f,myrank,ierr) nx = gnx ny = gny nz = gnz/npes nx0 = 1 ny0 = 1 nz0 = 1 + nz*myrank gn = gnx*gny*gnz n = nx * ny * nz istart = 1+n*myrank call make_poisson3d_crs_get_nnz( & nx,ny,nz, & nx0,ny0,nz0,& gnx,gny,gnz,& nnz, & istart) allocate(crsA(nnz)) allocate(crsCol(nnz)) allocate(crsRow_ptr(n+1)) allocate(vecx(n)) allocate(vecb(n)) vecx = 0.0d0 vecb = 1.0d0 call make_poisson3d_crs( & nx,ny,nz, & nx0,ny0,nz0,& gnx,gny,gnz,& crsA,crsCol,crsRow_ptr,n,nnz, & istart) call run_parcel_sycl( & mpi_comm_f, & n,nnz, & crsA, & crsCol, & crsRow_ptr, & vecx, & vecb & ) deallocate(crsA) deallocate(crsCol) deallocate(crsRow_ptr) deallocate(vecx) deallocate(vecb) call MPI_Finalize(ierr); end program main
extern "C" {
void run_parcel_sycl_c(
MPI_Comm mpi_comm_c,
int n, int nnz,
double* crsA,
int* crsCol,
int* crsRow_ptr,
double* vecx,
double* vecb
) {
run_parcel_sycl_main(
mpi_comm_c,
n, nnz,
crsA,
crsCol,
crsRow_ptr,
vecx,
vecb );
return ;
}
}
make_poisson3d_crs_get_nnz_,make_poisson3d_crs_は行列分割に対応したCRS形式の行列を生成する関数とする.
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
extern void make_poisson3d_crs_get_nnz_(
int* nx,
int* ny,
int* nz,
int* nx0,
int* ny0,
int* nz0,
int* gnx,
int* gny,
int* gnz,
int* nnz,
int* istart);
extern void make_poisson3d_crs_(
int* nx,
int* ny,
int* nz,
int* nx0,
int* ny0,
int* nz0,
int* gnx,
int* gny,
int* gnz,
double* crsA,
int* crsCol,
int* crsRow_ptr,
int* n,
int* nnz0,
int* istart);
extern void run_parcel_sycl_c(
MPI_Comm mpi_comm_c,
int n, int nnz,
double* crsA,
int* crsCol,
int* crsRow_ptr,
double* vecx,
double* vecb
);
int main(int argc, char* argv[]) {
int gnx = 16;
int gny = 16;
int gnz = 16;
MPI_Init(&argc, &argv);
MPI_Comm mpi_comm_c = MPI_COMM_WORLD;
int npes,myrank;
MPI_Comm_size(MPI_COMM_WORLD,&npes);
MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
int nx = gnx;
int ny = gny;
int nz = gnz/npes;
int nx0 = 1;
int ny0 = 1 ;
int nz0 = 1 + nz*myrank;
int gn = gnx*gny*gnz;
int n = nx * ny * nz;
int istart = 1+n*myrank;
int nnz;
make_poisson3d_crs_get_nnz_(
&nx,&ny,&nz,
&nx0,&ny0,&nz0,
&gnx,&gny,&gnz,
&nnz,
&istart);
double* crsA = (double*)malloc(sizeof(double)*nnz);
int* crsCol = (int*)malloc(sizeof(int)*nnz);
int* crsRow_ptr = (int*)malloc(sizeof(int)*(n+1));
double* vecx = (double*)malloc(sizeof(double)*n);
double* vecb = (double*)malloc(sizeof(double)*n);
make_poisson3d_crs_(
&nx,&ny,&nz,
&nx0,&ny0,&nz0,
&gnx,&gny,&gnz,
crsA,crsCol,crsRow_ptr,
&n,&nnz,
&istart);
for(int i = 0;i<n;i++){
vecx[i] = 0.0;
vecb[i] = 1.0;
}
run_parcel_sycl_c(
mpi_comm_c,
n,nnz,
crsA,
crsCol,
crsRow_ptr,
vecx,
vecb
);
free(crsA);
free(crsCol);
free(crsRow_ptr);
free(vecx);
free(vecb);
MPI_Finalize();
return 0;
}
[1]R. Barret, M. Berry, T. F. Chan, et al., “Templates for the Solution of Linear Systems: Building Blocks for Iterative Methods”, SIAM(1994)
[2]M. Hoemmen, “Communication-avoiding Krylov subspace methods”. Ph.D.thesis, University of California, Berkeley(2010)
[3]Y. Idomura, T. Ina, A. Mayumi, et al., “Application of a communication-avoiding generalized minimal residual method to a gyrokinetic five dimensional eulerian code on many core platforms”,ScalA 17:8th Workshop on Latest Advances in Scalable Algorithms for Large Scale Systems, pp.1-8, (2017).
[4] A. Stathopoulos, K. Wu, “A block orthogonalization procedure with constant synchronization requirements”. SIAM J. Sci. Comput. 23, 2165–2182 (2002)