Japan
サイト内の現在位置
NumPy互換数値演算ライブラリNLCPy NLCPy JITコンパイルの使い方
no.0222023.2.171. NLCPy JITコンパイルとは
今回はNLCPy JITコンパイルを使って何ができるのか具体的な例を使って紹介します。簡潔に言えば、JITコンパイルはPythonスクリプトを実行しながらPython以外のコンパイル型言語で書いたソースコードをコンパイルした後に共有ライブラリを作成して、その中に含まれる関数をPythonスクリプトから実行する枠組みを提供するものです。
NLCPyの関数やNLCで用意されていない数値計算処理をFortranやC/C++により関数として記載してコンパイル・共有ライブラリ化します。Pythonスクリプトの中からそれら関数をコールしてベクトルプロセッサへオフロードすることにより高速に処理する流れを自動的に実行する枠組みを提供します。
はじめに、簡単なサンプルコードを使ったJITコンパイル使用例を紹介します。次に、FortranやC/C++のプログラムを使用した例や、コンパイラオプションの指定方法を見ていきます。
2. NLCPy JITコンパイルの使い方
Pythonスクリプト内にCソースコードを併記してJITコンパイルを実施した例がFigure-1です。
入力[2]がCで記載した関数のソースコードです。次の入力[3]で、このソースコードをベクトルエンジンで実行可能にするためコンパイルして共有ライブラリを作成する定義を行います。コンパイルにはベクトルエンジン専用コンパイラnccが使われます。
作成された共有ライブラリの関数をPythonスクリプトで実行するために、入力[4]で関数の定義を行って関数への引数を指定します。この例では3つの64bit倍精度浮動小数点数型と1つの32bit整数型が関数への引数です。
最後に入力[5]で、NLCPyで定義した3つの配列'x','y','z'と配列長を関数've_add'に送り、ベクトルエンジンで処理します。
from nlcpy import ve_types
import nlcpy
# Cソースコード
c_src=r'''
int ve_add(double *px, double *py, double *pz, int n) {
#pragma omp parallel for
for (int i = 0; i < n; i++) pz[i] = px[i] + py[i];
return 0;
}
'''
# コンパイルと共有ライブラリ作成
ve_lib = nlcpy.jit.CustomVELibrary(code=c_src)
# 関数の定義
ve_add = ve_lib.get_function(
've_add',
args_type=(ve_types.uint64, ve_types.uint64, ve_types.uint64, ve_types.int32),
ret_type=ve_types.int32
)
x = nlcpy.arange(10., dtype='f8')
y = nlcpy.arange(10., dtype='f8')
z = nlcpy.empty(10, dtype='f8')
# 関数呼び出し
ret = ve_add(x.ve_adr, y.ve_adr, z.ve_adr, z.size, sync=True)
print(z)
[ 0. 2. 4. 6. 8. 10. 12. 14. 16. 18.]
Figure-1
Pythonスクリプトの中にソースコードを直接記載するだけでなく、別に用意したソースコードをPythonスクリプトから読み込んだ後に共有ライブラリ化する使い方があります。
Figure-2の例では、ファイル名've_add.c'というソースコードをあらかじめ作成しておき、Pythonスクリプトでこれを読み込んでいます。入力[2]の1-3行でソースファイルの呼出し、5-10行でコンパイルを実施します。
この例ではコンパイルの際に、ftrace=True、compiler='/opt/nec/ve/bin/ncc'などFTRACE機能出力や使用するコンパイラの指定などのオプションを指定しています。コンパイラオプションはソースコードをPythonスクリプトに直接記載する場合も同様に指定することができます。
Figure-1、2どちらの例においても、ソースコードのコンパイル後に.so拡張子を持った共有ライブラリが指定ディレクトリに作成されます(Figure-3)。