【问题标题】:Problem feeding Thrust vector into getrf/getri将推力向量输入 getrf/getri 时出现问题
【发布时间】:2019-04-24 16:47:42
【问题描述】:

继续我的 CUDA 初学者冒险,我被介绍给 Thrust,这似乎是一个方便的库,可以为我省去显式内存(取消)分配的麻烦。

我已经尝试将它与一些 cuBLAS 例程结合起来,例如gemv,通过使用thrust::raw_pointer_cast(array.data()) 生成指向底层存储的原始指针,然后将其提供给例程,它工作得很好。

当前任务是求矩阵的逆,为此我使用getrfBatchedgetriBatched。来自文档:

cublasStatus_t cublasDgetrfBatched(cublasHandle_t handle,
                                   int n, 
                                   double *Aarray[],
                                   int lda, 
                                   int *PivotArray,
                                   int *infoArray,
                                   int batchSize);

在哪里

Aarray - device - array of pointers to <type> array

当然,我认为我可以使用另一层推力向量来表达这个指针数组并再次将其原始指针提供给 cuBLAS,所以这就是我所做的:

void test()
{
    thrust::device_vector<double> in(4);
    in[0] = 1;
    in[1] = 3;
    in[2] = 2;
    in[3] = 4;
    cublasStatus_t stat;
    cublasHandle_t handle;
    stat = cublasCreate(&handle);
    thrust::device_vector<double> out(4, 0);
    thrust::device_vector<int> pivot(2, 0);
    int info = 0;
    thrust::device_vector<double*> in_array(1);
    in_array[0] = thrust::raw_pointer_cast(in.data());
    thrust::device_vector<double*> out_array(1);
    out_array[0] = thrust::raw_pointer_cast(out.data());
    stat = cublasDgetrfBatched(handle, 2,
        (double**)thrust::raw_pointer_cast(in_array.data()), 2,
        thrust::raw_pointer_cast(pivot.data()), &info, 1);
    stat = cublasDgetriBatched(handle, 2,
        (const double**)thrust::raw_pointer_cast(in_array.data()), 2,
        thrust::raw_pointer_cast(pivot.data()),
        (double**)thrust::raw_pointer_cast(out_array.data()), 2, &info, 1);
}

执行时,stat 表示 CUBLAS_STATUS_SUCCESS (0)info 表示 0(执行成功),但如果我尝试使用标准括号表示法访问 inpivotout 的元素,我打了一个thrust::system::system_error。在我看来,相应的内存不知何故损坏了。

我在这里遗漏了什么明显的东西?

【问题讨论】:

    标签: c++ cuda thrust cublas


    【解决方案1】:

    cublas&lt;t&gt;getrfBatcheddocumentation 表示infoArray 参数应为指向设备内存的指针。

    相反,您传递了一个指向主机内存的指针:

    int info = 0;
    ...
    stat = cublasDgetrfBatched(handle, 2,
        (double**)thrust::raw_pointer_cast(in_array.data()), 2,
        thrust::raw_pointer_cast(pivot.data()), &info, 1);
                                                ^^^^^
    

    如果您使用cuda-memcheck 运行您的代码(在我看来,任何时候您在使用 CUDA 代码时遇到问题,向其他人寻求帮助之前,这始终是一个好习惯),您将收到一个“大小为 4 的无效全局写入”的错误。这是因为cublasDgetrfBatched() 启动的内核试图使用您提供的普通主机指针将info 数据写入设备内存,这在CUDA 中始终是非法的。

    CUBLAS 本身不会出于性能原因捕获此类错误。然而,在某些情况下,thrust API 使用更严格的同步和错误检查。因此,在此错误之后使用推力代码会报告错误,即使该错误与推力无关(这是先前内核启动的异步报告错误)。

    解决方案很简单;为info提供设备存储:

    $ cat t329.cu
    #include <thrust/device_vector.h>
    #include <cublas_v2.h>
    #include <iostream>
    
    void test()
    {
        thrust::device_vector<double> in(4);
        in[0] = 1;
        in[1] = 3;
        in[2] = 2;
        in[3] = 4;
        cublasStatus_t stat;
        cublasHandle_t handle;
        stat = cublasCreate(&handle);
        thrust::device_vector<double> out(4, 0);
        thrust::device_vector<int> pivot(2, 0);
        thrust::device_vector<int> info(1, 0);
        thrust::device_vector<double*> in_array(1);
        in_array[0] = thrust::raw_pointer_cast(in.data());
        thrust::device_vector<double*> out_array(1);
        out_array[0] = thrust::raw_pointer_cast(out.data());
        stat = cublasDgetrfBatched(handle, 2,
            (double**)thrust::raw_pointer_cast(in_array.data()), 2,
            thrust::raw_pointer_cast(pivot.data()), thrust::raw_pointer_cast(info.data()), 1);
        stat = cublasDgetriBatched(handle, 2,
            (const double**)thrust::raw_pointer_cast(in_array.data()), 2,
            thrust::raw_pointer_cast(pivot.data()),
            (double**)thrust::raw_pointer_cast(out_array.data()), 2, thrust::raw_pointer_cast(info.data()), 1);
        for (int i = 0; i < 4; i++) {
          double test = in[i];
          std::cout << test << std::endl;
          }
    }
    
    
    int main(){
    
      test();
    }
    $ nvcc -o t329 t329.cu -lcublas
    t329.cu(12): warning: variable "stat" was set but never used
    
    $ cuda-memcheck ./t329
    ========= CUDA-MEMCHECK
    3
    0.333333
    4
    0.666667
    ========= ERROR SUMMARY: 0 errors
    $
    

    您会注意到,上述代码中的这一更改适用于两个 cublas 调用,因为 infoArray 参数对两者的期望相同。

    【讨论】:

    • 好的...谢谢你第二次帮助我!
    猜你喜欢
    • 2021-03-13
    • 2019-08-29
    • 2020-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-22
    相关资源
    最近更新 更多