AMD Codexl профилиране: Открито е изтичане на памет на Opencl [Ref =1] Обект, създаден от clEnqueueNDRangeKernel

Нямам представа защо продължавам да получавам това предупреждение, тъй като минах през кода много пъти и не мога да разбера откъде идва това, тъй като съм почти сигурен (но очевидно не), че освобождавам цялата памет. Надяваме се, че някой, който знае повече от мен, може да погледне моя код и да посочи къде и защо се случва това.

Благодаря!

int runKernel( Image *anImage, 
              PixelPacket *imagePixels, 
              MagickSizeType imageSizeBytes, 
              const char *kernelSource )
{

    cl_context myContext ;
    cl_command_queue myQueue ;
    cl_mem *outputImage ;
    cl_event clEvent ;
    int bitsPerChannel = anImage[0].depth ; 
    int width = anImage[0].columns ;
    int height = anImage[0].rows ;



    /****************************
    Setup the Opencl environment
    ****************************/


    // Use this to check the output of each API call
    cl_int status ;

    // Retrieve the number of platforms
    cl_uint numPlatforms = 0 ;
    status = clGetPlatformIDs( 0, NULL, &numPlatforms ) ;

    // Allocate enough space for each platform
    cl_platform_id *platforms = NULL ;
    platforms = (cl_platform_id *) malloc( numPlatforms * sizeof(cl_platform_id) ) ;

    // Fill in the platforms
    status = clGetPlatformIDs( numPlatforms, platforms, NULL ) ;

    // Retrieve the number of devices for the 1st platform
    cl_uint numDevices = 0 ;
    status = clGetDeviceIDs( platforms[0], CL_DEVICE_TYPE_ALL, 0, NULL, &numDevices ) ;

    // Allocate enough space for each device
    cl_device_id *devices ;
    devices = (cl_device_id *) malloc( numDevices * sizeof(cl_device_id) ) ;

    // Fill in the devices
    status = clGetDeviceIDs( platforms[0], CL_DEVICE_TYPE_ALL, numDevices, 
                devices, NULL ) ;

    // Create the context
    myContext = clCreateContext( NULL, numDevices, devices, NULL, NULL, &status ) ;

    // Create the command queue with the 1st device
    myQueue = clCreateCommandQueue( myContext, devices[0], 0, &status ) ;



    /****************************
    Create Images and Move Data
    ****************************/



    // Set format and descriptor to proper values according to image type
    cl_image_format *image_format = NULL ;
    cl_image_desc *image_desc = NULL ;
    get_cl_image_format( anImage, &image_desc, &image_format ) ;

    // Create the image sampler
    cl_sampler clSampler = clCreateSampler(
                            myContext,
                            CL_FALSE, //use pixel based addressing not normalized
                            CL_ADDRESS_CLAMP_TO_EDGE, // set equal to the pixel at the edge of the image
                            CL_FILTER_NEAREST, 
                            &status);

    // Set input Image region parameters
    size_t origin[3] = {0, 0, 0} ; // Offset within the image to copy from
    size_t region[3] = {width, height, 1} ; // Elements per dimension for 2d image 


    // Create cl memory object for the input image
    cl_mem_flags flagsRead = CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR ;

    cl_mem clInput = clCreateImage( myContext, flagsRead, 
                                ( const cl_image_format *)image_format, 
                                ( const cl_image_desc *)image_desc, 
                                imagePixels, 
                                &status ) ;


    // Allocate space for output image and create cl memory object 
    float *outputPixels =  (float *) malloc( imageSizeBytes ) ;
    cl_mem_flags flagsWrite = CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR ;

    cl_mem clOutput = clCreateImage( myContext, flagsWrite, 
                                    (const cl_image_format *)image_format, 
                                    ( const cl_image_desc *)image_desc, 
                                    outputPixels, 
                                    &status ) ;


    //Copy input image to the device
    status = clEnqueueWriteImage( myQueue, clInput, CL_FALSE, origin, region,
                                0, 0, imagePixels, 0, NULL, NULL ) ;



    /*****************************
    Compile the kernel from source
    *****************************/



    // kernelSource stores the kernel code and must be NULL terminated
    cl_program myProgram = clCreateProgramWithSource( myContext, 1, 
                                                    &kernelSource, 
                                                    NULL, 
                                                    &status ) ;

    // Compile the program  
    const char buildOptions[] = "-cl-std=CL1.2 -cl-mad-enable\0";
    status = clBuildProgram( myProgram, 1, devices, buildOptions, NULL, NULL ) ;

    // Create the kernel
    cl_kernel myKernel = clCreateKernel( myProgram, "convolution", &status ) ;



    /**********************************
    Set kernel args and run the program
    **********************************/



    // Set the kernel arguments

    clSetKernelArg( myKernel, 0, sizeof( cl_mem ), &clInput ) ;
    clSetKernelArg( myKernel, 1, sizeof( cl_mem ), &clOutput ) ;
    clSetKernelArg( myKernel, 2, sizeof( int ), &height ) ;
    clSetKernelArg( myKernel, 3, sizeof( int ), &width ) ;
    clSetKernelArg( myKernel, 4, sizeof( cl_sampler ), &clSampler ) ;

    //Execute the kernel
    status = clEnqueueTask( myQueue, myKernel, 0, NULL, NULL ) ;

    //Read the output buffer back to the host
    status = clEnqueueReadImage( myQueue, clOutput, CL_TRUE, origin, region, 0, 0, 
                               (void *) outputPixels, 0, NULL, &clEvent ) ;



    /**********************************
    Free Resources
    **********************************/



    /* Wait for the kernel to finish */ 
    clWaitForEvents( 1, &clEvent ) ;

    free( refImage ) ;
    free( platforms ) ;
    free( devices ) ;
    free( outputPixels ) ;
    free( image_desc ) ;
    free( image_format ) ;

    clReleaseSampler( clSampler ) ;
    clReleaseMemObject( clInput ) ;
    clReleaseMemObject( clOutput ) ;    
    clReleaseProgram( myProgram ) ;
    clReleaseCommandQueue( myQueue ) ;
    clReleaseKernel( myKernel ) ;   
    clReleaseContext( myContext ) ; 
    clReleaseEvent( clEvent ) ;

    return 0;
}

