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

Multithreading GPU上的独立搜索--如何同步其完成?,multithreading,synchronization,opencl,gpgpu,gpu,Multithreading,Synchronization,Opencl,Gpgpu,Gpu,假设我有一些算法generaterandomnumbersandtesthems(),它以概率p返回true,以概率1-p返回false。通常p非常小,例如p=0.000001 我正试图在JOCL中构建一个程序,该程序对p的估计如下:generaterandomnumbersandtesthem()在所有可用的着色器内核(最好是多个GPU)上并行执行,直到找到至少100个trues。那么p的估计值是100/n,其中n是GeneratorDomainNumbersAndTestThemes()执行

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

我正试图在JOCL中构建一个程序,该程序对p的估计如下:generaterandomnumbersandtesthem()在所有可用的着色器内核(最好是多个GPU)上并行执行,直到找到至少100个trues。那么p的估计值是100/n,其中n是GeneratorDomainNumbersAndTestThemes()执行的总次数

对于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 HD7970。但如果我能在我目前的HD5450上测试它,那就太好了

我假设可以做一些类似于Java的“synchronized”修饰符的事情,但我找不到确切的方法。做这件事的“正确”方法是什么,也就是说,没有严重性能损失的任何方法?

我建议不要使用全局标志来停止内核,而是运行内核进行一定量的尝试,检查主机上是否积累了足够的“成功”,必要时重复。在内核中使用未定义长度的循环是不好的,因为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);
    }
}
\uuuu内核void sampleKernel(所有输入,\uu全局无符号长*成功){
int gid=获取全局id(0);
//这里的代码将所有输入本地化,以便更快地访问
对于(int i=0;i

ATT_PER_线程将根据执行
GeneratorDomainNumbers和TestThems()所需的时间进行调整。内核启动开销非常小,所以通常不需要让内核运行超过0.1-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);
    }
}
\uuuu内核void sampleKernel(所有输入,\uu全局无符号长*成功){
int gid=获取全局id(0);
//这里的代码将所有输入本地化,以便更快地访问
对于(int i=0;i

ATT_PER_线程将根据执行
GeneratorDomainNumbers和TestThems()所需的时间进行调整。内核启动开销非常小,因此通常不需要让内核运行超过0.1--1秒

此策略的问题是需要本地化相当多的内存。输入主要由一个图组成,必须沿图的边缘计算某些流。要传输的内存总量可能很容易达到1MB或更大,对每个内核不断地这样做对我来说似乎是一个主要的瓶颈。如果我必须在GeneratorDomainNumbers和TestThemes()中执行数千个本地内存操作,那么停止内核的全局标志会有很大的代价吗?因此,简而言之,内核启动开销可能非常小,但内存本地化可能不是。从技术上讲,这应该是可以避免的,因为图形始终保持不变,但我不知道如何实现这一点。是否可以使用您的方法,而不必在每次内核再次启动时重新本地化相同的内存内容?1MB不是那么多,但它在很大程度上取决于访问模式和内存类型。鉴于您没有提供太多关于
generaterandomnumbersandtesthems()
的信息,因此不可能确定什么,但作为GPGPU编程的一般规则,应该避免任何线程间同步(本地内存访问障碍除外)。这应该让您了解GeneratorDomainNumbers和TestThemes():这是我要实现的java版本。瓶颈来自于对一个二分图的所有边的迭代,我通过为每个边存储两个二分图类(edgeRow和edgeColumn)的顶点来实现。一个大的例子是lengte=hoogte=2000,aantalEnen=100000,一个小的例子是lengte=hoogte=500,aantalEnen=2000。我还使用了两个大小为(lengte x hoogte)的二元矩阵G,H。我认为其余的都不相关。这个策略的问题是有相当多的内存需要本地化。输入主要由一个图组成,必须沿图的边缘计算某些流。要传输的内存总量可能很容易达到1MB或更大,对每个内核不断地这样做对我来说似乎是一个主要的瓶颈。Wou