SSブログ

OS XのOpenCL - その12 [OS XのOpenCL]

なかなか終わらないOS XでのOpenCLのプログラミングガイド抄訳の続き。今日のところはOpenCLデバイスで使える汎用のメモリ領域の話。普通にCPUのメモリを確保したり解放したりというのと考え方は基本的には同じだけど、ポインタを通して直接アクセスはできない....

8  OpenCLのバッファオブジェクトを作成し使用する

OpenCLのプログラミングインターフェイスは汎用のデータを表現するためにバッファオブジェクトを提供している。扱っているデータをハードウェアの特定のタイプに変換する代わりに、データをそのままOpenCLデバイスに渡して慣れたC言語と同じような機能を使って操作するということも可能である。

データ転送は高コストなので読んだり書いたりは可能な限り最小限にとどめるのが一番いいことである。デバイス上に残すようにホスト側のデータ全体をバッファオブジェクトに包んでしまうことで、データを処理するために必要な転送を減らすことができる。

8.1  デバイスメモリにバッファオブジェクトを確保する

デバイスメモリ中にバッファオブジェクトを確保するには次の関数を使う
void * gcl_malloc(size_t bytes, void *host_ptr, cl_malloc_flags flags)
gcl_malloc関数はCのmalloc関数に似ていて、デバイスメモリバッファへの不透過型(opaque type)ポインタを返す。

注意:戻り値をメモリへの直接アクセスに使ってはいけない。デバイスメモリバッファへの不透過型ポインタである。メモリオブジェクトであると期待してこのハンドルをカーネルへ引数として渡してよい。また、デバオスメモリのポインタとしてほかのgcl_関数(gbl_memcpyのような関数)に渡してもよい。

要求を満足する十分なメモリがない場合はNULLを返す。
bytes
バイト単位のサイズ要求
host_ptr
フラグ引数にCL_MEM_COPY_HOST_PTRがあるとき、メモリ確保の初期化のためのホスト側のバッファへのポインタ
flags
ビットフィールドになったフラグ。詳しくはOpenCL1.1のセクション5.2.1にある。host_ptrに必要なフラグを渡す。そのときはhost_ptrはNULLであってはならない。そうでなければNULLを渡すこと

8.2  OpenCL規格のAPIを使えるようにハンドルをcl_memオブジェクトに変換

もしOpenCL規格のAPIを使いたいなら、cl_memオブジェクトが必要となる。cl_memオブジェクトを作るのは確保にgcl_malloc関数を呼んで、それからgcl_create_buffer_from_ptr関数を呼んで確保したメモリをOpenCL規格のAPiで使える形に変換する。
cl_mem gcl_create_buffer_from_ptr(void *ptr)
引数ptrはgcl_mallocが返したポインタである。

この関数はgcl_ の入り口の付近でOpenCL規格のAPIを使うときにだけ必要になる。

gcl_mallocで確保したポインタを引数にしてcl_memオブジェクトを返す。

注意:gcl_freeでハンドルを解放する前にgcl_create_buffer_from_ptrを使って作ったcl_memオブジェクトに対してclReleaseMemObjectを呼ばなければならない。

コードは次のようになる
void* device_ptr = gcl_malloc(…);
cl_mem device_mem = gcl_create_buffer_from_ptr(device_ptr);
 
// device_ptr と device_memでなにかする
 
clReleaseMemObject(device_mem);
gcl_free(device_ptr);

8.3  デバイスのグローバルメモリにアクセスする

gcl_malloc関数を呼んで作ったポインタで表されるデバイスのグローバルメモリにアクセスするには次の関数を使う
void *gcl_map_ptr(void *ptr, cl_map_flags map_flags, size_t cb);
このgcl_map_ptr関数はOpenCL規格のclEnqueueMapBuffer関数に似た機能を提供する。読み書きに適した形でデバイスメモリのポインタを表すホストからアクセス可能なメモリへのポインタを返す。gcl_malloc関数で作ったポインタが表すデバイスのグローバルメモリをアクセスするためにいろいろあるgcl_コピー関数の代わりに使うことができる。
ptr
マップしたいデバイスメモリへのポインタ。これはgcl_malloc関数で作られたもの
map_flags
CL_MAP_READとCL_MAP_WRITEを指定するビットフィールド。返ってきたポインタをどう使いたいかによって指定する
cb
マップするバッファのバイト数(cbはCount Bytesである)

