【发布时间】:2016-07-31 17:29:14
【问题描述】:
当 OpenCL 内核中的 for 循环边界是动态的时(即对于每个工作项,for 循环执行不同的次数时),它们如何在设备上执行?
AFAIK,内核是一组(或者更好地说是一个流)指令。 GPU 设备是一组独立的计算单元(流式多处理器 - SM),每个计算单元都包含多个计算单元(流式处理器 - SP)。
每个 SM 可以从内核(即指令流)加载一条指令(对于不同的 SM,这可能是不同的指令),并为当前 SM 中的 SP(每个 SP 运行相同的指令,但数据不同——SIMD)。
一个 SM 中的所有 SP 必须运行相同的指令,因此在执行 for 循环的条件后,必须根据每个工作项的条件结果做出动态决定,下一条指令将是什么可以在 SM 上运行和来运行它的工作项。
基于这个假设,我假设foobaz 内核(见下文)会执行得更快,因为当一个工作项完成执行时,另一个工作项可以取代它。
这个假设是错误的吗?
以下两个内核,foobar 和 foobaz,哪一个最终会执行得更快? 性能取决于什么? (一个元素的属性数量可能比其他元素多几个数量级)。
foobar;
__kernel void foobar(__global int* elements, /* size N */
__global int* element_properties, /* size N*constant */
__global int* output) /* size N */
{
size_t gid = get_global_id(0);
int reduced = 0;
for (size_t i=N*gid; i<N+N*gid; i++)
reduce += predict_future_events( reduce, element_properties[i] );
output[gid] = reduced;
}
…和foobaz;
__kernel void foobaz(__global int* elements, /* size N */
__global int* element_properties, /* size upper-bounded */
__global int2* element_properties_ranges, /* size N */
__global int* output) /* size N */
{
size_t gid = get_global_id(0);
int reduced = 0;
// `range.x` = starting index in `element_properties`
// `range.y` = ending index in `element_properties`
int2 range = element_properties_ranges[gid];
for (size_t i=range.x; i<range.y; i++)
reduce += predict_future_events( reduce, element_properties[i] );
output[gid] = reduced;
}
【问题讨论】:
标签: loops parallel-processing opencl gpgpu cpu-architecture