2015-07-27 3 views
0

Я пытаюсь сделать очень простую программу, чтобы выполнить добавление матриц. Я разделил код на два файла, файл main.cu и файл header.cuh. Код:Программа Cuda для добавления матрицы

В main.cu:

#include <iostream> 
#include <cuda.h> 

#include "Matriz.cuh" 

using std:: cout; 

int main(void) 
{ 

    Matriz A; 
    Matriz B; 
    Matriz *C = new Matriz; 
    int lin = 10; 
    int col = 10; 

    A.lin = lin; 
    A.col = col; 
    B.lin = lin; 
    B.col = col; 
    C->lin = lin; 
    C->col = col; 
    C->matriz = new double[lin*col]; 

    A.matriz = new double[lin*col]; 
    B.matriz = new double[lin*col]; 

    for (int ii = 0; ii < lin; ii++) 
     for (int jj = 0; jj < col; jj++) 
     { 
      A.matriz[jj*A.lin + ii] = 1./(float)(10.*jj + ii + 10.0); 
      B.matriz[jj*B.lin + ii] = (float)(jj + ii + 1); 
     } 

    somaMatriz(A, B, C); 

    for (int ii = 0; ii < lin; ii++) 
    { 
     for (int jj = 0; jj < col; jj++) 
      cout << C->matriz[jj*C->lin + jj] << " "; 
     cout << "\n"; 
    } 

    return 0; 

} 

В matrix.cuh:

#include <cuda.h> 
#include <iostream> 
using std::cout; 

#ifndef MATRIZ_CUH_ 
#define MATRIZ_CUH_ 

typedef struct{ 
    double *matriz; 
    int lin; 
    int col; 
} Matriz; 

__global__ void addMatrix(const Matriz A, const Matriz B, Matriz C) 
{ 
    int idx = threadIdx.x + blockDim.x*gridDim.x; 
    int idy = threadIdx.y + blockDim.y*gridDim.y; 

    C.matriz[C.lin*idy + idx] = A.matriz[A.lin*idx + idy] + B.matriz[B.lin*idx + idy]; 
} 

void somaMatriz(const Matriz A, const Matriz B, Matriz *C) 
{ 
    Matriz dA; 
    Matriz dB; 
    Matriz dC; 

    int BLOCK_SIZE = A.lin; 

    dA.lin = A.lin; 
    dA.col = A.col; 
    dB.lin = B.lin; 
    dB.col = B.col; 
    dC.lin = C->lin; 
    dC.col = C->col; 

    cudaMalloc((void**)&dA.matriz, dA.lin*dA.col*sizeof(double)); 
    cudaMalloc((void**)&dB.matriz, dB.lin*dB.col*sizeof(double)); 
    cudaMalloc((void**)&dC.matriz, dC.lin*dC.col*sizeof(double)); 

    cudaMemcpy(dA.matriz, A.matriz, dA.lin*dA.col*sizeof(double), cudaMemcpyHostToDevice); 
    cudaMemcpy(dB.matriz, B.matriz, dB.lin*dB.col*sizeof(double), cudaMemcpyHostToDevice); 

    dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE); 
    dim3 dimGrid(dA.lin/dimBlock.x, dA.col/dimBlock.y); 

    addMatrix<<<dimGrid, dimBlock>>>(dA, dB, dC); 

    cudaMemcpy(C->matriz, dC.matriz, dC.lin*dC.col*sizeof(double), cudaMemcpyDeviceToHost); 
    cudaFree(dA.matriz); 
    cudaFree(dB.matriz); 
    cudaFree(dC.matriz); 

    return; 
} 

#endif /* MATRIZ_CUH_ */ 

Что я получаю: Матрица C заполняется из них, независимо от того, что я делаю , Я использую эту программу, чтобы получить представление о том, как работать с матрицами с переменным размером в программе GPU. Что не так с моим кодом?

+0

В печати C у вас есть 'cout << C-> matriz [jj * C-> lin + jj] <<" ";' (оба jj) возможно хотели 'cout << C-> matriz [jj * C-> lin + ii] << "" и в 'addMatrix' для A и B у вас есть' lin * idx', а C имеет 'lin * idy', но я подозреваю, что они должны быть одинаковыми. – ryanpattison

