У меня есть следующий код, написанный на cuda-C (Visual Studio 2015 на Win-10, устройство GPU = TitanXp) для вычисления суммы всех элементов в 1D-массиве (сглаженном из 2D). Хост-версия проста с операцией +=
для суммирования всех элементов и возврата значения. для реализации cuBLAS я использовал подход скалярного произведения (выполнение скалярного произведения целевого массива с массивом всех единиц одинакового размера, чтобы получить сумму всех элементов). Код работает для небольших массивов (например, массив из 100 элементов), однако возвращает неверные значения (хотя и достаточно близкие к правильному значению) для больших массивов (например, 512x512 = 262144-элементный массив). Что я упускаю или делаю неправильно? Заранее спасибо. (Отказ от ответственности - новый пользователь cuBLAS).
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "book.h"
#include <cublas_v2.h>
void creatematrix(float *out, int nx, int ny)
{
float ctr = 0;
for (int i = 0; i < nx; ++i) {
for (int j = 0; j < ny; ++j) {
out[j * nx + i] = ctr/1E+5;
ctr = ctr + 1;
}
}
}
float add_arr_val(float *im, int N)
{
float tmp = 0;
for (int i = 0; i < N; ++i)
tmp += im[i];
float out = tmp;
return out;
}
__global__ void init_ones(float *d_in, int N)
{
int i = threadIdx.x + blockIdx.x * blockDim.x;
if (i < N)
{
d_in[i] = 1.0;
}
}
void main()
{
// Define matrix size (using flattened array for most operations)
int nx = 512; // row size
int ny = 512; // column size
int N = nx * ny; // total size of flattened array
// CPU section ========================================
float *M; M = (float*)malloc(N * sizeof(float)); // create array pointer and allocate memory
creatematrix(M, nx, ny); // create a test matrix of size nx * ny
float cpu_out = add_arr_val(M, N); // CPU function
// GPU and cuBLAS section ==============================
float *d_M;
HANDLE_ERROR(cudaMalloc(&d_M, N * sizeof(float)));
HANDLE_ERROR(cudaMemcpy(d_M, M, N * sizeof(float), cudaMemcpyHostToDevice)); // copy original array M to device as d_M
// create array of all ones, size N for dot product
float *d_ones;
cudaMalloc(&d_ones, N * sizeof(float));
// Max potential blocksize
int minGridSize, blockSize, gridSize;
cudaOccupancyMaxPotentialBlockSize(&minGridSize, &blockSize, init_ones, 0, N);
gridSize = (N + blockSize - 1) / blockSize;
init_ones << <gridSize, blockSize >> > (d_ones, N); // kernel launch to generate array of all 1's
cudaDeviceSynchronize();
float blas_out; // output on host variable
cublasHandle_t handle; cublasCreate(&handle); // initialize CUBLAS context
cublasSdot(handle, N, d_M, 1, d_ones, 1, &blas_out); // Perform cublas single-precision dot product of (d_M . d_ones)
cudaDeviceSynchronize();
//print output from cpu and gpu sections
printf("native output = %lf\n", cpu_out);
printf("cublas output = %lf\n", blas_out);
cublasDestroy(handle);
free(M);
cudaFree(d_M);
cudaFree(d_ones);
}
Вывод для массива из 262144 элементов (сглаженная матрица 512x512):
native output = 343590.437500
cublas output = 343596.062500
Press any key to continue . . .
Вывод для массива из 144 элементов (сглаженная матрица 12x12):
native output = 0.102960
cublas output = 0.102960
Press any key to continue . . .