OpenCL中求和缩减的最佳工作组大小

OpenCL中求和缩减的最佳工作组大小,opencl,gpu,gpgpu,Opencl,Gpu,Gpgpu,我使用下面的内核进行求和 __kernel void reduce(__global float* input, __global float* output, __local float* sdata) { // load shared mem unsigned int tid = get_local_id(0); unsigned int bid = get_group_id(0); unsigned int gid = get_global_id(0);

我使用下面的内核进行求和

__kernel void reduce(__global float* input, __global float* output, __local float* sdata)
{
    // load shared mem
    unsigned int tid = get_local_id(0);
    unsigned int bid = get_group_id(0);
    unsigned int gid = get_global_id(0);

    unsigned int localSize = get_local_size(0);
    unsigned int stride = gid * 2;
    sdata[tid] = input[stride] + input[stride + 1];

    barrier(CLK_LOCAL_MEM_FENCE);
    // do reduction in shared mem
    for(unsigned int s = localSize >> 2; s > 0; s >>= 1) 
    {
        if(tid < s) 
        {
            sdata[tid] += sdata[tid + s];
        }
        barrier(CLK_LOCAL_MEM_FENCE);
    }

    // write result for this block to global mem
    if(tid == 0) output[bid] = sdata[0];
}
\uuuuu内核void reduce(\uuuu全局浮点*输入,\uuuuu全局浮点*输出,\uuuu本地浮点*数据)
{
//加载共享内存
unsigned int tid=get\u local\u id(0);
unsigned int bid=get\u group\u id(0);
unsigned int gid=get_global_id(0);
unsigned int localSize=get\u local\u size(0);
无符号整数步长=gid*2;
sdata[tid]=输入[步幅]+输入[步幅+1];
屏障(CLK_本地_MEM_围栏);
//是否减少共享内存
对于(无符号整数s=localSize>>2;s>0;s>>=1)
{
如果(tid
它工作得很好,但如果我需要多个工作组(例如,如果我想计算1048576个元素的总和),我不知道如何选择最佳工作组大小或工作组数量。据我所知,我使用的工作组越多,得到的子结果就越多,这也意味着我最终需要更多的全局缩减


我已经看到了一般工作组规模问题的答案。是否有任何建议专门涉及减少操作?

这个问题可能与我刚才回答的问题重复:

实验将是确定任何给定设备的最佳方法

更新: 我认为您可以安全地坚持一维工作组,就像您在示例代码中所做的那样。在主机上,您可以尝试最佳值

对于每个设备:

1) 查询CL\内核\首选\工作\组\大小\倍数

2) 循环几次,并以该组大小运行内核。为每个测试节省执行时间

3) 当您认为您有一个最佳值时,将其硬编码到一个新内核中,以便与特定设备一起使用。这将进一步提高性能。您还可以在特定于设备的内核中删除sdata参数

//define your own context, kernel, queue here

int err;
size_t global_size; //set this somewhere to match your test data size
size_t preferred_size;
size_t max_group_size;

err = clGetKernelWorkGroupInfo(kernel, device_id, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, sizeof(size_t), preferred_size, NULL);
//check err
err = clGetKernelWorkGroupInfo(kernel, device_id, CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), max_group_size, NULL);
//check err

size_t test_size;

//your vars for hi-res timer go here

for (unsigned int i=preferred_size ; i<=max_group_size ; i+=preferred_size){
    //reset timer
    test_size = (size_t)i;
    err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &global_size, &test_size, 0, NULL, NULL);
    if(err){
        fail("Unable to enqueue kernel");  //implement your own fail function somewhere..
    }else{
        clfinish(queue);
        //stop timer, save value
        //output timer value and test_size
    }
}
//在此处定义您自己的上下文、内核和队列
INTERR;
大小\u t全局\u大小//将其设置为与测试数据大小匹配的位置
尺寸不是首选尺寸;
大小\u t最大\u组大小;
err=clGetKernelWorkGroupInfo(内核、设备id、内核、首选工作、组大小、倍数、大小(大小)、首选大小、空);
//检查错误
err=clGetKernelWorkGroupInfo(内核、设备id、内核工作组大小、sizeof(大小)、最大组大小,NULL);
//检查错误
尺寸测试尺寸;
//高分辨率定时器的VAR在这里
对于(无符号整数i=首选大小;i>2;s>0;s>>=1){
如果(tid
这完全取决于硬件。你在什么上面运行你的内核?@蝉:这就是重点。我想在不同的设备上测试它:Intel HD Graphics 4400和2 x NVIDIA Tesla C2070(多GPU)。因此,如果我能编写一个函数,动态计算最佳大小,那就更好了。据我所知,到目前为止最好的方法是用不同的值进行测试,并通过实验找到最佳值。问题是“最佳”尺寸。在我看来,获得一个相当好的价值是容易的,但获得一个最佳的可能是地狱。我建议使用一些简单的启发式值,它应该给出好的值。只有通过测试才能找到最佳,为了100%确定(由于许多不同的硬件),我知道它是相似的,您对该问题的回答非常有用。我想你们中的一些人对简化算法很有经验。许多OpenCL书籍都提到了它,但在大多数情况下,只显示了内核代码。更新了主机代码主要部分的答案。将其放入您的实现中,并进行必要的更改。
#define LOCAL_SIZE 32
__kernel void reduce(__global float* input, __global float* output)
{
    unsigned int tid = get_local_id(0);
    unsigned int stride = get_global_id(0) * 2;
    __local float sdata[LOCAL_SIZE];
    sdata[tid] = input[stride] + input[stride + 1];

    barrier(CLK_LOCAL_MEM_FENCE);

    for(unsigned int s = LOCAL_SIZE >> 2; s > 0; s >>= 1){
        if(tid < s){
            sdata[tid] += sdata[tid + s];
        }
        barrier(CLK_LOCAL_MEM_FENCE);
    }
    if(tid == 0) output[get_group_id(0)] = sdata[0];
}