GPU上的独立搜索 - 如何同步其完成?

时间:2012-01-05 21:01:01

标签: multithreading synchronization opencl gpgpu gpu-programming

假设我有一些算法generateRandomNumbersAndTestThem(),它以概率p和false返回true,概率为1-p。通常p非常小,例如P = 0.000001

我正在尝试在JOCL中构建一个程序,估计p如下:generateRandomNumbersAndTestThem()在所有可用的着色器核心(最好是多个GPU)上并行执行,直到找到至少100个trues。然后p的估计值为100 / n,其中n是执行generateRandomNumbersAndTestThem()的总次数。

对于p = 0.0000001,这意味着大约10 ^ 9次独立尝试,这应该说明我为什么要在GPU上执行此操作。但我正在努力解决如何正确实施停止条件。我的想法是将这些内容作为内核:

__kernel void sampleKernel(all_the_input, __global unsigned long *totAttempts) {
    int gid = get_global_id(0);
    //here code that localizes all_the_input for faster access
    while (lessThan100truesFound) {
        totAttempts[gid]++;
        if (generateRandomNumbersAndTestThem()) 
            reportTrue();
    }
}

如果没有严重的性能损失,我该如何实现呢?鉴于

  • 触发“if”将是一个非常罕见的事件,因此如果所有线程都必须在执行reportTrue()时等待,那么这不是问题
  • lessThan100truesFound只有在第100次调用reportTrue()时才需要修改一次(从true到false)(所以我甚至不知道布尔值是否正确)
  • 计划是为此购买全新的GPU硬件,因此您可以假设最新的GPU,例如多个ATI Radeon HD7970s。但如果我可以在目前的HD5450上进行测试,那就太好了。

我认为可以像Java的“synchronized”修饰符那样完成某些操作,但我找不到确切的方法。这样做的“正确”方法是什么,即任何方式都可以在没有严重性能损失的情况下工作?

1 个答案:

答案 0 :(得分:1)

我建议不要使用全局标志来停止内核,而是运行内核来执行一定数量的尝试,如果已经积累了足够的“成功”,请检查主机,并在必要时重复。在内核中使用未定义长度的循环是不好的,因为GPU驱动程序可能被看门狗计时器杀死。此外,在每次迭代时检查一些全局变量肯定会破坏内核性能。

这样,reportTrue可以作为atomic_inc实现到驻留在全局内存中的某个计数器。

__kernel void sampleKernel(all_the_input, __global unsigned long *successes) {
    int gid = get_global_id(0);
    //here code that localizes all_the_input for faster access
    for (int i = 0; i < ATT_PER_THREAD; ++i) {
        if (generateRandomNumbersAndTestThem()) 
            atomic_inc(successes);
    }
}

ATT_PER_THREAD将根据执行generateRandomNumbersAndTestThem()所需的时间进行调整。内核启动开销非常小,因此通常不需要使内核运行超过0.1-1秒