如何解决CUDA Thrust库-for_each同步错误?

3
我正在尝试使用CUDA的thrust库修改一个简单的动态向量。但是屏幕上显示“launch_closure_by_value”错误,指示错误与某些同步过程有关。
由于此错误,不可能对简单的1D动态数组进行修改。
导致错误的代码片段如下所示。
从.cpp文件中调用setIndexedGrid,该函数在System.cu中定义。
float* a= (float*)(malloc(8*sizeof(float))); 
a[0]= 0; a[1]= 1; a[2]= 2; a[3]= 3; a[4]= 4; a[5]= 5; a[6]= 6; a[7]= 7;
float* b = (float*)(malloc(8*sizeof(float)));
setIndexedGridInfo(a,b);

System.cu中的代码段:

void
setIndexedGridInfo(float* a, float*b)
{

    thrust::device_ptr<float> d_oldData(a);
    thrust::device_ptr<float> d_newData(b);

    float c = 0.0;

    thrust::for_each(
        thrust::make_zip_iterator(thrust::make_tuple(d_oldData,d_newData)),
        thrust::make_zip_iterator(thrust::make_tuple(d_oldData+8,d_newData+8)),
        grid_functor(c));
}

grid_functor在_kernel.cu中定义。

struct grid_functor
{
    float a;

    __host__ __device__
    grid_functor(float grid_Info) : a(grid_Info) {}

    template <typename Tuple>
    __device__
    void operator()(Tuple t)
    {
        volatile float data = thrust::get<0>(t);
        float pos = data + 0.1;
        thrust::get<1>(t) = pos;
    }

};

我也在Output窗口(我使用Visual Studio)上看到了以下内容:

在Particles.exe中,地址为0x000007fefdc7cacd处发生了一次C++异常:cudaError_enum,内存地址为0x0029eb60。在smokeParticles.exe中,地址为0x000007fefdc7cacd处发生了一次C++异常:thrust::system::system_error,内存地址为0x0029ecf0。在Particles.exe中,地址为0x000007fefdc7cacd处发生了一次未处理的C++异常:thrust::system::system_error,内存地址为0x0029ecf0。

导致这个问题的原因是什么?
1个回答

5
您正在尝试在期望设备内存指针的函数中使用主机内存指针。这段代码是问题的根源:
float* a= (float*)(malloc(8*sizeof(float))); 
a[0]= 0; a[1]= 1; a[2]= 2; a[3]= 3; a[4]= 4; a[5]= 5; a[6]= 6; a[7]= 7;
float* b = (float*)(malloc(8*sizeof(float)));
setIndexedGridInfo(a,b);

.....

thrust::device_ptr<float> d_oldData(a);
thrust::device_ptr<float> d_newData(b);

thrust::device_ptr旨在“包装”使用CUDA API分配的设备内存指针,以便thrust可以使用它。您正在尝试直接将主机指针视为设备指针。那是非法的。您可以像这样修改您的setIndexedGridInfo函数:

void setIndexedGridInfo(float* a, float*b, const int n)
{

    thrust::device_vector<float> d_oldData(a,a+n);
    thrust::device_vector<float> d_newData(b,b+n);

    float c = 0.0;

    thrust::for_each(
        thrust::make_zip_iterator(thrust::make_tuple(d_oldData.begin(),d_newData.begin())),
        thrust::make_zip_iterator(thrust::make_tuple(d_oldData.end(),d_newData.end())),
        grid_functor(c));
}
device_vector构造函数将分配设备内存,然后将主机内存的内容复制到设备中。这应该可以解决您所看到的错误,尽管我不确定您正在尝试使用for_each迭代器以及您编写的函数对象是否正确。


编辑:

以下是您的完整、可编译、可运行代码:

#include <cstdlib>
#include <cstdio>
#include <thrust/device_vector.h>
#include <thrust/for_each.h>
#include <thrust/copy.h>

struct grid_functor
{
    float a;

    __host__ __device__
    grid_functor(float grid_Info) : a(grid_Info) {}

