【问题标题】:Thrust transform throws error: "bulk_kernel_by_value: an illegal memory access was encountered"推力变换抛出错误:“bulk_kernel_by_value:遇到非法内存访问”
【发布时间】:2016-04-25 02:28:52
【问题描述】:

我对 CUDA/Thrust 比较陌生,并且对代码 sn-p 有疑问。 为了更容易,我将其削减到最低限度。 代码如下:

struct functor{
functor(float (*g)(const float&)) : _g{g} {}

__host__ __device__ float operator()(const float& x) const { 
        return _g(x);
    }
private:
    float (*_g)(const float&);
};

__host__ __device__ float g(const float& x){return 3*x;}

int main(void){
thrust::device_vector<float> X(4,1);
thrust::transform(X.begin(), X.end(), X.begin(), functor(&g));
}

我的想法是我可以将任何函数传递给函子,因此我可以将该函数应用于向量中的每个元素。 不幸的是,我不确定为什么会收到所描述的错误。 我用-w -O3 -shared -arch=sm_20 -std=c++11 -DTHRUST_DEBUG编译

感谢大家能给我的任何帮助:)

【问题讨论】:

  • 简短的原因是 &amp;g 不是指向设备函数的指针,并且将其传递给将在 GPU 上运行的闭包是无效的

标签: c++ c++11 cuda thrust


【解决方案1】:

__device__ 函数的地址(或__host__ __device__)不能在主机代码中使用,用于设备:

thrust::transform(X.begin(), X.end(), X.begin(), functor(&g));
                                                         ^
                                                     You will not get the 
                                                     __device__ function
                                                     address here

stackoverflow 上有很多问题讨论了通过内核调用传递的 CUDA 设备函数地址的用法。 This answer 几个可能感兴趣的链接。

解决此问题的一种可能方法是在设备代码中获取设备功能地址,并将其传递给主机,以供您描述的用法:

$ cat t1057.cu
#include <thrust/device_vector.h>
#include <thrust/transform.h>
#include <thrust/copy.h>
#include <iostream>
struct functor{
functor(float (*g)(const float&)) : _g{g} {}

__host__ __device__ float operator()(const float& x) const {
        return _g(x);
    }
private:
    float (*_g)(const float&);
};

__host__ __device__ float g(const float& x){return 3*x;}

__device__ float (*d_g)(const float&) = g;

int main(void){
float (*h_g)(const float&) = NULL;
cudaMemcpyFromSymbol(&h_g, d_g, sizeof(void *));
thrust::device_vector<float> X(4,1);
thrust::transform(X.begin(), X.end(), X.begin(), functor(h_g));
thrust::copy_n(X.begin(), X.size(), std::ostream_iterator<float>(std::cout, ","));
std::cout << std::endl;
}
$ nvcc -o t1057 t1057.cu -std=c++11
$ ./t1057
3,3,3,3,
$

另一种可能的方法,利用@m.s 的一贯聪明的工作。 here 使用模板:

$ cat t1057.cu
#include <thrust/device_vector.h>
#include <thrust/transform.h>
#include <thrust/copy.h>
#include <iostream>

typedef float(*fptr_t)(const float&);

template <fptr_t F>
struct functor{

  __host__ __device__ float operator()(const float& x) const {
        return F(x);
    }
};

__host__ __device__ float g(const float& x){return 3*x;}


int main(void){
thrust::device_vector<float> X(4,1);
thrust::transform(X.begin(), X.end(), X.begin(), functor<g>());
thrust::copy_n(X.begin(), X.size(), std::ostream_iterator<float>(std::cout, ","));
std::cout << std::endl;
}
$ nvcc -o t1057 t1057.cu -std=c++11
$ ./t1057
3,3,3,3,
$

【讨论】:

  • 我认为这是做到这一点的唯一方法(尽管我对静态初始化的工作方式有点惊讶)。曾几何时,需要运行一个小的“setter”内核来获取设备函数的地址并将其设置为全局内存符号。
  • @m.s.使用模板和 c++11 here 提供了一种巧妙的方法实际上,函数地址仍在设备代码中“捕获”。
猜你喜欢
  • 1970-01-01
  • 2021-11-22
  • 2020-12-27
  • 2021-03-25
  • 2015-05-02
  • 2022-01-18
  • 2017-01-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多