CUDA推力设备指针与变换复制崩溃

时间:2018-06-11 14:49:45

标签: cuda thrust

在CUDA 9.2中,我有类似的东西:

#ifdef __CUDA_ARCH__
    struct Context { float n[4]; } context;
#else
    typedef __m128 Context;
#endif
struct A { float k[2]; };
struct B { float q[4]; };


struct FTransform : thrust::unary_function<A, B>
{
    const Context context;


    FTransform(Context context) : context(context){}


    __device__ __host__ B operator()(const A& a) const
    {
        B b{{a.k[0], a.k[1], a.k[0]*context.n[0], a.k[1]*context.n[1]}};



        return b;
    }
};


void DoThrust(B* _bs, const Context& context, A* _as, uint32_t count)
{
    thrust::device_ptr<B> bs = thrust::device_pointer_cast(_bs);
    thrust::device_ptr<A> as = thrust::device_pointer_cast(_as);

    FTransform fTransform(context);

    auto first = thrust::make_transform_iterator(as, fTransform);
    auto last = thrust::make_transform_iterator(as + count, fTransform);


    thrust::copy(first, last, bs);
}


int main(int c, char **argv)
{
    const uint32_t Count = 4;
    Context context;

    A* as;
    B* bs;

    cudaMalloc(&as, Count*sizeof(A));
    cudaMalloc(&bs, Count*sizeof(B));

    A hostAs[Count];
    cudaMemcpy(as, hostAs, Count * sizeof(A), cudaMemcpyHostToDevice);


    DoThrust(bs, context, as, Count);


        B hostBs[Count];
        cudaMemcpy(hostBs, bs, Count * sizeof(B), cudaMemcpyDeviceToHost);//crash

return 0;
    }

然后,当我稍后调用标准cudaMemcpy()调用结果时,我得到异常“遇到非法内存访问”。

如果我用非推力等效物替换推力代码,则没有错误,一切正常。试图复制到device_vectors等的各种组合我得到了不同的崩溃,似乎试图释放device_ptr由于某种原因 - 所以也许它出于某种原因?

== UPDATE ==

好吧这令人困惑它似乎是由于我实际更复杂的情况下的仿函数FTransform上下文成员变量。具体如下:

struct FTransform : thrust::unary_function<A, B>
{
    #ifdef __CUDA_ARCH__
        struct Context { float v[4]; } context;
    #else
        __m128 context;
    #endif
    ...
};

所以我猜这是一个对齐问题,某种方式=&gt;事实上它是,因为这是有效的:

#ifdef __CUDA_ARCH__
    struct __align__(16) Context { float v[4]; } context;
#else
    __m128 context;
#endif

1 个答案:

答案 0 :(得分:-2)

解决方案是确保如果在复制到GPU的推力仿函数成员(例如__m128 SSE类型)中使用对齐类型,则在NVCC的CPU和GPU代码构建过程中将它们定义为对齐 - 而不是意外地假设,即使某种类型似乎自然地与另一种类型相对应,它也可以正常,因为否则很难理解可能发生的事情。

所以例如在这样的代码中需要_ align _(16):

struct FTransform : thrust::unary_function<A, B>
{
#ifdef __CUDA_ARCH__
    struct __align__(16) Context { float v[4]; } context;
#else
    __m128 context;
#endif


    FTransform(Context context) : context(context){}
    __device__ __host__ B operator()(const A& a) const; // function makes use of context
};