在Thrust中的函数内使用多态函子 [英] Using polymorphic functors inside functions in Thrust

查看:623
本文介绍了在Thrust中的函数内使用多态函子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个函数来计算GPU上几个变量的一些数学函数。我决定使用Thrust及其 zip_iterator 在一个元组中打包变量,并将我的数学函数实现为一个函数foka for_each 。但我想有一个通用的函数,可以计算不同的数学函数。所以,我需要在函数中传递这个函子。

I need a function that computes some "math" function of several variables on GPU. I decided to use Thrust and its zip_iterator to pack variables in a tuple, and implement my math function as a functor foк for_each. But I'd like to have a universal function that can compute different "math" functions. So, I need to pass this functor in the function.

我认为,为了做这个任务,我应该实现一些简单的层次结构(只有基类)的函数不同版本的 ()(Tuple t)。例如,函子可以是这样的:

As I think, to do this task, I should implement some simple hierarchy (with the only base class) of functors with different versions of operator()(Tuple t). For example, functors can be like these:

struct Func {
    template <typename Tuple>
    __host__ __device__
    void operator()(Tuple arg) {
        thrust::get<1>(arg) = 0;
    }
};

strust f1 : public Func {
   ...
};

strust f2 : public Func {
   ...
};



< ?这个函数可以是:

The question is how can I properly pass required functor into the function, and how to define such a function? This function can be like:

thrust::host_vector evaluateFunction(Func func, thrust::host_vector point) {
    thrust::host_vector result(point.size());

    thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(point.begin(), result.begin())),
    thrust::make_zip_iterator(thrust::make_tuple(point.end(), result.end())),
                 func);
    return result;
}

但是这样的定义不能通过 f1 f2 。如何正确定义?

but with such a definition I cannot pass f1 or f2 into it. How can I define it properly?

推荐答案

看起来你想传递一个用户定义或用户可选择的函数来推测函数。基于这一点,我认为一个可能的答案非常类似于这里,但我会提出一些其他意见。

It appears that you want to pass a user-defined or user-selectable function to thrust, for evaluation in a functor. Based on that, I think a possible answer is very similar to what is posted here, however I'll make some other comments.


  1. 我认为你实际上是在询问这个问题,但我认为在主机类中表示的多态性,最终传递给设备以在 thrust :: device_vector 中使用的对象基本上是不可能的,因为不允许作为参数传递给 __ global __ function一个带有虚函数的类的对象。虽然不是很明显,但是如果我在主机上创建了一个合适的对象数组,然后尝试多态使用在 thrust :: device_vector 中。至少,我不能打我的方式通过丛林。您可以在设备代码中使用多态性,当然,假设对象在设备上正确创建,以便可以正确分配其虚拟函数表。 此问题和意见也可能感兴趣。如果您想查看在设备对象上使用多态性的示例,请查看我的答案这里。它演示了使用对象本身来定义您希望对其执行的函数的想法。 (虽然,我不认为这是你的想法。)

  2. 根据您编辑的问题,似乎你想传递函数的地址,用于函子。这也是(至少以直接的方式)不可能与CUDA,因为不允许在主机代码中使用 __ device __ 函数的地址。这种限制可以通过调用一个初始化内核,它填充了用于设备代码的设备函数指针表,但我认为净效果不如我在下面3中建议的更好。

  3. 可以传递用户可选择的功能索引,用于在设备代码中使用。

  1. I don't think you were actually asking about this, but I think polymorphism expressed in host classes, objects of which that are eventually passed to the device for use in a thrust::device_vector would be essentially impossible, because It is not allowed to pass as an argument to a __global__ function an object of a class with virtual functions. Although it's not entirely obvious, this is in effect what I would be doing if I created an appropriate array of objects on the host and then attempted to use them polymorphically in a thrust::device_vector. At least, I could not fight my way through the jungle. You can use polymorphism in device code, of course, assuming the objects are correctly created on the device so that their virtual function tables can be properly assigned. This question and comments may also be of interest. If you want to see an example of using polymorphism on device objects, take a look at my answer here. It demonstrates the idea of using the object itself to define the function you wish to perform on it. (Although, again, I don't think that is what you had in mind.)
  2. Based on your edited question, it appears that you'd like to pass the address of a function, for use in a functor. This is also (at least in a straightforward manner) impossible with CUDA, because it is not allowed to take the address of a __device__ function in host code. This limitation can be worked around, after a fashion, by calling an "initialization kernel" which fills in a table of device function pointers for use in device code, but I think the net effect is no better than what I propose in 3 below.
  3. You can pass a user-selectable index of a function, for use in device code.

以下是一个演示最后这个想法的例子:

Here's an example which demonstrates this last idea:

#include <thrust/device_vector.h>
#include <thrust/sequence.h>
#include <thrust/copy.h>
#include <thrust/for_each.h>
#include <thrust/iterator/zip_iterator.h>
#include <iostream>
#include <math.h>


__host__ __device__ float f1(float x)
{
  return sinf(x);
}

__host__ __device__ float f2(float x)
{
  return cosf(x);
}



struct select_functor
{
  unsigned fn;

  select_functor(unsigned _fn) : fn(_fn) {};
  template <typename Tuple>
  __host__ __device__
  void operator()(const Tuple &t) {
    if (fn == 1) thrust::get<1>(t)  = f1(thrust::get<0>(t));
    else if (fn == 2) thrust::get<1>(t)  = f2(thrust::get<0>(t));
    else thrust::get<1>(t) = 0;
  }
};


int main(void)
{
  unsigned ufn = 1;
  const unsigned N = 8;
  thrust::device_vector<float> data(N), result(N);
  // initilaize to some values
  thrust::sequence(data.begin(), data.end(),  0.0f, (float)(6.283/(float)N));
  std::cout<< "x: " << std::endl;
  thrust::copy(data.begin(), data.end(), std::ostream_iterator<float>(std::cout, " "));
  thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(data.begin(), result.begin())),thrust::make_zip_iterator(thrust::make_tuple(data.end(),result.end())),select_functor(ufn));
  std::cout<< std::endl << "sin(x): " << std::endl;
  thrust::copy(result.begin(), result.end(), std::ostream_iterator<float>(std::cout, " "));
  ufn = 2;
  thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(data.begin(), result.begin())),thrust::make_zip_iterator(thrust::make_tuple(data.end(),result.end())),select_functor(ufn));
  std::cout<< std::endl << "cos(x): " << std::endl;
  thrust::copy(result.begin(), result.end(), std::ostream_iterator<float>(std::cout, " "));
  std::cout<< std::endl;
  return 0;
}

这篇关于在Thrust中的函数内使用多态函子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