Как передать динамический собственный вектор на GPU с помощью Cuda?

#c #cuda #eigen #eigen3 #gpu

#c #cuda #eigen #eigen3 #графический процессор

Вопрос:

Я собираюсь узнать, как передать динамический собственный вектор на графический процессор и получить его обратно. Для этих целей я написал тестовый код:

     using Vector = Eigen::Matrix<float, Eigen::Dynamic, 1, Eigen::ColMajor>;
    Vector vector;
    uint64_t size = 6;

    vector.resize(size);
    for (uint64_t i = 0; i < size;   i)
        vector[i] = i;

    uint64_t sizeInBytes = size * sizeof (float)   sizeof (vector);

    Vector *vectorCuda;
    cudaMalloc((void**)amp;vectorCuda, sizeInBytes);
    cudaMemcpy(vectorCuda, amp;vector, sizeInBytes, cudaMemcpyKind::cudaMemcpyHostToDevice);

    Vector resu<
    result.resize(size);
    cudaMemcpy(amp;result, vectorCuda, sizeInBytes, cudaMemcpyKind::cudaMemcpyDeviceToHost);

    cudaFree(vectorCuda);
    std::cout << "result: " << std::endl << result << std::endl;
 

Вывод:

 result: 
0
1
2
3
4
5
double free or corruption (fasttop)
 

Итак, я передал данные на GPU и получил их обратно, но я получаю ошибку SIGABRT. Ошибка возникает в std::free(ptr):

 1  __GI_raise                                                                      raise.c           50   0x7ffff660b18b 
2  __GI_abort                                                                      abort.c           79   0x7ffff65ea859 
3  __libc_message                                                                  libc_fatal.c      155  0x7ffff66553ee 
4  malloc_printerr                                                                 malloc.c          5347 0x7ffff665d47c 
5  _int_free                                                                       malloc.c          4266 0x7ffff665ede5 
6  Eigen::internal::aligned_free                                                   Memory.h          177  0x555555564e14 
7  Eigen::internal::conditional_aligned_free<true>                                 Memory.h          230  0x55555556601e 
8  Eigen::internal::conditional_aligned_delete_auto<float, true>                   Memory.h          416  0x555555565820 
9  Eigen::DenseStorage<float, -1, -1, 1, 0>::~DenseStorage                         DenseStorage.h    542  0x555555565281 
10 Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1>>::~PlainObjectBase PlainObjectBase.h 98   0x5555555650be 
11 Eigen::Matrix<float, -1, 1, 0, -1, 1>::~Matrix                                  Matrix.h          178  0x5555555650de 
12 main                                                                            main.cpp          26   0x555555564b42 
 

Я думал, это потому, что деструктор вызывается для пустого объекта, но когда я прокомментировал строку

 //    cudaMemcpy(amp;result, vectorCuda, sizeInBytes, cudaMemcpyKind::cudaMemcpyDeviceToHost);
 

ошибка исчезла.

Итак, как это исправить?

Кроме того, я пишу на Cuda совсем недавно, и в моем коде могут быть некоторые неправильные строки. Поэтому я был бы рад, если бы кто-то более опытный заметил что-то, что может вызвать будущие ошибки. Я хотел бы сохранить начальный и конечный динамические собственные векторы в стеке.

Ответ №1:

Самый простой способ исправить это — превратить это в указатель с плавающей точкой * с помощью функции Eigen data(), которая возвращает необработанный указатель на данные в вашей матрице. Вы можете перенести данные на графический процессор, поработать с ними там, затем скопировать эти данные обратно и снова сохранить их в хорошей собственной матрице.

 #include <iostream>
#include <cuda_runtime.h>
#include <eigen3/Eigen/Core>
#include <eigen3/Eigen/Dense>

using Vector = Eigen::Matrix<float, Eigen::Dynamic, 1, Eigen::ColMajor>;

int main(){
Vector vector;
uint64_t size = 6;

vector.resize(size);
for (uint64_t i = 0; i < size;   i)
    vector[i] = i;

uint64_t sizeInBytes = size * sizeof (float);

float *raw_vector = vector.data();
float *vectorCuda;
cudaMalloc((void**)amp;vectorCuda, sizeInBytes);
cudaMemcpy(vectorCuda, raw_vector, sizeInBytes, cudaMemcpyKind::cudaMemcpyHostToDevice);

Vector resu<
result.resize(size);
cudaMemcpy(result.data(), vectorCuda, sizeInBytes, cudaMemcpyKind::cudaMemcpyDeviceToHost);

cudaFree(vectorCuda);
std::cout << "result: " << std::endl << result << std::endl;
return 0;

 }
 

Комментарии:

1. Спасибо за ваш ответ. Возможно, мой вопрос был не совсем полным. Я искал способ отправить динамический собственный вектор в ядро, потому что некоторые функции внутри ядра используют его. К сожалению, я пришел к выводу, что единственный способ — передать данные на GPU в виде указателя с плавающей точкой * из data(), а затем обернуть их внутри ядра с помощью Eigen::Map.

2. Это, вероятно, довольно хорошее решение, т.е., Может быть, не самое элегантное, но вызов eigen::map внутри ядра (или функции вызова), вероятно, не приведет к значительным накладным расходам.