我在 OpenCL 上运行 mandelbrot 生成器(来自静态参数的 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;
[/编辑]
我在我的 Nvidia Quadro 1000M 上运行它,它有 2 个计算单元和 96 个 CUDA 内核(每个计算单元 48 个内核)。
在将内核排队时,我正在通过更改本地组大小来玩弄。这些是我在生成 400Mpixel 图像时得到的不同尺寸的性能结果。所有数字都来自 OpenCL 分析器,不包括返回到操作系统的最终内存副本。图像为 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 获得最佳性能?!?我原本预计 33% 的 SIMD 处理器处于空闲状态,但看起来工作组位于两个计算单元之间?!?
- 为什么 PREFERRED_WORK_GROUP_SIZE_MULTIPLE 返回 32 而不是 48?
- 仅考虑我从 OpenCL 信息结构中获得的信息,是否有一种非经验方法可以计算出任何 GPU(ATI/Nvidia/Intel HD)上最高性能的几何形状?
提前致谢