我第一次尝试使用opencl,目标是计算数组中每一行的argmin。由于每一行的操作都独立于其他行,因此我认为将其轻松放在图形卡上是很容易的。
与使用外部forloop在cpu上运行代码时相比,使用此代码获得的性能似乎更差,我们将不胜感激。
这是代码:
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
int argmin(global double *array, int end)
{
double minimum = array[0];
int index;
for (int j = 0; j < end; j++)
{
if (array[j] < minimum)
{
minimum = array[j];
index = j;
}
}
return index;
}
kernel void execute(global double *dist, global long *res, global double *min_dist)
{
int row_size = 0;
int i = get_global_id(0);
int row_index = i * row_size;
res[i] = argmin(&dist[row_index], row_size);
min_dist[i] = dist[res[i] + row_index];
}
Run Code Online (Sandbox Code Playgroud)
评论者提出了一些有效的观点,但我会尝试更有建设性和更有组织性:
double您的数据似乎由精度浮点值组成。根据您的 GPU,这本身可能是个坏消息。消费级 GPU 通常未针对处理doubles 进行优化,与单精度运算相比,通常仅实现 1/32 或 1/16 的吞吐量float。不过,许多专业级 GPU(Quadro、Tesla、FirePro、一些 Radeon Pro 卡)都可以很好地使用它们,实现 1/2 或 1/4 的吞吐量,而float. 由于您只执行简单的算术运算(比较),并且您的运行时很可能由内存访问主导,因此它在消费类硬件上也可能没问题。row_size实际上不是 0,这将有助于了解真正的(典型)值是什么,以及它是固定的、按行变量还是每次运行变量但每行都相同。无论如何,除非row_size非常小,否则您在其上运行串行循环的事实for可能会阻碍您的代码。改进建议:
row_size非常小(且固定),否则尝试将循环拆分为多个工作项,并使用本地内存(缩减算法)和全局内存中的原子操作进行协调。double在消费类硬件上比较 s 太慢,请检查是否可以将数据生成为floats 而不会损失准确性(这也将使您的内存带宽问题减半) ),或者检查是否可以以其他方式做得更好,例如将 the 视为doublealong并使用整数运算手动解包和比较指数和尾数。