【问题标题】:creating Thrust::device_vectors in a __host__ __device__ functor在 __host__ __device__ 函子中创建 Thrust::device_vectors
【发布时间】:2016-07-22 14:44:50
【问题描述】:

我目前正在尝试并行化当前在主函数中顺序运行的推力 cuda 代码(因此不利用 GPU 的功能)。我基本上已经将功能代码放入一个仿函数中,thrust::for_each 可以使用 cuda 流调用。但是,如果我使用

定义函子
__host__ __device__ 

VS2013 抛出各种警告,说我正在尝试从设备启动主机功能。这些错误发生在我使用定义向量的地方

thrust::device_vector vect (size_vector); 

以及一些推力::转换函数。它特别引用了thrust::device_malloc_allocator 的问题。如果我将函子严格定义为 host 函子,这些错误都会消失,但是当我使用分析器时,很明显只有 0.01% 的设备被使用,这让我相信 for_each 实际上并不是在函子中启动推力代码。

编辑 下面是一些编译并显示此错误的代码

#include <iostream>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/sort.h>
#include <thrust/execution_policy.h>
#include <thrust/for_each.h>
#include <thrust/sequence.h>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>
#include <memory.h>
#include <cstdio>
#include <thread>
#include <thrust/copy.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/reduce.h>


using namespace std;

const int num_segs = 1;  // number of segments to sort
const int num_vals = 5;  // number of values in each segment


template <typename T> 
struct sort_vector
{
    T *Ddata;
    T *vect3;
    T *answer;

    sort_vector(T *_Ddata, T *_vect3, float *a) : Ddata(_Ddata), vect3(_vect3), answer(a) {};


    __host__ __device__ void operator()(int idx)
    {
        thrust::sort(thrust::seq, Ddata + idx*num_vals, Ddata + ((idx + 1)*num_vals));
        thrust::device_ptr<float> vect3_ptr = thrust::device_pointer_cast(vect3);
        thrust::device_vector<float> vect(10, 1);
        thrust::device_vector<float> vect2(10, 3);
        thrust::transform(thrust::device, vect.begin(), vect.end(), vect2.begin(), vect3_ptr, thrust::minus<float>());
        *answer = thrust::reduce(thrust::device, Ddata + idx*num_vals, Ddata + ((idx + 1)*num_vals));

    }
};

int main() {

    thrust::device_vector<float> d_Ddata(num_segs*num_vals);
    d_Ddata[0] = 50;
    d_Ddata[1] = 9.5;
    d_Ddata[2] = 30;
    d_Ddata[3] = 8.1;
    d_Ddata[4] = 1;

    thrust::device_vector<float> d_Ddata2(num_segs*num_vals);
    d_Ddata2[0] = 50;
    d_Ddata2[1] = 20.5;
    d_Ddata2[2] = 70;
    d_Ddata2[3] = 8.1;
    d_Ddata2[4] = 1;

    thrust::device_vector<float> vect3(10, 0);
    thrust::device_vector<float> vect4(10, 0);

    cout << "original dut" << endl;
    int g = 0;
        while (g < num_segs*num_vals){
            cout << d_Ddata[g] << endl;
            g++;
        }

        thrust::device_vector<int> d_idxs(num_segs);
        thrust::sequence(d_idxs.begin(), d_idxs.end());

        thrust::device_vector<float> dv_answer(1);
        thrust::device_vector<float> dv_answer2(1);
        cudaStream_t s1, s2;
        cudaStreamCreate(&s1);
        cudaStreamCreate(&s2);

        clock_t start;
        double duration;
        start = clock();

        thrust::for_each(thrust::cuda::par.on(s1),
            d_idxs.begin(),
            d_idxs.end(), sort_vector<float>(thrust::raw_pointer_cast(d_Ddata.data()), thrust::raw_pointer_cast(vect3.data()), thrust::raw_pointer_cast(dv_answer.data())));

        thrust::for_each(thrust::cuda::par.on(s2),
            d_idxs.begin(),
            d_idxs.end(), sort_vector<float>(thrust::raw_pointer_cast(d_Ddata2.data()), thrust::raw_pointer_cast(vect4.data()), thrust::raw_pointer_cast(dv_answer2.data())));

        cudaStreamSynchronize(s1);
        cudaStreamSynchronize(s2);

        cout << "sorted dut" << endl;
        int n = 0;
        while (n < num_segs*num_vals){
            cout << d_Ddata[n] << endl;
            n++;
        } 
        cout << "sum" << endl;
        cout << dv_answer[0] << endl;
        cout << dv_answer2[0] << endl;

        cout << "vector subtraction" << endl;
        int e = 0;
        while (e < 10){
            cout << vect3[e] << endl;
            e++;
        }

        cudaStreamDestroy(s1);
        cudaStreamDestroy(s2);

        duration = (clock() - start) / (double)CLOCKS_PER_SEC;
        cout << "time " << duration << endl;

        cin.get();
        return 0;
    }