+0

Хорошо ...Я изменил эти строки, но я все еще получаю некоторые странные результаты: я пытаюсь использовать матрицы 10x10, а результирующая C - это полная матрица, за исключением двух последних строк и двух столбцов, где она приводит к подматрице реального числа 2x2. – Gabs

ответ

1

Каждый раз, когда у вас возникают проблемы с кодом CUDA, рекомендуется делать proper cuda error checking и запускать код с cuda-memcheck. Когда я запускаю свой код с помощью cuda-memcheck, я получаю указание, что ядро ​​пытается выполнить операции чтения вне пределов. Поскольку ваше ядро ​​тривиально просто, это означает, что ваши вычисления индексации должны быть неверными.

Ваша программа должна по крайней мере 2 изменений, чтобы получить его работу для маленьких квадратных матриц:

  1. Расчеты индекса в ядре для A, B и C все должны быть одинаковыми:

    C.matriz[C.lin*idy + idx] = A.matriz[A.lin*idx + idy] + B.matriz[B.lin*idx + idy]; 
    

    так:

    C.matriz[C.lin*idy + idx] = A.matriz[A.lin*idy + idx] + B.matriz[B.lin*idy + idx]; 
    
  2. Ваше х/у создания индекса в ядре не со дый правильный:

    int idx = threadIdx.x + blockDim.x*gridDim.x; 
    int idy = threadIdx.y + blockDim.y*gridDim.y; 
    

    они должны быть:

    int idx = threadIdx.x + blockDim.x*blockIdx.x; 
    int idy = threadIdx.y + blockDim.y*blockIdx.y; 
    

С учетом указанных выше изменений, я был в состоянии получить рациональную ищет выход.

Ваш код установки также не представляется, обработки больших матриц корректно:

int BLOCK_SIZE = A.lin; 
... 
dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE); 
dim3 dimGrid(dA.lin/dimBlock.x, dA.col/dimBlock.y); 

Вы, вероятно, хотите что-то вроде:

int BLOCK_SIZE = 16; 
... 
dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE); 
dim3 dimGrid((dA.lin + dimBlock.x - 1)/dimBlock.x, (dA.col + dimBlock.y -1)/dimBlock.y); 

С этими изменениями, вы должны добавить действительный чек нить к вашему ядру, что-то вроде этого:

__global__ void addMatrix(const Matriz A, const Matriz B, Matriz C) 
{ 
    int idx = threadIdx.x + blockDim.x*blockIdx.x; 
    int idy = threadIdx.y + blockDim.y*blockIdx.y; 

    if ((idx < A.col) && (idy < A.lin)) 
     C.matriz[C.lin*idy + idx] = A.matriz[A.lin*idx + idy] + B.matriz[B.lin*idx + idy]; 
} 

Я также не подтвердил d, что вы правильно сравниваете все измерения с соответствующими ограничениями строк или строк. Это еще что-то проверить для неквадратных матриц.

+0

Спасибо, очень! Фактически, я следую руководству по программированию NVidia Cuda C, и в примерах нет чеканки памяти. Кроме того, значения idx, idy и dimGrid были получены по примерам руководства NVidia (см. Стр. 22 - 25). – Gabs

+0

Если я имею дело с огромными матрицами, как мне обновить индексы матриц? Я думаю, это не то же самое, что для одномерных массивов. – Gabs

+0

Я смотрю руководство по программированию CUDA C (PG-02829-001_v7.0) для CUDA 7.0, на стр. 22, и я не вижу ничего похожего на ваш код. Они генерируют линейный индекс без использования 'gridDim' (который был ключевой ошибкой в ​​вашем коде), а ядро ​​на стр. 22 (делая векторное добавление) пропускает длину вектора и проверяет переменную индекса потока на эту длину. Расчет размера сетки, который я вижу на p22, выглядит как мой, а не ваш. В общем, руководство по программированию не демонстрирует правильной проверки ошибок для каждого примера, ради краткости представления понятий. –

Смежные вопросы