set_arg関数はkernelの特定の引数に対して引数値を設定。
詳しくは「表:clSetKernelArg」(Table B.81, “表:clSetKernelArg”)を参照ください。
set_arg(self, index, #(1) arg) #(2)
引数の添字(インデックス)を指定。カーネルが宣言している引数の数をnとした場合、左端の引数を0で始めてn - 1 までの添字でカーネルの引数の番号を指定。 | |
indexで指定した引数に、カーネルの引数値として渡したいメモリオブジェクトまたはデータを指定。 |
引数の設計する際には、メモリ領域の種類(private, local, global)、どれだけのバイトサイズを割り当てるか、どのデータ型というように、カーネル関数側で決めうちしておかないと混乱します。
以下の項目では、最も初心者がはまる傾向があるメモリ領域の種類を見てみます。
private修飾子を付けた引数はプライベート引数となります。最もシンプルなプライベート引数の宣言は以下のようにします。
__kernel void helloworld(uint p_num) { }
つまりプライベート引数は既定の設定のため、メモリ空間についての指定は不要となります。次に実装をしてみましょう。
import pyopencl as cl import numpy as np p_program = cl.Program(ctx, """ __kernel void helloworld(__private uint p_num) { printf("My private number: %u\\n", p_num); } """).build()
これに対応したclSetKernelArg関数を考えてみましょう。ここではuintに対応するホストAPIの型として、cl_uintで変数を宣言します。
import pyopencl as cl import numpy as np num = np.int32(100) #(1) p_kernel = cl.Kernel(p_program, name="helloworld") p_kernel.set_arg(0, num) cl.enqueue_task(queue, p_kernel)
numpy |
出力.
My private number: 100
結果は100が表示されました。
ローカル引数を宣言する際はポインタにします。
__kernel void helloworld(__local uint* l_num) { }
ローカルメモリ空間内に割り当てる引数はホストAPIのLocalMemoryを使ってカーネル関数に渡します。
class pyopencl.LocalMemory(size)
sizeはローカルメモリで使う要素数を指定します。
kernel.set_arg(0, cl.LocalMemory(16))
このようにバッファオブジェクトを使わず明示的にローカルメモリとカーネルの引数に設定します。
例えばカーネル関数を以下のように設定した場合の挙動を見てみましょう。
import pyopencl as cl import numpy as np program = cl.Program(ctx, """ __kernel void helloworld(__local uint* loc) { loc = 100; printf("My Local Number: %u\\n", loc); } """).build()
int型のローカルメモリ空間に100を設定して、それを出力します。
My Local Number: 100
カーネル関数内で初期化した通りの100が表示されます。
ローカル引数はホストAPIでNULLと設定します。ホストAPIからのデータ初期化ではなく、カーネル内で初期化をします。
グローバル引数はグローバルメモリ空間(ヒープ領域に該当)に割り当てられるため、バッファオブジェクトを生成します。そのためカーネル関数内では常にポインタで宣言します。
g_program = cl.Program(ctx, """ __kernel void helloworld(__global float* g_mat) { printf("Accessing mat[3]: %#f\\n", g_mat[3]); } """).build()
このカーネル関数に対応したホストAPIは以下のようにします。
ary = np.arange(16).astype(np.float32) ary_mem = cl.Buffer(ctx, cl.mem_flags.USE_HOST_PTR, hostbuf=ary) # g_programインスタンスの生成 g_kernel = cl.Kernel(g_program, name="helloworld") g_kernel.set_arg(0, ary_mem) cl.enqueue_task(queue, g_kernel)
グローバルメモリを使った引数を指定する際には、バッファオブジェクト(上記例では「g_mat」)を使います。
出力は以下のようになります。
Accessing mat[3]: 3.000000
numpyのarangeで生成した値と同じものと確認できました。
Copyright 2018-2019, by Masaki Komatsu