CUDA C诉Thrust,我错过了什么吗?

Tyl*_*eau 4 linux cuda nvcc thrust

我刚开始学习CUDA编程.我正在通过一些简单的CUDA C例子,一切都在游泳.然后!突然!推力!我认为自己熟悉的C++函数子和在之间的区别感到吃惊CUDA CThrust

我觉得很难相信

__global__ void square(float *a, int N) {
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    if (idx < N) {
        a[idx] = a[idx] * a[idx];
    }
}

int main(int argc, char** argv) {

float *aHost, *aDevice;

const int N = 10;
size_t size = N * sizeof(float);

aHost = (float*)malloc(size);
cudaMalloc((void**)&aDevice, size);

for (int i = 0; i < N; i++) {
    aHost[i] = (float)i;
}

cudaMemcpy(aDevice, aHost, size, cudaMemcpyHostToDevice);

int block = 4;
int nBlock = N/block + (N % block == 0 ? 0:1);

square<<<nBlock, block>>>(aDevice, N);

cudaMemcpy(aHost, aDevice, size, cudaMemcpyDeviceToHost);

for (int i = 0; i < N; i++) {
    printf("%d, %f\n", i, aHost[i]);
}

free(aHost);
cudaFree(aDevice);
}
Run Code Online (Sandbox Code Playgroud)

是等价的

template <typename T>
    struct square {
    __host__ __device__ T operator()(const T& x) const {
        return x * x;
    }
}; 

int main(int argc, char** argv) {
    const int N = 10;
    thrust::device_vector<float> dVec(N);
    thrust::sequence(dVec.begin(), dVec.end());
    thrust::transform(dVec.begin(), dVec.end(), dVec.begin(), square<float>());
    thrust::copy(dVec.begin(), dVec.end(), std::ostream_iterator<float>(std::cout, "\n"));
}
Run Code Online (Sandbox Code Playgroud)

我错过了什么吗?上面的代码是在GPU上运行的吗?Thrust是一个很好的工具,但我怀疑它会处理所有繁重的C风格的内存管理.

  • Thrust被在GPU上执行的代码?我该怎么说?
  • 如何Thrust消除唤起内核的奇怪语法?
  • Thrust实际上是在唤起内核吗?
  • 是否Thrust自动处理线程索引计算?

谢谢你的时间.对不起,如果这些都是愚蠢的问题,但我发现我看到的例子很快就从可以被描述为Model T转变为M3.

mac*_*las 6

大概:是的,当然.Thrust是一个图书馆,所以它们都是为了让它变得更容易而诞生的.它的重点在于避免使用所有显式的CUDA代码,这对于其他程序员来说看起来很奇怪,提供了一个友好的类似C++的接口.

Thrust使用GPU,但不仅仅是 GPU.如果您编写自己的代码,它会进行相同的操作,即用于分配内存,复制,设置网格和块大小的C/C++代码......然后调用GPU执行内核.

对于那些不想进入低级CUDA内容但是在一个简单(但频繁)的问题中利用GPU并行性的人来说,这是一个很好的选择,比如矢量操作.

  • 是的,它调用你的*functor*,作为*内核*的一部分,它在"引擎盖下"创建.Thrust是一个开源库; 你可以自己检查一下.还有GPU分析工具可以用来确认推力确实在使用GPU.关于线程的分配,当创建大量输出时,在CUDA编程中为每个输出元素分配一个线程是一种常见策略.看看你的仿函数和整体算法,我观察到输入和输出之间存在1:1的关系(通常是`transform`),所以每个数据元素一个线程是有意义的. (2认同)