Algorithm 使用GPU计算和存储最大值的最佳解决方案是什么?我现在的不满意

Algorithm 使用GPU计算和存储最大值的最佳解决方案是什么?我现在的不满意,algorithm,cuda,Algorithm,Cuda,我的设备上运行以下内核: __global__ void kernel1(float *Vb, int *sS, int *sE, int *bI, float *eR, int S, int K, int B, int N) { const unsigned long long int blockId = blockIdx.x //1D + blockIdx.y * gridDim.x //2D + gridDim.x * gridDim.y * blo

我的设备上运行以下内核:

__global__ void kernel1(float *Vb, int *sS, int *sE, int *bI, float *eR, int S, int K, int B, int N)
{
    const unsigned long long int blockId = blockIdx.x //1D
        + blockIdx.y * gridDim.x //2D
        + gridDim.x * gridDim.y * blockIdx.z; //3D
    const unsigned long long int threadId = blockId * blockDim.x + threadIdx.x;
    int s = threadId / (K * B), k = (threadId - (s * K * B)) / B, b = threadId - (s * K * B) - (k * B);

    if (s < S && k < K && b < B)
    {
        float sum = 0;

        for (int t = sS[k]; t <= sE[k]; t++)
            sum += eR[s * N + bI[b * N + t]];

        if (sum > Vb[b * K + k])
        {
            Vb[b * K + k] = sum;
        }
    }
}
我基本上是基于映射为简单1D数组的eR[SxN]和bI[BxN]矩阵以及sE[K]和sS[K]数组计算一些和,并尝试将每个s,K,b对获得的最大值存储在同样映射为1D数组的Vb[BxK]矩阵中

我的问题是,最终,Vb矩阵不包含为每对计算的最大值。据我所知,问题的出现是因为所有GPU线程都并行运行,这当然是件好事,它们都同时到达if sum>Vb[b*K+K]语句,因此都根据Vb[b*K+K]元素的原始值来计算它。因此,Vb[b*K+K]中存储的最终值是最后一个线程中计算的总和的值,该线程将元素最后一个总和的值设置为大于原始元素值,而不是总的最大值

为了纠正这一点,我尝试将Vb转换为[SxKxB]立方体,以便计算所有s、k、b对的和,然后在CPU上最大化每个s的元素。内核如下所示:

__global__ void kernel2(float *Vb, int *sS, int *sE, int *bI, float *eR, int S, int K, int B, int N)
{
    const unsigned long long int blockId = blockIdx.x //1D
        + blockIdx.y * gridDim.x //2D
        + gridDim.x * gridDim.y * blockIdx.z; //3D
    const unsigned long long int threadId = blockId * blockDim.x + threadIdx.x;
    int s = threadId / (K * B), k = (threadId - (s * K * B)) / B, b = threadId - (s * K * B) - (k * B);

    if (s < S && k < K && b < B)
    {
        float sum = 0;

        for (int t = sS[k]; t <= sE[k]; t++)
            sum += eR[s * N + bI[b * N + t]];

        Vb[s * K * B + k * B + b] = sum;
    }
}
这适用于相对较小的S、K和B,但当S=100000、K=12、B=1000较大时,Vb矩阵的内存需求约为4.5GB,远远超过设备可用内存约600-700MB

因此,我的问题是: 1.有没有办法让第一个内核按照预期工作,最终获得最大和? 2.在处理大型数据集时,您认为解决此问题的最佳方法是什么? A.将数据分割成多个块并运行多个内核2实例?我认为这大大增加了计算所需的时间 B投资于具有更大内存能力的硬件? C我已经读到,有可能直接使用零内存拷贝设备的主机内存,但我不熟悉它现在是如何工作的。这可能是一个解决方案吗?所以我可以专注于学习和实施它 D另一种方法请建议…越简单越好

对于第一个问题,最好采用积极有效的解决方案


我的设备是GeForce GT 220,总内存为1GB,计算能力为1.2最新驱动程序。我在Windows 8.1 64位上的VS2012中使用CUDA5.5。

您可以实现并使用atomicMax的浮点版本,但性能可能不好-尤其是在CC 1.2设备上。也许值得一试

借用自:

然后:


原子学是我的答案。似乎使用atomicMax带来的额外开销通过CPU端更高效的处理得到了补偿,因为数据矩阵的大小减小了。非常感谢你。
__device__ static float atomicMax(float* address, float val)
{
    int* address_as_i = (int*) address;
    int old = *address_as_i, assumed;
    do {
        assumed = old;
        old = ::atomicCAS(address_as_i, assumed,
            __float_as_int(::fmaxf(val, __int_as_float(assumed))));
    } while (assumed != old);
    return __int_as_float(old);
}
__global__ void kernel1(float *Vb, int *sS, int *sE, int *bI, float *eR, int S, int K, int B, int N)
{
    const unsigned long long int blockId = blockIdx.x //1D
        + blockIdx.y * gridDim.x //2D
        + gridDim.x * gridDim.y * blockIdx.z; //3D
    const unsigned long long int threadId = blockId * blockDim.x + threadIdx.x;
    int s = threadId / (K * B), k = (threadId - (s * K * B)) / B, b = threadId - (s * K * B) - (k * B);

    if (s < S && k < K && b < B)
    {
        float sum = 0;

        for (int t = sS[k]; t <= sE[k]; t++)
            sum += eR[s * N + bI[b * N + t]];

        atomicMax(Vb + b * K + k, sum);
    }
}