person Jason White    schedule 14.04.2014    source източник
comment
Вашето съобщение за грешка показва, че изтичането на памет възниква в clEnqueueNDRangeKernel. Освен ако не съм сляп, най-близкото до вас е clEnqueueTask, който може да извиква clEnqueueNDRangeKernel. След като направите корекцията, предложена от tim, моля, коментирайте реда clEnqueueTask и вижте дали изтичането на памет все още е налице. Ако не присъства, тогава подозирам, че обект cl_event се създава в clEnqueueTask, въпреки че предавате NULL за събитието за връщане.   -  person chippies    schedule 15.04.2014
comment
Хей Chippies изглежда си прав! Добавих clEvent на мястото на NULL и го пуснах веднага след това и той решава изтичането. Благодаря!   -  person Jason White    schedule 16.04.2014
comment
Чудя се дали това представлява грешка в драйвера? Това, което направихте, беше напълно правилно. clEnqueueTask изтече събитието, а не вие.   -  person Tim    schedule 16.04.2014
comment
@Тим, съгласен съм. Моето разбиране за спецификациите е, че всички функции не трябва да създават събитие, когато предават NULL за параметъра на събитието. За бъдещи справки OP е публикувал това във форумите за разработчици на AMD на http://devgurus.amd.com/thread/168582.   -  person chippies    schedule 17.04.2014


Отговори (1)


Възможно е унищожаването на опашката, ядрото, контекста или програмата преди освобождаване на събитието (clEvent) да е причина за предупреждението. Може да опитате следното:

clReleaseEvent( clEvent ) ; // <<< THIS ONE FIRST
clReleaseSampler( clSampler ) ;
clReleaseMemObject( clInput ) ;
clReleaseMemObject( clOutput ) ;    
clReleaseProgram( myProgram ) ;
clReleaseCommandQueue( myQueue ) ;
clReleaseKernel( myKernel ) ;   
clReleaseContext( myContext ) ; 

Като алтернатива отстранявайте грешките в операциите за освобождаване ред по ред, докато получите предупреждението.

person Tim    schedule 15.04.2014
comment
Хей Тим, пробвах това, но нямаше ефект. Редът изглежда няма значение, тъй като го опитах накрая веднъж и все още показва същото, но благодаря за опита! - person Jason White; 16.04.2014
comment
Не съм сигурен какво казва спецификацията на CL, но като цяло може да е добра идея да сте чувствителни към реда на унищожаване, ако стартирате това на други реализации. Браво на внедряването на AMD за разрешаването на всякакъв ред на унищожаване! - person Tim; 16.04.2014
comment
Функциите clRelease* намаляват референтния брояч. След като този брояч достигне 0 и всички обекти, прикачени към обекта, който се освобождава, са изтрити, тогава обектът се изтрива. След това правилно написаната реализация трябва вътрешно да сортира реда, в който обектите се изтриват, независимо от реда, в който ги освобождавате, с ограничението, че трябва да ги освободите, преди да могат да бъдат изтрити. - person chippies; 17.04.2014