8.4  バッファオブジェクトのコピー

gcl_malloc関数を使ってデバイスメモリを確保したとき、デバイス固有のディスパッチキューを作る必要はない。しかしメモリを実際に使うときがきたらカーネルの実行のためとコピーなどのためにどのデバイスを使うかをOpenCLに認識させる必要がある。

8.4.1  ホストからデバイスへあるいはその逆へのデータのコピー

ホストとデバイス間でデータをコピーするには
void gcl_memcpy(void *dst, const void *src, size_t size);
を使う。
dst
コピー先のメモリへのポインタ。これは普通のホスト側のポインタでも、gcl_mallocで作ったデバイスメモリへのポインタでもいい
src
コピー元のメモリへのポインタ。こっちもどっちでもいい
size
コピーするバイト単位のサイズ
重要:バッファはコピーできる十分なサイズがあることを確認する。この関数を呼ぶのは特定のディスパッチキューのブロック内部でなければならない。

8.4.2  汎用のバッファ間コピー

もともと多次元のバッファデータをバッファ間でコピーするには次の関数を使う。
void gcl_memcpy_rect(
                       void *dst,
                       const void *src, 
                        const size_t dst_origin[3],
                        const size_t src_origin[3],
                        const size_t region[3],
                        size_t dst_row_pitch,
                        size_t dst_slice_pitch,
                        size_t src_row_pitch,
                        size_t src_slice_pitch);
この関数はOpenCL規格のclEnqueueCopyBufferRect関数の機能に似ている。この関数は1、2、3次元の長方形領域をそれぞれの原点に対してsrcポインタからdstポインタへコピーする。図に示すように、regionパラメータでコピーするエリアのサイズと形を指定する。
0615fig08.png
バッファ間のコピーなので全ての引数はバイト単位である。

OpenCL規格のclEnqueueCopyBufferRect関数と同じで、コピーはコピー元オフセット(src_origin)とコピー先オフセット(dst_origin)から始まる。regionの幅でそれぞれのバイトがコピーされる。一つの幅のコピーが終わるとオフセットはそれぞれのrow_pitchぶん足され(て次の幅がコピーされ)る。

そうやって2次元の長方形がコピーされるとそれぞれのslice_pitchが足されてつぎの長方形がコピーされる。
dst
コピー先ノメモリへのポインタ。これはホストの通常メモリでも、gcl_mallocで確保したデバイスのメモリポインタでも構わない
src
コピー元のメモリへのポインタ。これもホストあるいはデバイスのどちらでもよい
dst_origin[3]
コピーによる書き込みが始まるバイト単位でのオフセット。そのアドレスは
dst_origin[0] * dst_row_pitch +
dst_origin[1] * dst_slice_pitch +
dst_origin[2]
である
src_origin[3]
コピーによる読み出しが始まるバイト単位でのオフセット。そのアドレスは
src_origin[0] * src_row_pitch +
src_origin[1] * src_slice_pitch +
src_origin[2]
である
region
2あるいは3次元のコピー領域
dst_row_pitch
dstのメモリ領域の1列の長さ、バイト単位。これに0が指定されるとregion[0]と解釈される
dst_slice_pitch
dstの2次元領域の3次元内でのピッチ
src_row_pitch
srcでの1列の長さ
src_slice_pitch
srcの2次元領域のピッチ
重要:バッファはコピーできる十分なサイズがあることを確認する。この関数を呼ぶのは特定のディスパッチキューのブロック内部でなければならない。

8.4.3  バッファオブジェクトの解放

メモリリークを避けるために不要になったバッファオブジェクトは解放する。gcl_malloc関数で確保したバッファオブジェクトではgcl_free関数を呼ぶ。
void   gcl_free(void *ptr);
ptr
解放するバッファオブジェクトのハンドル

nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。