通过构造函数将 device_vector 存储在仿函数中?

Storing a device_vector inside a functor through the constructor?

我正在尝试将 thrust::device_vector 存储在仿函数中。简单解读如下:

struct StructOperator : public thrust::unary_function<float, int>  {
  int num_;
  thrust::device_vector<int> v_test;

  explicit StructOperator(thrust::device_vector<int> const& input_v) :
    v_test(input_v), num_(input_v.size()) {};

  __host__ __device__
   float operator()(int index) {
      // magic happens
   }
};

无法编译 - nvcc 一直说从 __host__ __device__ 调用 __host__ 是不允许的。我看到 this 问题 - 这是实现此目标的唯一方法吗?

当您将 __device__ 装饰器放在仿函数运算符上时,您现在已将在该运算符主体中可以做的事情限制为与 CUDA 设备代码兼容的事情。

A thrust::device_vector 是一个 class 定义,旨在促进推力的 expression/computation 模型(大致类似于 STL containers/algorithms)。因此它包括主机和设备代码。 thrust::device_vector 中的主机代码未修饰以供在设备上使用,普通主机代码在 CUDA 设备代码中不可用。

thrust::device_vector 并非旨在也无意直接在设备代码中使用。它不能像你建议的那样使用。与可能的推测相反,它并非设计为可在 CUDA 设备代码中使用的 std::vector 的模拟。它被设计为可用于推力算法的 std::vector 的模拟(根据设计,来自主机代码的 callable/usable)。这就是您在编译时收到消息的原因,并且没有简单的方法 (*) 可以解决这个问题。

据推测,thrust::device_vector 的主要目的是作为一个容器来保存设备上 usable/accessible 的数据。 CUDA 设备代码已经支持的 POD 类型数据中最直接的等价物是数组或指向数据的指针。

因此我认为用 "yes" 来回答您的问题是合理的 - 这是实现此目的的唯一方法。

  • 我将各种类似的方法归为一类,例如传递推力指针而不是裸指针。
  • (*)我忽略了这样的想法,例如编写允许在设备上使用的自己的容器 class,或者进行大量修改以推动自身以某种方式允许这种行为。

这是一个完整的示例,围绕您所展示的内容:

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


struct StructOperator : public thrust::unary_function<float, int>  {
  int num_;
  int *v_test;

  explicit StructOperator(int *input_v, int input_v_size) :
    v_test(input_v), num_(input_v_size) {};

  __host__ __device__
   float operator()(int index) {
      if (index < num_)  return v_test[index] + 0.5;
      return 0.0f;
   }
};

const int ds = 3;
int main(){

  thrust::device_vector<int> d(ds);
  thrust::sequence(d.begin(), d.end());
  thrust::device_vector<float> r(ds);
  thrust::transform(d.begin(), d.end(), r.begin(), StructOperator(thrust::raw_pointer_cast(d.data()), d.size()));
  thrust::copy(r.begin(), r.end(), std::ostream_iterator<float>(std::cout, ","));
  std::cout << std::endl;
}
$ nvcc t1385.cu -o t1385
$ ./t1385
0.5,1.5,2.5,
$