Проблема с подачей вектора тяги в getrf / getri - PullRequest
0 голосов
/ 22 ноября 2018

Продолжая приключение моего новичка в CUDA, я познакомился с Thrust, который кажется удобной библиотекой, которая избавляет меня от необходимости явного (де-) выделения памяти.

Я уже пытался скомбинировать егос несколькими подпрограммами cuBLAS, например, gemv, сгенерировав необработанный указатель на базовое хранилище с помощью thrust::raw_pointer_cast(array.data()), а затем передав его в подпрограммы, и он работает просто отлично.

Текущая задача - получитьобратная матрица, и для этого я использую getrfBatched и getriBatched.Из документации:

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

Естественно, я подумал, что мог бы использовать другой слой вектора Thrust для выражения этого массива указателей и снова подать свой необработанный указатель на 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 (выполнение выполнено), но если я пытаюсь получить доступ к элементам in,pivot или out со стандартным обозначением в скобках, я нажал thrust::system::system_error.Сдается мне, что соответствующая память как-то повреждена.

Что-нибудь очевидно, что я здесь скучаю?

1 Ответ

0 голосов
/ 23 ноября 2018

Документация для cublas<t>getrfBatched указывает, что параметр 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не перехватывает подобные ошибки по соображениям производительности.Однако в некоторых случаях упорный API использует более строгую синхронизацию и проверку ошибок.Следовательно, использование кода Thrust после этой ошибки сообщает об ошибке, даже если ошибка не имела ничего общего с Thrust (это была асинхронная ошибка, возникшая при предыдущем запуске ядра).

Решение является простым;предоставить хранилище устройства для 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 имеет одинаковые ожидания для обоих.

...