是否有可能thrust::for_each 不能调用__host__ 函子?

某些推力呼叫是否与幕后的主机天生相关?

我能看到的唯一可能的解决方法是创建一个__host__ __device__ fucntor,其中包含单独的主机和设备定义代码。在研究这个主题时,我也可能遗漏了一些东西。任何建议将不胜感激。

【问题讨论】:

标签: c++ parallel-processing cuda thrust


【解决方案1】:

这些错误发生在我定义向量的地方

正如编译器清楚地告诉你的那样,问题在于thrust::vector 中定义的构造函数和所有运算符目前是仅限主机 函数。尝试在 __device__function 中使用它们是非法的。

除了不尝试在设备代码中实例化向量之外,没有其他解决方案。

【讨论】:

  • 是的,这就是我认为的问题所在。但是,将其更改为宿主代码会导致 for_each 调用失败并且根本不调用函子。所以你的意思是没有解决办法?也许是这样的? stackoverflow.com/questions/30029197/…
  • @gracie:在您现在发布的代码中的解决方法是从仿函数中删除设备向量。你甚至没有将它用于任何事情。
  • 我意识到它在我发布的代码中没有做任何事情。这只是显示此操作产生的警告的一个示例,因为我正在尝试在更大的程序中使用此技术。
  • 很抱歉,我无法为您提供我看不到的问题的解决方案。如果您发布带有非代表性示例的非代表性问题,则无法合理地期望得到准确的答案。
  • 我已经更新了代码以使其更具代表性。
【解决方案2】:

Thrust 为其所有算法提供主机和设备路径,但算法只能从主机启动。

在编译时,Thrust 查看迭代器的类型以确定要构建的路径。如果它构建设备路径,则与常规 CUDA 代码相同的限制适用,其中之一是设备代码不能调用主机上的函数。

因此,像thrust::sort() 这样的语句会启动一个算法,并且只能存在于主机代码中。在编译时,传递给sort() 的迭代器被检查并且推力模板用于构建处理您的特定类型的sort() 的主机或设备版本。如果构建了一个设备版本并且它需要一个仿函数,那么它也必须可以构建一个仿函数的设备版本,这意味着仿函数不能包含启动新算法的 Thrust 语句。

在运行时,像 thrust::sort() 这样的语句的设备版本将启动一个或多个 CUDA 内核,因此您可能想要研究的是 Thrust 将单独的算法组合到同一个内核中的能力,这被 Thrust 称为内核融合。有几种方法可以做到这一点,其中一种是使用转换迭代器。有关详细信息,请参阅 Thrust 文档。

【讨论】:

  • 推力算法可以从设备代码启动。这个答案是不正确的。 OP 已经提出了几个问题,证明推力算法可以从设备代码中启动。
  • 我可以清楚地看到有些可以从设备代码启动,但似乎有些不能。只是有些不能(至少以我使用的形式)专门转换和设备向量分配吗?这些在图书馆中的设置是否不同?我尝试发送推力::设备和推力::seq 标志,但它仍然抛出一堆错误并且没有工作。
  • 设备向量不是算法。您可能需要阅读推力快速入门指南。 thrust::device_vector(这是一个容器,而不是算法)不能在设备代码中使用,正如其他答案已经向您指出的那样。而且,不,thrust::for_each(或任何算法)不能使用 __host__(仅)函子,如果该算法正在处理设备数据。
  • 哦,我明白了。这现在更有意义了。同样,当容器正确传递时,thrust::transform 的错误也会消失。所以这解决了我的问题。谢谢。
猜你喜欢
  • 2020-10-29
  • 2021-08-30
  • 1970-01-01
  • 1970-01-01
  • 2016-01-18
  • 2020-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多