我遇到了一个奇怪的问题。我在 OpenCL 中实现了一些线性代数,到目前为止只有矩阵乘法,并且一直在我的笔记本电脑上进行测试。代码非常简单:
__kernel void matrix_mult(__global float* a,
__global float* b,
__global float* c,
const int N)
{
int row = get_global_id(1);
int col = get_global_id(0);
float sum = 0.0f;
for (int i = 0; i < N; i++) {
sum += a[row*N+i] * b[i*N+col];
}
c[row*N+col] = sum;
}
我通过运行代码 100 次来测试硬件,如下所示:
clock_t begin=clock();
const unsigned int repeats = 100;
for(int i = 0; i != repeats; i++){
runCL(a, b, results,N, N*N);
}
clock_t end=clock();
在我的 MBP 矩阵乘法上大约需要 1.2 毫秒,在大小为 512*512 的矩阵上,而在 GTX 480 Linux 机器上运行相同的代码大约需要 3 毫秒。这让我很困扰,因为我不希望昂贵的 GTX 卡比笔记本电脑快一点。
据我所见,我的代码要么是“错误的”,要么是我以某种错误的方式计时。
我尝试在 OpenCL 规范中使用基于事件的计时系统,这给出了一些更真实的结果。
cl_event event = {0};
err = clEnqueueNDRangeKernel(cmd_queue, kernel[0], 2, NULL, global_work_size, NULL, 0, NULL, &event);
assert(err == CL_SUCCESS);
cl_int err = clWaitForEvents (1,&event);
cl_ulong start, end;
clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &end, NULL);
clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start, NULL);
double executionTimeInMilliseconds = (end - start) * 1.0e-6f;
std::cout << "execution time in milis : " << executionTimeInMilliseconds << std::endl;
现在 GT330M 将在 46 毫秒内完成操作,而 GTX480 在 2.5 毫秒内完成。这就引出了另一个非常有趣的问题,开启 PROFILING 后,GT 330M 的速度会慢 30 倍左右,这是有道理的,但 GTX480 保持了相同的性能。谁能解释这是为什么?