2

我有一个我无法解决的问题。

问题如下。

CPP代码

const int dataSize = 65535;
const int category = 10;
float data[dataSize][category];
const float threshold = 0.5f;

int cnt = 0;

// data array contains any values

for(int i=0;i<dataSize;i++)
{
    if( data[i][9] > threshold )
    {
        data[cnt][0] = data[i][0];
        data[cnt][1] = data[i][1];
        data[cnt][2] = data[i][2];
        data[cnt][3] = data[i][3];
        data[cnt][4] = data[i][4];
        data[cnt][5] = data[i][5];
        data[cnt][6] = data[i][6];
        data[cnt][7] = data[i][7];
        data[cnt][8] = data[i][8];
        data[cnt][9] = data[i][9];
        cnt++;
    }
}

通过使用此代码,我希望“数据”数组的元素被收集到超过阈值。(未超过阈值的元素对我来说并不重要。重要的是刚刚超过阈值。)

我想要在 CUDA 中以相同结果运行的代码。

所以我试着这样做。

CUDA 代码

__global__ void checkOverThreshold(float *data, float threshold, int *nCount)
{
    int idx = threadIdx.x + blockIdx.x * blockDim.x;

    if( data[idx*10+9] > threshold )
    {
        data[nCount+0] = data[idx*10+0];
        data[nCount+1] = data[idx*10+1];
        data[nCount+2] = data[idx*10+2];
        data[nCount+3] = data[idx*10+3];
        data[nCount+4] = data[idx*10+4];
        data[nCount+5] = data[idx*10+5];
        data[nCount+6] = data[idx*10+6];
        data[nCount+7] = data[idx*10+7];
        data[nCount+8] = data[idx*10+8];
        data[nCount+9] = data[idx*10+9];
        atomicAdd( nCount, 1);
    }
}

....

// kernel function call
checkOverThreshold<<< dataSize / 128, 128 >>>(d_data, treshold, d_count);

但是 CUDA 代码的结果并不是我所期望的。

它包含很多垃圾价值,甚至结果与CPP的不一样。

我认为 nCount 变量的同步问题造成了这种情况。

但是,我不知道如何解决这个问题。

请帮助我的代码。先感谢您。

4

3 回答 3

3

此代码已损坏:

    data[nCount+0] = data[idx*10+0];
    data[nCount+1] = data[idx*10+1];
    data[nCount+2] = data[idx*10+2];
    data[nCount+3] = data[idx*10+3];
    data[nCount+4] = data[idx*10+4];
    data[nCount+5] = data[idx*10+5];
    data[nCount+6] = data[idx*10+6];
    data[nCount+7] = data[idx*10+7];
    data[nCount+8] = data[idx*10+8];
    data[nCount+9] = data[idx*10+9];
    atomicAdd( nCount, 1);

如果nCount在所有这些分配过程中被修改,就会产生废话。它应该是

    int d = atomicAdd(nCount, 1);
    data[d+0] = data[idx*10+0];
    data[d+1] = data[idx*10+1];
    data[d+2] = data[idx*10+2];
    data[d+3] = data[idx*10+3];
    data[d+4] = data[idx*10+4];
    data[d+5] = data[idx*10+5];
    data[d+6] = data[idx*10+6];
    data[d+7] = data[idx*10+7];
    data[d+8] = data[idx*10+8];
    data[d+9] = data[idx*10+9];
于 2012-07-18T05:42:38.193 回答
3

您可以使用 Thrust 库中的 Stream Compaction 函数。

例如,

#include <thrust/copy.h>
// ...
const int dataSize = 65535;
struct Datum {
  float f0, f1, f2, ..., f9;
};
Datum data[dataSize];
const float threshold = 0.5f;

struct below_threshold
{
  __host__ __device__
  bool operator()(const Datum &d)
  {
    return d.f9 <= threshold;
  }
};

// data array is contains any values
Datum *new_end = thrust::remove_if(data, data + N, below_threshold());
int cnt = new_end - data;
// first cnt elements have the f9 term > threshold
// other elements are undefined

编辑:相关推力文档链接

如果您不熟悉 Thrust,这里有一个快速概述。它基本上是很多 STL 风格的容器和算法,加上一些 Boost 风格的花里胡哨。真正酷的是,如果您使用 Thrust 编写算法而不是使用自定义内核,您实际上可以在 CPU 或 GPU 上运行完全相同的算法。所以我在这里的实现草图将在 CPU 上运行,因为内存是在主 RAM 中分配的。但是如果不是使用常规数组存储数据,而是使用thrust::device_vector(很像std::vector),那么Thrust 会将您的数据复制到GPU,并且相同的thrust::remove_if() 调用配对相同的函子会产生相同的结果。我希望这能让您对 Thrust 有所了解,并鼓励您在他们的快速入门指南中找到更多信息。

于 2012-07-18T07:34:36.560 回答
1

正如 SchighSchagh 所建议的,推力将是一种方法。ArrayFire 为正在发生的事情提供了更数学的表示。

const int dataSize = 65535;
const int category = 10;
float data[dataSize][category];
const float threshold = 0.5f;

int cnt = 0;

// populate data

// Transfer to device
array Data(data, category, dataSize); // Column major
array idx = where(Data(9, span) > threshold);
Data = Data(span, idx);
于 2012-07-18T19:20:55.267 回答