    template <typename Tuple>
    __device__
    void operator()(Tuple t)
    {
        volatile float data = thrust::get<0>(t);
        float pos = data + 0.1f;
        thrust::get<1>(t) = pos;
    }

};

void setIndexedGridInfo(float* a, float*b, const int n)
{

    thrust::device_vector<float> d_oldData(a,a+n);
    thrust::device_vector<float> d_newData(b,b+n);

    float c = 0.0;

    thrust::for_each(
        thrust::make_zip_iterator(thrust::make_tuple(d_oldData.begin(),d_newData.begin())),
        thrust::make_zip_iterator(thrust::make_tuple(d_oldData.end(),d_newData.end())),
        grid_functor(c));

    thrust::copy(d_newData.begin(), d_newData.end(), b);
}

int main(void)
{
    const int n = 8;
    float* a= (float*)(malloc(n*sizeof(float))); 
    a[0]= 0; a[1]= 1; a[2]= 2; a[3]= 3; a[4]= 4; a[5]= 5; a[6]= 6; a[7]= 7;
    float* b = (float*)(malloc(n*sizeof(float)));
    setIndexedGridInfo(a,b,n);

    for(int i=0; i<n; i++) {
        fprintf(stdout, "%d (%f,%f)\n", i, a[i], b[i]);
    }

    return 0;
}

我可以在装有CUDA 4.1的OS 10.6.8主机上,按如下方式编译并运行此代码:

$ nvcc -Xptxas="-v" -arch=sm_12 -g -G thrustforeach.cu 
./thrustforeach.cu(18): Warning: Cannot tell what pointer points to, assuming global memory space
./thrustforeach.cu(20): Warning: Cannot tell what pointer points to, assuming global memory space
./thrustforeach.cu(18): Warning: Cannot tell what pointer points to, assuming global memory space
./thrustforeach.cu(20): Warning: Cannot tell what pointer points to, assuming global memory space
ptxas info    : Compiling entry function '_ZN6thrust6detail7backend4cuda6detail23launch_closure_by_valueINS2_18for_each_n_closureINS_12zip_iteratorINS_5tupleINS0_15normal_iteratorINS_10device_ptrIfEEEESB_NS_9null_typeESC_SC_SC_SC_SC_SC_SC_EEEEi12grid_functorEEEEvT_' for 'sm_12'
ptxas info    : Used 14 registers, 160+0 bytes lmem, 16+16 bytes smem, 4 bytes cmem[1]
ptxas info    : Compiling entry function '_ZN6thrust6detail7backend4cuda6detail23launch_closure_by_valueINS2_18for_each_n_closureINS_12zip_iteratorINS_5tupleINS0_15normal_iteratorINS_10device_ptrIfEEEESB_NS_9null_typeESC_SC_SC_SC_SC_SC_SC_EEEEj12grid_functorEEEEvT_' for 'sm_12'
ptxas info    : Used 14 registers, 160+0 bytes lmem, 16+16 bytes smem, 4 bytes cmem[1]

$ ./a.out
0 (0.000000,0.100000)
1 (1.000000,1.100000)
2 (2.000000,2.100000)
3 (3.000000,3.100000)
4 (4.000000,4.100000)
5 (5.000000,5.100000)
6 (6.000000,6.100000)
7 (7.000000,7.100000)

我完全误解了推力的概念。我以为它也可以传递主机数组。我只是想尝试将每个元素增加0.1,只是为了练习。谢谢你的帮助。 - Emre Turkoz
但是这个device_vector初始化不起作用。device_vector<float>是不够的。device_vector还需要一个typename Alloc:device_vector<float, ?>。 - Emre Turkoz
1
相信我,它可以。我在更改您的for_each调用时犯了一个小的语法错误。看看新版本。我现在已经使用编译器进行了检查,并且在计算1.2设备上使用CUDA 4.1运行良好。 - talonmies
我已经包含了一个完整可运行的示例,展示了我建议的修改并且可以正确编译和运行。如果这对你不起作用,我实在无法再提供更多建议了。 - talonmies

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接