Я столкнулся со странной проблемой. Я реализую некоторую линейную алгебру, только матричные умножения, в 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 matrix_multiplications требуется около 1,2 мс, на матрицах размером 512 * 512, в то время как тот же код занимает около 3 мс при работе на Linux GTX 480. Это беспокоит меня с тех пор, я не ожидал бы, что дорогая карта 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 сохраняет ту же производительность. Кто-нибудь может объяснить, почему это так?