2014-09-06 6 views
7

Se si esegue questo programma, viene visualizzato "un accesso errato alla memoria nell'errore matrixMulti.cu alla riga 48". Ho cercato e provato molto. Quindi spero che qualcuno possa aiutarmi.Il semplice test CUDA fallisce sempre con "un accesso illegale alla memoria rilevato" errore

Riga 48: HANDLE_ERROR (cudaMemcpy (array, devarray, N * N * sizeof (int), cudaMemcpyDeviceToHost));

Il programma è solo per entrare in CUDA. Ho provato ad implementare una moltiplicazione di matrice.

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

using namespace std; 

#define HANDLE_ERROR(err) (HandleError(err, __FILE__, __LINE__)) 
void printVec(int** a, int n); 

static void HandleError(cudaError_t err, const char *file, int line) 
{ 
    if (err != cudaSuccess) 
    { 
    printf("%s in %s at line %d\n", cudaGetErrorString(err), 
      file, line); 
    exit(EXIT_FAILURE); 
    } 
} 

void checkCUDAError(const char *msg) 
{ 
    cudaError_t err = cudaGetLastError(); 
    if(cudaSuccess != err) 
    { 
     fprintf(stderr, "Cuda error: %s: %s.\n", msg, 
           cudaGetErrorString(err)); 
     exit(EXIT_FAILURE); 
    }       
} 
__global__ void MatrixMulti(int** a, int** b) { 
    b[0][0]=4; 
} 

int main() { 
    int N =10; 
    int** array, **devarray; 
    array = new int*[N]; 

    for(int i = 0; i < N; i++) { 
     array[i] = new int[N]; 
    } 

    HANDLE_ERROR (cudaMalloc((void**)&devarray, N*N*sizeof(int))); 
    HANDLE_ERROR (cudaMemcpy(devarray, array, N*N*sizeof(int), cudaMemcpyHostToDevice)); 
    MatrixMulti<<<1,1>>>(array,devarray); 
    HANDLE_ERROR (cudaMemcpy(array, devarray, N*N*sizeof(int), cudaMemcpyDeviceToHost)); 
    HANDLE_ERROR (cudaFree(devarray)); 
    printVec(array,N); 

    return 0; 
} 

void printVec(int** a , int n) { 
    for(int i =0 ; i < n; i++) { 
     for (int j = 0; j <n; j++) { 
     cout<< a[i][j] <<" "; 
     }  
     cout<<" "<<endl;  
    } 
} 

risposta

9

In generale, il metodo di allocazione e copia di un array C con doppia sottoscrizione non funzionerà. cudaMemcpy prevede flat, allocato in modo contiguo, array a un puntatore, a singolo indice.

Come risultato di questa confusione, i puntatori vengono passati al kernel (int** a, int** b) non può essere correttamente (in modo sicuro) dereferenziati due volte:

b[0][0]=4; 

Quando si tenta di fare quanto sopra nel codice del kernel, si ottiene un accesso illegale alla memoria, perché non hai assegnato correttamente un'allocazione di stile puntatore a puntatore sul dispositivo.

Se si è eseguito il codice con cuda-memcheck, si otterrà un'altra indicazione dell'accesso di memoria illegale nel codice del kernel.

Il solito suggerimento in questi casi è di "appiattire" i propri array 2D in una singola dimensione e utilizzare l'aritmetica del puntatore o dell'indice appropriata per simulare l'accesso 2D. È possibile allocare array 2D (vale a dire doppio-pedice, doppio puntatore), ma è abbastanza coinvolto (dovuto in parte alla necessità di una "copia profonda"). Se desideri saperne di più, cerca semplicemente nell'angolo in alto a destra per CUDA 2D array.

Ecco una versione del codice che ha la matrice appiattimento per l'array dispositivo di lato:

$ cat t60.cu 
#include <iostream> 
#include <cuda.h> 
#include <stdio.h> 

using namespace std; 

#define HANDLE_ERROR(err) (HandleError(err, __FILE__, __LINE__)) 
void printVec(int** a, int n); 

static void HandleError(cudaError_t err, const char *file, int line) 
{ 
    if (err != cudaSuccess) 
    { 
    printf("%s in %s at line %d\n", cudaGetErrorString(err), 
      file, line); 
    exit(EXIT_FAILURE); 
    } 
} 

void checkCUDAError(const char *msg) 
{ 
    cudaError_t err = cudaGetLastError(); 
    if(cudaSuccess != err) 
    { 
     fprintf(stderr, "Cuda error: %s: %s.\n", msg, 
           cudaGetErrorString(err)); 
     exit(EXIT_FAILURE); 
    } 
} 

__global__ void MatrixMulti(int* b, unsigned n) { 
    for (int row = 0; row < n; row++) 
     for (int col=0; col < n; col++) 
    b[(row*n)+col]=col; //simulate 2D access in kernel code 
} 

int main() { 
    int N =10; 
    int** array, *devarray; // flatten device-side array 
    array = new int*[N]; 
    array[0] = new int[N*N]; // host allocation needs to be contiguous 
    for (int i = 1; i < N; i++) array[i] = array[i-1]+N; //2D on top of contiguous allocation 

    HANDLE_ERROR (cudaMalloc((void**)&devarray, N*N*sizeof(int))); 
    HANDLE_ERROR (cudaMemcpy(devarray, array[0], N*N*sizeof(int), cudaMemcpyHostToDevice)); 
    MatrixMulti<<<1,1>>>(devarray, N); 
    HANDLE_ERROR (cudaMemcpy(array[0], devarray, N*N*sizeof(int), cudaMemcpyDeviceToHost)); 
    HANDLE_ERROR (cudaFree(devarray)); 
    printVec(array,N); 

    return 0; 
} 

void printVec(int** a , int n) { 
    for(int i =0 ; i < n; i++) { 
     for (int j = 0; j <n; j++) { 
     cout<< a[i][j] <<" "; 
     } 
     cout<<" "<<endl; 
    } 
} 
$ nvcc -arch=sm_20 -o t60 t60.cu 
$ ./t60 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
$ 
+0

Grazie :) Penso che proverò la versione 1D della matrice, sembra essere più facile – Henrik