cudaMemCpy2D se bloquea

Estoy tratando de implementar la binarización de Sauvola en cuda. ​​Para esto, he leído la imagen en una matriz 2D en el host y he asignado memoria para la matriz 2D en el dispositivo usando pitch. Después de asignar la memoria, estoy tratando de copiar la matriz 2D del host en el dispositivo 2D Array usando cudaMemcpy2D, se compila bien pero falla aquí en el tiempo de ejecución. No puedo entender dónde me estoy perdiendo. Por favor, sugiera algo. El código que he escrito es el siguiente:

#include "BinMain.h"
#include "Binarization.h"
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <cuda.h>
#include <cuda_runtime.h>

void printDevProp(cudaDeviceProp);
void CUDA_SAFE_CALL( cudaError_t);


int main()
{
    //Read an IplImage in imgOriginal as grayscale
    IplImage * imgOriginal = cvLoadImage("E:\\1.tiff",CV_LOAD_IMAGE_GRAYSCALE);

    //Create a size variable of type CvSize for cvCreateImage Parameter
    CvSize size = cvSize(imgOriginal->width,imgOriginal->height);

    //create an image for storing the result image with same height and width as     imgOriginal
    IplImage * imgResult = cvCreateImage(size,imgOriginal->depth,imgOriginal-    >nChannels);

    //Create a 2D array for storing the pixels value of each of the pixel of imgOriginal grayscale image
    int ** arrOriginal = (int **)malloc(imgOriginal->height * sizeof(int *));
    for (int i = 0; i < imgOriginal->height; i++) 
{
    arrOriginal[i] = (int*)malloc(imgOriginal->width * sizeof(int));
}

//Create a 2D array for storing the returned device array
int ** arrReturn = (int **)malloc(imgOriginal->height * sizeof(int *));
for (int i = 0; i < imgOriginal->height; i++) 
{
    arrReturn[i] = (int*)malloc(imgOriginal->width * sizeof(int));
}

//Create a CvScalar variable to copy pixel values in 2D array (arrOriginal)
CvScalar s;

//Copying the pixl values
for(int j = 0;j<imgOriginal->height;j++)
{
    for(int k =0;k<imgOriginal->width;k++)
    {
        s = cvGet2D(imgOriginal,j,k);
        arrOriginal[j][k] = s.val[0];
    }
}

//Cuda Device Property
int devCount;
cudaGetDeviceCount(&devCount);
printf("CUDA Device Query...\n");
printf("There are %d CUDA devices.\n", devCount);

// Iterate through devices
for (int i = 0; i < devCount; ++i)
{
    // Get device properties
    printf("\nCUDA Device #%d\n", i);
    cudaDeviceProp devProp;
    cudaGetDeviceProperties(&devProp, i);
    printDevProp(devProp);
}

//Start the clock
clock_t start = clock();

//Allocating Device memory for 2D array using pitch
size_t host_orig_pitch = imgOriginal->width * sizeof(int)* imgOriginal->height; //host original array pitch in bytes
size_t dev_pitch;   //device array pitch in bytes which will be used in cudaMallocPitch
size_t dev_pitchReturn; //device return array pitch in bytes
size_t host_ret_pitch = imgOriginal->width * sizeof(int)* imgOriginal->height;  //host return array pitch in bytes

int * devArrOriginal;   //device 2d array of original image
int * result;   //device 2d array for returned array
int dynmicRange = 128; //Dynamic Range for calculating the threshold from sauvola's formula

//Allocating memory by using cudaMallocPitch
CUDA_SAFE_CALL(cudaMallocPitch((void**)&devArrOriginal,&dev_pitch,imgOriginal->width * sizeof(int),imgOriginal->height * sizeof(int)));

//Allocating memory for returned array
CUDA_SAFE_CALL(cudaMallocPitch((void**)&result,&dev_pitchReturn,imgOriginal->width * sizeof(int),imgOriginal->height * sizeof(int)));

//Copying 2D array from host memory to device mempry by using cudaMemCpy2D
CUDA_SAFE_CALL(cudaMemcpy2D((void*)devArrOriginal,dev_pitch,(void*)arrOriginal,host_orig_pitch,imgOriginal->width * sizeof(float),imgOriginal->height,cudaMemcpyHostToDevice));
    int windowSize = 19;    //Size of the window for calculating mean and variance
    //Launching the kernel by calling myKernelLauncher function.
    myKernelLauncher(devArrOriginal,result,windowSize,imgOriginal->width,imgOriginal-    >height,dev_pitch,dynmicRange);
    //Calling the sauvola binarization function by passing the parameters as 
    //1.arrOriginal 2D array 2.Original image height 3.Original image width
    //int ** result = AdaptiveBinarization(arrOriginal,imgOriginal->height,imgOriginal-    >width);//binarization(arrOriginal,imgOriginal->width,imgOriginal->height);
    //
CUDA_SAFE_CALL(cudaMemcpy2D(arrReturn,host_ret_pitch,result,dev_pitchReturn,imgOriginal->width * sizeof(int),imgOriginal->height * sizeof(int),cudaMemcpyDeviceToHost));
//create a CvScalar variable to set the data in imgResult
CvScalar ss;

//Copy the pixel values from returned array to imgResult
for(int i=0;i<imgOriginal->height;i++)
{
    for(int j=0;j<imgOriginal->width;j++)
    {
        ss = cvScalar(arrReturn[i][j]*255);
        cvSet2D(imgResult,i,j,ss);
        //k++; //No need for k if returned array is 2D
    }
}

printf("Done \n");
//calculate and print the time elapsed
printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);

//Create a windoe and show the resule image
cvNamedWindow("Result",CV_WINDOW_AUTOSIZE);
cvShowImage("Result",imgResult);
cvWaitKey(0);
getch();

