используя указатель на вектор & lt; T & gt; :: data () для cublasSgemm

Я пытаюсь использовать указатель vector :: data () при использовании cudaMalloc, cudaMemcpy и cublasSgemm, но я не могу заставить его работать. Если я не ошибаюсь, vector :: data () должен возвращать указатель на фактический массив, сохраненный в памяти для этого вектора, поэтому он должен быть таким же, как указатель T * aArray на массив типа T, хранящийся в памяти. Использование последнего работает, но не указатель data ().

Вот код, над которым я работаю:

Matrix<T> Matrix<T>::cudaProd(Matrix<T>&A,Matrix<T>&B, Matrix<T>&C)
{
C = Matrix<T>(A.height, B.width); //resizing of the vector of elements for Matrix C
//A[m][n]*B[n][k]=C[m][k]
int m = A.height;
int n = B.height;
int k = B.width;
float alpha = 1.0f;
float beta = 0.0f;

T* d_a = A.GetPointer();
T* d_b = B.GetPointer();
T* d_c = C.GetPointer();

cudaMalloc(&d_a,A.size);
cudaMalloc(&d_b,B.size);
cudaMalloc(&d_c,C.size);

cudaMemcpy(d_a,A.GetPointer(),A.size,cudaMemcpyHostToDevice);
cudaMemcpy(d_b,B.GetPointer(),B.size,cudaMemcpyHostToDevice);

cublasHandle_t handle;

cublasStatus_t status = cublasCreate(&handle);

if (status != CUBLAS_STATUS_SUCCESS)
{
std::cerr << "!!!! CUBLAS initialization error\n";
}

status = cublasSgemm(handle,CUBLAS_OP_N,CUBLAS_OP_N,k,m,n,&alpha,d_b,k,d_a,n,&beta,d_c,k);

if (status != CUBLAS_STATUS_SUCCESS)
{
std::cerr << "!!!! kernel execution error.\n";
}

status = cublasDestroy(handle);
if (status != CUBLAS_STATUS_SUCCESS)
{
std::cerr << "!!!! shutdown error (A)\n";
}

cudaMemcpy(C.GetPointer(), d_c, C.size,cudaMemcpyDeviceToHost);

cudaFree(d_a);
cudaFree(d_b);
cudaFree(d_c);

Функция-член GetPointer () возвращает vector :: data () вектора элементов для этого объекта Matrix. Размер — это размер векторного элемента в памяти.

Вектор матрицы C возвращает все нули при использовании указателя data () и возвращает произведение матриц A и B при использовании указателей T * aArray без векторов.

Можно ли на самом деле использовать векторы для хранения массива элементов, а затем указатель data () для инициализации копии массива на устройстве или я вынужден использовать хранилище массива в стиле C на хосте? Кроме того, я попытался использовать thrust :: device_vector, и это работает, но я бы хотел избежать создания raw_pointer_casts.

Спасибо за вашу помощь!

Редактировать:
Для тех, кто испытывает проблемы с копированием и вставкой, вот полный пример:

#include <cuda.h>
#include <cuda_runtime.h>
#include <cuda_device_runtime_api.h>
#include <cublas_v2.h>
#include <vector>
#include <iostream>

using namespace std;

template<typename T> class Matrix
{
public:
~Matrix();
Matrix();
Matrix(int rows, int columns);
int width;
int height;
int stride;
size_t size;

T &GetElement(int row, int column);
void SetElement(int row, int column, T value);
void SetElements(vector<T> value);
vector<T>& GetElements();
T* GetPointer();
Matrix<T> cudaProd(Matrix<T>&A,Matrix<T>&B, Matrix<T>&C);
private:
vector<T> elements;
T* firstElement;
};

template<typename T>
Matrix<T>::~Matrix()
{
}

template<typename T>
Matrix<T>::Matrix()
{
}

template<typename T>
Matrix<T>::Matrix(int rows, int columns)
{
height = rows;
width = columns;
stride = columns; //in row major order this is equal to the # of columns
elements.resize(rows*columns);
firstElement = elements.data();
size = height*width*sizeof(T);
}

template<typename T>
T &Matrix<T>::GetElement(int row, int column)
{
return elements[row*width + column]; //row major order return
}

template<typename T>
vector<T>& Matrix<T>::GetElements()
{
return elements; //row major order return
}

template<typename T>
void Matrix<T>::SetElement(int row, int column, T value)
{
elements[row*width + column] = value; //row major order return
}

template<typename T>
void Matrix<T>::SetElements(vector<T> value)
{
elements = value;
}

template<typename T>
T* Matrix<T>::GetPointer()
{
return firstElement;
}template<typename T>
//Matrix Multiplication using CUDA
Matrix<T> Matrix<T>::cudaProd(Matrix<T>&A,Matrix<T>&B, Matrix<T>&C)
{
C = Matrix<T>(A.height, B.width);
//A[m][n]*B[n][k]=C[m][k]
int m = A.height;
int n = B.height;
int k = B.width;
float alpha = 1.0f;
float beta = 0.0f;//Thrust usage

/*thrust::device_vector<T> d_A = A.GetElements();
T* d_a = thrust::raw_pointer_cast(&d_A[0]);
thrust::device_vector<T> d_B = B.GetElements();
T* d_b = thrust::raw_pointer_cast(&d_B[0]);
thrust::device_vector<T> d_C = C.GetElements();
T* d_c = thrust::raw_pointer_cast(&d_C[0]);*/

T* d_a = A.GetPointer();
T* d_b = B.GetPointer();
T* d_c = C.GetPointer();

cudaMalloc(&d_a,A.size);
cudaMalloc(&d_b,B.size);
cudaMalloc(&d_c,C.size);

cudaMemcpy(d_a,A.GetPointer(),A.size,cudaMemcpyHostToDevice);
cudaMemcpy(d_b,B.GetPointer(),B.size,cudaMemcpyHostToDevice);
cudaMemcpy(d_c,C.GetPointer(),C.size,cudaMemcpyHostToDevice);

cublasHandle_t handle;

cublasStatus_t status = cublasCreate(&handle);

if (status != CUBLAS_STATUS_SUCCESS)
{
std::cerr << "!!!! CUBLAS initialization error\n";
}

status = cublasSgemm(handle,CUBLAS_OP_N,CUBLAS_OP_N,k,m,n,&alpha,d_b,k,d_a,n,&beta,d_c,k);

if (status != CUBLAS_STATUS_SUCCESS)
{
std::cerr << "!!!! kernel execution error.\n";
}

status = cublasDestroy(handle);
if (status != CUBLAS_STATUS_SUCCESS)
{
std::cerr << "!!!! shutdown error (A)\n";
}

//thrust::copy(d_C.begin(), d_C.end(), C.GetElements().begin());

cudaMemcpy(C.GetPointer(), d_c, C.size,cudaMemcpyDeviceToHost);

cudaFree(d_a);
cudaFree(d_b);
cudaFree(d_c);

return C;

}

int main()
{
Matrix<float> A(2,2);
Matrix<float> B(2,2);
Matrix<float> C;

vector<float> aE(4,2);
vector<float> bE(4,4);
A.SetElements(aE);
B.SetElements(bE);

C = C.cudaProd(A, B, C);  //function call to cudaProd()

for(int row = 0; row < A.height; ++row)
{
for(int col = 0; col < A.width; ++col)
{
cout<<A.GetElement(row, col)<<" "; //h_c is stored on device in column major order, need to switch to row major order
}
printf("\n");
}
printf("\n");

for(int row = 0; row < B.height; ++row)
{
for(int col = 0; col < B.width; ++col)
{
cout<<B.GetElement(row, col)<<" "; //h_c is stored on device in column major order, need to switch to row major order
}
printf("\n");
}
printf("\n");

for(int row = 0; row < C.height; ++row)
{
for(int col = 0; col < C.width; ++col)
{
cout<<C.GetElement(row, col)<<" "; //h_c is stored on device in column major order, need to switch to row major order
}
printf("\n");
}
printf("\n");
}

0

Решение

От std :: vector :: документация данных, data() возвращает оба const и неconst квалифицированные указатели, в зависимости от того, что vector квалифицируется как const или нет. Цитирование документации

Если векторный объект является const-квалифицированным, функция возвращает указатель на const value_type. В противном случае он возвращает указатель на value_type.

Соответственно, используя

firstElement = elements.data();

в Matrix Конструктор отлично подходит для чтения / записи данных.

Основная проблема с вашим кодом заключается в том, что вы декларируете C в main, передав ссылку на C к cudaProd метод, а затем внутренне с помощью

C = Matrix<T>(A.height, B.width);

который переопределит Matrix,

Если вы измените определение cudaProd метод для

template<typename T>
void cudaProd(Matrix<T>&A,Matrix<T>&B, Matrix<T>&C)

удалить

return C;

Заявление и выделить место для C в основном как

Matrix<float> C(2,2);
vector<float> cE(4,10);
C.SetElements(cE);

Ваш код должен работать правильно.

0

Другие решения

Если я не ошибаюсь, vector::data() должен возвращать указатель на фактический массив, сохраненный в памяти для этого вектора, поэтому он должен быть таким же, как T* aArray указатель на массив типа T хранится в памяти.

std::vector класс владеющим класс ресурсов. Это означает, что попытка самостоятельно управлять основным ресурсом с помощью data указатель заставит вас войти в мир боли.

По этой же самой причине:

cudaMalloc(&d_a,A.size);
cudaMalloc(&d_b,B.size);
cudaMalloc(&d_c,C.size);

а также:

cudaMemcpy(C.GetPointer(), d_c, C.size,cudaMemcpyDeviceToHost);

а также:

cudaFree(d_a);
cudaFree(d_b);
cudaFree(d_c);

не может работать

0