OS XのOpenCL - その12 [OS XのOpenCL]
なかなか終わらないOS XでのOpenCLのプログラミングガイド抄訳の続き。今日のところはOpenCLデバイスで使える汎用のメモリ領域の話。普通にCPUのメモリを確保したり解放したりというのと考え方は基本的には同じだけど、ポインタを通して直接アクセスはできない....
データ転送は高コストなので読んだり書いたりは可能な限り最小限にとどめるのが一番いいことである。デバイス上に残すようにホスト側のデータ全体をバッファオブジェクトに包んでしまうことで、データを処理するために必要な転送を減らすことができる。
注意:戻り値をメモリへの直接アクセスに使ってはいけない。デバイスメモリバッファへの不透過型ポインタである。メモリオブジェクトであると期待してこのハンドルをカーネルへ引数として渡してよい。また、デバオスメモリのポインタとしてほかのgcl_関数(gbl_memcpyのような関数)に渡してもよい。
要求を満足する十分なメモリがない場合はNULLを返す。
この関数はgcl_ の入り口の付近でOpenCL規格のAPIを使うときにだけ必要になる。
gcl_mallocで確保したポインタを引数にしてcl_memオブジェクトを返す。
注意:gcl_freeでハンドルを解放する前にgcl_create_buffer_from_ptrを使って作ったcl_memオブジェクトに対してclReleaseMemObjectを呼ばなければならない。
コードは次のようになる
OpenCL規格のclEnqueueCopyBufferRect関数と同じで、コピーはコピー元オフセット(src_origin)とコピー先オフセット(dst_origin)から始まる。regionの幅でそれぞれのバイトがコピーされる。一つの幅のコピーが終わるとオフセットはそれぞれのrow_pitchぶん足され(て次の幅がコピーされ)る。
そうやって2次元の長方形がコピーされるとそれぞれのslice_pitchが足されてつぎの長方形がコピーされる。
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パラメータでコピーするエリアのサイズと形を指定する。 バッファ間のコピーなので全ての引数はバイト単位である。
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
- 解放するバッファオブジェクトのハンドル
2015-07-11 20:07
nice!(0)
コメント(0)
トラックバック(0)
コメント 0