//Release the various resources
cvReleaseImage(&imgResult);
cvReleaseImage(&imgOriginal);
cvDestroyWindow("Result");
for(int i = 0; i < imgOriginal->height; i++)
    free(arrOriginal[i]);

free(arrOriginal);
free(result);
cudaFree(&devArrOriginal);
cudaFree(&result);

}

// Print device properties
void printDevProp(cudaDeviceProp devProp)
{
printf("Major revision number:         %d\n",  devProp.major);
printf("Minor revision number:         %d\n",  devProp.minor);
printf("Name:                          %s\n",  devProp.name);
printf("Total global memory:           %u\n",  devProp.totalGlobalMem);
printf("Total shared memory per block: %u\n",  devProp.sharedMemPerBlock);
printf("Total registers per block:     %d\n",  devProp.regsPerBlock);
printf("Warp size:                     %d\n",  devProp.warpSize);
printf("Maximum memory pitch:          %u\n",  devProp.memPitch);
printf("Maximum threads per block:     %d\n",  devProp.maxThreadsPerBlock);
for (int i = 0; i < 3; ++i)
printf("Maximum dimension %d of block:  %d\n", i, devProp.maxThreadsDim[i]);
for (int i = 0; i < 3; ++i)
printf("Maximum dimension %d of grid:   %d\n", i, devProp.maxGridSize[i]);
printf("Clock rate:                    %d\n",  devProp.clockRate);
printf("Total constant memory:         %u\n",  devProp.totalConstMem);
printf("Texture alignment:             %u\n",  devProp.textureAlignment);
printf("Concurrent copy and execution: %s\n",  (devProp.deviceOverlap ? "Yes" : "No"));
printf("Number of multiprocessors:     %d\n",  devProp.multiProcessorCount);
printf("Kernel execution timeout:      %s\n",  (devProp.kernelExecTimeoutEnabled ? "Yes" : "No"));
return;
}

/* Utility Macro : CUDA SAFE CALL */ 
void CUDA_SAFE_CALL( cudaError_t call) 
{ 

cudaError_t ret = call; 
switch(ret) 
{ 
    case cudaSuccess: 
         break; 
    default : 
            {
                printf(" ERROR at line :%i.%d' ' %s\n", 
                __LINE__,ret,cudaGetErrorString(ret)); 
                exit(-1); 
                break; 
            } 
} 
} 

El flujo del código es el siguiente: 1. Cree una matriz 2D en el host desde la imagen y otra matriz para la matriz devuelta desde el núcleo. 2. Asigne memoria para una matriz 2D en el dispositivo mediante CudaMallocPitch 3. Asigne memoria para una matriz 2D que devolverá el kernel. 4. Copie la matriz 2d original del host a la matriz de dispositivos mediante cudaMemcpy2d. 5. Inicie el núcleo. 6. Copie la matriz de dispositivos devuelta a la matriz host mediante cudaMemcpy2D.

El programa se bloquea mientras llega al cuarto punto. Es una excepción no controlada que indica "Excepción no controlada en 4x0de en SauvolaBinarization_CUDA_OpenCV.exe: 773415xC0: Ubicación de lectura de infracción de acceso 0000005x0".

Creo que el problema debe ser al asignar la memoria, pero estoy usando la función por primera vez y no tengo idea de cómo funciona, por favor sugiera.

preguntado el 28 de agosto de 12 a las 10:08

1 Respuestas

En primer lugar, no estás llamando a "cudaMallocPitch" correctamente. El parámetro "altura" debe representar el número de filas, por lo que en lugar de:

imgOriginal->height * sizeof(int)

simplemente debe usar:

imgOriginal->height

Esto está bien porque el número de bytes por fila ya está contenido en la propiedad "pitch". Sin embargo, el principal problema radica en la forma en que asigna la memoria para la imagen del host. Cuando escribes:

//Create a 2D array for storing the pixels value of each of the pixel of imgOriginal grayscale image
    int ** arrOriginal = (int **)malloc(imgOriginal->height * sizeof(int *));
    for (int i = 0; i < imgOriginal->height; i++) 
{
    arrOriginal[i] = (int*)malloc(imgOriginal->width * sizeof(int));
}

está creando efectivamente una matriz con punteros a matrices. La llamada a la API de CUDA que está realizando:

CUDA_SAFE_CALL(cudaMemcpy2D((void*)devArrOriginal,dev_pitch,(void*)arrOriginal,host_orig_pitch,imgOriginal->width * sizeof(float),imgOriginal->height,cudaMemcpyHostToDevice));

espera que el búfer de memoria de entrada sea contiguo. Esto es lo que sucederá: la primera fila de la imagen de entrada (totalizando "imgOriginal->width * sizeof(float)" bytes) se leerá comenzando con la dirección:

 (void*)arrOriginal

Sin embargo, la cantidad de datos válidos que tiene a partir de esa dirección es solo "imgOriginal->height * sizeof(int *)" bytes. Es muy probable que los dos recuentos de bytes sean diferentes, lo que provocará el bloqueo porque terminará leyendo desde una ubicación desconocida.

Para resolver esto, considere asignar "arrOriginal" como un bloque contiguo, como:

int * arrOriginal = (int *)malloc(imgOriginal->height * imgOriginal->width * sizeof(int));

Además, en este caso, su tono debe ser:

 "imgOriginal->width * sizeof(int)"

Respondido 28 ago 12, 15:08

Gracias, ¿significa que debería hacer una matriz de host 2d aplanada? - user1393349

Puede cambiar a una matriz de host aplanada o copiar la matriz de host a la GPU una fila a la vez. Una copia grande para una matriz aplanada será más rápida que el tiempo combinado para muchas copias de filas individuales. - njuffa

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.