OpenCL でマンデルブロ ジェネレーター (静的パラメーターからの 2D 画像) を実行しています。プログラムは簡単です:
__kernel
void mandelbrot(__global uchar * output,
const float xstep,
const float xoffset,
const float ystep,
const float yoffset,
const int maxiter)
{
int gid_y = get_global_id(1);
int gid_x = get_global_id(0);
//calculate x and y on the fly for every pixel.
//This is just as fast as reading precalculated rulers from global memory.
float x = gid_x * xstep + xoffset;
float y = gid_y * ystep + yoffset;
float real = 0;
float imag = 0;
int out = 0;
for(int curiter = 0; curiter < maxiter; curiter++) {
float nreal = real*real - imag*imag + x;
imag = 2* real*imag + y;
real = nreal;
if (real*real + imag*imag > 4.0f) {
out = curiter;
break;
}
}
//normalize output
out *= 256.0 / (float)maxiter;
output[gid_y * get_global_size(0) + gid_x] = out;
}
[編集] [完全なカーネルを投稿し、提案どおりに行と列を入れ替えました。この方法で、AMD では 18% のパフォーマンスが得られましたが、NVidia では 0% でした。元のコードは
output[get_global_id(0) * get_global_size(1) + get_global_id(1)] = out;
[/編集]
2 つの計算ユニットと 96 個の CUDA コア (計算ユニットあたり 48 コア) を備えた Nvidia Quadro 1000M で実行しています。
カーネルをキューに入れるときにローカル グループのサイズを変更して遊んでいます。これらは、400M ピクセルの画像を生成するときにさまざまなサイズで取得したパフォーマンス結果です。すべての数値は OpenCL プロファイラーからのものであり、OS への最終的なメモリ コピーは除外されています。画像は 40992x10272 で、高さと幅の両方が 48 で割り切れます。
rows x columns
8x8: 397 MPixel/s
8x12: 505 MPixel/s
8x16: 523 MPixel/s
8x24: 521 MPixel/s
8x32: 520 MPixel/s
8x48: 520 MPixel/s
1x48: 321 MPixel/s
2x32: 424 MPixel/s
2x48: 523 MPixel/s
4x24: 519 MPixel/s
3x32: 525 MPixel/s
4x32: 525 MPixel/s
4x48: 525 MPixel/s
12x8: 490 MPixel/s
12x12:464 MPixel/s
12x24:505 MPixel/s
12x32:508 MPixel/s
12x48:433 MPixel/s
16x8: 499 MPixel/s
16x12:499 MPixel/s
16x16:472 MPixel/s
16x24:450 MPixel/s
16x32:440 MPixel/s
16x48:418 MPixel/s
これらの数字のいくつかは、私を困惑させます。48列で最良の結果が得られる理由は明らかですが(SIMD操作の仕組みのおかげです)、私には理解できません:
- グループごとに 16 行を使用するとパフォーマンスが劇的に低下するのはなぜですか?
- 1x48 でパフォーマンスが低下するのはなぜですか?
- 3x32、4x32、8x32 で最高のパフォーマンスが得られるのはなぜですか?!? SIMD プロセッサの 33% がアイドル状態になると予想していましたが、代わりに、2 つの計算ユニットの間にワークグループが存在しているように見えますか?!?
- Preferred_WORK_GROUP_SIZE_MULTIPLE が 48 ではなく 32 を返すのはなぜですか?
- OpenCL情報構造から取得したものだけを考慮して、任意のGPU(ATI/Nvidia/Intel HD)で最高のパフォーマンスを得るためのジオメトリを把握するための非経験的な方法はありますか?
前もって感謝します