その他

clCreateImageがCL_INVALID_VALUEを返す問題の回避方法

Mac(OSX 10.8.3、GPU Geforce 9400M)のclCreateImageがおかしいという記事を書いたが、さすがにclCreateImage程度の基本的な関数がまともに動かないってのはおかしいと思ったので少し詳しく調べてたら回避方法みたいなものが分かった。

C++ Wrapper(cl.hpp)のcl::Image2Dの中では、clCreateImageの第4引数に以下のように初期化したcl_image_desc構造体を渡すようになってる。

cl_image_desc desc;
desc.image_type = CL_MEM_OBJECT_IMAGE2D;
desc.image_width = width;
desc.image_height = height;
desc.image_row_pitch = row_pitch;
desc.num_mip_levels = 0;
desc.num_samples = 0;
desc.buffer = 0;

このcl_image_desc構造体のフィールドはこれで全てではなく、この他にimage_depth, image_array_size, image_slice_pitchの3つがある。
この3つは他の関数で使う場合に必須になるもので、image_type = CL_MEM_OBJECT_IMAGE2DでclCreateImageを呼び出す場合には無関係なはずである。
cl.hppでその3つが初期化されていない点からも、仕様上この3つは初期化する必要がないんだろうなという事が推測できる。

しかし初期化されていないフィールドにはおかしな値が入ってるはずで、念のため以下のように全てのフィールドを初期化してclCreateImageに渡してみた。

cl_image_desc desc;
desc.image_type = CL_MEM_OBJECT_IMAGE2D;
desc.image_width = width;
desc.image_height = height;
desc.image_depth = 0;
desc.image_array_size = 0;
desc.image_row_pitch = row_pitch;
desc.image_slice_pitch = 0;
desc.num_mip_levels = 0;
desc.num_samples = 0;
desc.buffer = 0;

そしたらなんと正常に実行出来るようになってしまった。
さらに調べてみるとimage_depthが未初期化の場合にエラーになる事が判明。

エラーになる場合は、CL_INVALID_VALUEが返ってくるが、これはclCreateImageの第2引数であるCL_MEM_READ_ONLYなどのflagの指定がおかしなときのエラーとされているので、上記のdescriptor(cl_image_desc)は無関係のはずである。
(descriptorがおかしな場合のために、CL_INVALID_IMAGE_DESCRIPTORというエラーが別に用意されている。)

この事から、clCreateImageの実装の中のflagの妥当性チェックの処理で、本来無関係であるはずのdesc.image_depthを見てしまってるのではないかという気がする。

で、この問題は誰のせいか。
cl.hppの実装ミス。
AppleのOpenCL実装ミス。
NVIDIAのドライバのミス。
と、大まかに3つ考えられるが、cl.hppはKhronosが配ってるぐらいだから仕様には忠実なはずとして除外すると、GPUデバイスに限らずCPUデバイスをターゲットにしてもこの問題が起きることから、Appleがやらかしてるんじゃないかという気がする。

しかしそうだとしたら、この問題に気づく人がもっと多くてもいいような気がするけど、ググったところ同じような報告は少なかった。
機種依存・環境依存なのかもしれない。

さて、肝心の処理速度だけど、CUDA版に比べて2倍強遅かったのがImage2Dを使うことによって微妙に改善した。
が、それでもまだ2倍弱の遅さ。
CUDAとOpenCLではスピードの差は出ないと聞いたことがあるので、どこか同じ条件になってない部分があるんだろうけど、それがどこなのかさっぱり分からない。

これは本題と関係ないけど、OpenCLってCPUでも実行出来るのが利点だけど、GPUで実行する場合と微妙に動きが違う部分があるのが気になる。
CPUとGPUで対応してるOpenCL Cのバージョンが違うせいで動きが違うのは当たり前なんだけど、バージョンの違いとか関係ないはずの部分でも微妙に動きが違う点があって混乱する。

概念上はCUDAとOpenCLは似たようなもので、CUDA Driver APIと比べて必要なコード数にもそれほど差はないのに、個人的にOpenCLの方が10倍くらいめんどくさい感覚がある。
リファレンスを見るだけでは分からない微妙な部分が多すぎるからだろう。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です



※画像をクリックして別の画像を表示

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください