実行
並列実行
NLCPyを使用するPythonスクリプトは、Vector Engine(VE)でマルチスレッド化することにより、性能を発揮します。並列スレッドのデフォルト数は、実行時に環境変数 VE_OMP_NUM_THREADS
で指定できます。 VE_OMP_NUM_THREADS
が未定義であるか、値が無効な場合、システムで使用可能なCPUコアの最大数が設定されます。
例を以下に示します。
対話モード:
$ VE_OMP_NUM_THREADS=4 python >>> import nlcpy
後続の計算は、VE上の4つの並列スレッドによって実行されます。
非対話モード:
$ VE_OMP_NUM_THREADS=4 python example.py
example.pyの計算は、VE上の4つの並列スレッドによって実行されます。
VEのノード番号を指定する場合は、次のように環境変数 VE_NODE_NUMBER
を使用する必要があります。
対話モード:
$ VE_NODE_NUMBER=1 VE_OMP_NUM_THREADS=4 python >>> import nlcpy
後続の計算は、VEノード#1の4つの並列スレッドによって実行されます。
非対話モード:
$ VE_NODE_NUMBER=1 VE_OMP_NUM_THREADS=4 python example.py
example.pyの計算は、VEノード#1の4つの並列スレッドによって実行されます。
注釈
1つのVEに対して2つ以上のNLCPyプログラムを実行すると、コンテキストスイッチが発生します。 このような場合、パフォーマンスは大幅に低下します。
複数VEの利用
NLCPyは複数VEを利用するための方法をを2種類提供しています。
-
mpi4py-veは、SX-Aurora TSUBASA用に、Message Passing Interface (MPI)を利用して、プロセス間の通信を実装したPythonライブラリです。MPI通信に利用可能なオブジェクトは
numpy.ndarray
とnlcpy.ndarray
です。mpi4py-veの利用には、NEC MPIのランタイムパッケージが必要な点にご注意ください。詳細は、 mpi4py-ve project をご参照ください。
-
Pythonスクリプトから "with" コンテキストマネージャーを利用することで、実行するVEデバイスを選択することが可能です。
import nlcpy with nlcpy.venode.VE(0): # do something on VE#0 x_ve0 = nlcpy.arange(10) with nlcpy.venode.VE(1): # do something on VE#1 y_ve1 = nlcpy.arange(10) # transfer x_ve0 to VE#1 x_ve1 = nlcpy.venode.transfer_array(x_ve0, nlcpy.venode.VE(1)) with nlcpy.venode.VE(1): # do something on VE#1 z_ve1 = x_ve1 + y_ve1
nlcpy.venode.transfer_array()
は現時点ではVE間の直接転送に対応していない点にご注意ください。言い換えると、VE間のデータ転送はVHを経由する必要があります。もし、大規模なデータを転送する必要がある場合は、mpi4py-veのご利用を推奨します。デフォルトでは、NLCPyは
import nlcpy
が実行されたときに物理VE#0にのみVEプロセスを生成します。他のVEプロセスに関しては、nlcpy.venode.VENode.__enter__()
,nlcpy.venode.VENode.use()
,nlcpy.venode.VENode.apply()
のいずれかが初めて呼び出されたときに生成されます。ここで、VEプロセスの生成には数秒かかる点にご注意ください。もし、import nlcpy
が実行されるときに複数のVEプロセスを生成したい場合は、環境変数VE_NLCPY_NODELIST=0,1,...
を指定することができます。NLCPyはimport nlcpy
実行時に環境変数VE_NLCPY_NODELIST
に指定されたIDに対応する物理VEに対してプロセスを生成します。環境変数
VE_NLCPY_NODELIST
が設定されているとき、nlcpy.venode.VE()
の引数に指定するIDと物理VEのIDは異なる場合があります。環境変数
VE_NLCPY_NODELIST=1,2
を設定した場合のVEデバイスマッピングの例は以下の通りです:$ VE_NLCPY_NODELIST=1,2 python >>> import nlcpy >>> nlcpy.venode.VE(0) <VE node logical_id=0, physical_id=1> >>> nlcpy.venode.VE(1) <VE node logical_id=1, physical_id=2>
数学関数の最適化
環境変数 VE_NLCPY_FAST_MATH
を yes
または YES
に設定すると、NLCPyはVE用に最適化した共有オブジェクト libnlcpy_ve_kernel_fast_math.so
を使用します。デフォルトでは、VE_NLCPY_FAST_MATH
は未設定です。共有オブジェクト libnlcpy_ve_kernel_fast_math.so
は、NEC C/C++コンパイラの以下の最適化オプションを指定してコンパイルされています。
-ffast-math
ベクトル化ループ外でスカラ高速バージョンの数学関数を使用します。
-mno-vector-intrinsic-check
ベクトル化された部分から呼び出された数学関数の引数の値の範囲を実行時に検査しません。このオプションの対象となる数学関数は次のとおりです。acos
,acosh
,asin
,atan
,atan2
,atanh
,cos
,cosh
,cotan
,exp
,exp10
,exp2
,expm1
,log10
,log2
,log
,pow
,sin
,sinh
,sqrt
,tan
,tanh
-freciprocal-math
式
x/y
をx * (1/y)
に変更します。-mvector-power-to-explog
ベクトル化されたループ中の
pow(R1,R2)
の呼び出しをexp(R2*log(R1))
の呼び出しに置き換えることを許可します。powf()
に対しても同様の最適化が適用されます。pow
、powf
で計算した場合に比べて実行時間は短縮されますが、計算結果が誤差レベルで変わることがあります。-mvector-low-precise-divide-function
低精度のベクトル浮動小数点数除算を使用します。通常精度版と比較して高速に処理されますが、除算結果の仮数部に最大1ビットの誤差が含まれることがあります。
これらの最適化は副作用を引き起こします。 たとえば、 nan
または inf
が正しく取得されない場合があります。
VE_NLCPY_FAST_MATH
は次のように設定できます。
対話モード:
$ VE_NLCPY_FAST_MATH=yes python >>> import nlcpy
非対話モード:
$ VE_NLCPY_FAST_MATH=yes python example.py
メモリプールの管理
NLCPyは、事前に確保されたメモリ (メモリプール) を再利用してmallocとfreeの呼び出しを省略することで、VEメモリ確保のオーバーヘッドを削減しています。環境変数 VE_NLCPY_MEMPOOL_SIZE
を設定することで、メモリプールの容量を管理することが可能です。デフォルトの値は1 GB に設定されています。この環境変数の利用方法は、 環境変数 をご参照ください。
この環境変数に1 GB以上の値を設定することで性能改善するケースがあります。ただし、メモリフラグメンテーションの影響でメモリ不足が発生することがあります。