5
votes

I'm working in some code that sends large amounts of data from host to device, and it behaves erratically.

In the following piece of the code, I'm trying to send from host to device an array. The array size is incrementing on each iteration, gradually increasing the amount of memory sent to the device. The first element in the array is filled with a nonzero value, and it's read from inside the kernel and printed to console. The value should be the same when it's read from the host and from the device, but in some iterations it's not.

Here's the code:


    int SizeArray = 0;

    for(int j=1; j<100 ;j++){ 

        //Array memory allocation, starting with 4MB in first iteration to 400MB in last one
        SizeArray = j * 1000000 * sizeof(float);
        Array = (float*)malloc(SizeArray);
        memset(Array, 0, SizeArray);

        //Give the array's first element some nonzero value
        //This is the value that is expected to be printed by the kernel execution
        Array[0] = j;

        memArray = clCreateBuffer(context, CL_MEM_READ_WRITE, SizeArray, NULL, &ret);

        //Write the array contents into the buffer inside the device
        ret = clEnqueueWriteBuffer(command_queue, memArray, CL_TRUE, 0, SizeArray, Array, 0, NULL, NULL);
        ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&memArray);

        getchar();

        //Execute the kernel where the content of the first element of the array will be printed
        ret = clEnqueueNDRangeKernel(command_queue, kernel, 3, NULL, mGlobalWorkSizePtr, mLocalWorkSizePtr, 0, NULL,NULL);
        ret = clFinish(command_queue);

        /****** FAIL! Kernel prints correct value of Array's first element ONLY IN 
        SOME ITERATIONS (when it fails zero values are printed)! Depending on SizeArray :?? ******/

        free(Array);
        ret = clReleaseMemObject(memArray);
    }

The device where this code was tested has the following features:

    - Name: Intel(R) HD Graphics 4000 - DeviceVersion: OpenCL 1.1 - DriverVersion: 8.15.10.2696 - MaxMemoryAllocationSize: 425721856 - GlobalMemoryCacheSize: 2097152 - GlobalMemorySize: 1702887424 - MaxConstantBufferSize: 65536 - LocalMemorySize: 65536

Kernel prints incorrect values or not, depending on the buffer size sent to the device.

Here's the output:


Array GPU: 1.000000
Array GPU: 2.000000
Array GPU: 3.000000
Array GPU: 4.000000
Array GPU: 5.000000
Array GPU: 6.000000
Array GPU: 7.000000
Array GPU: 8.000000
Array GPU: 9.000000
Array GPU: 10.000000
Array GPU: 11.000000
Array GPU: 12.000000
Array GPU: 13.000000
Array GPU: 14.000000
Array GPU: 15.000000
Array GPU: 16.000000
Array GPU: 17.000000
Array GPU: 18.000000
Array GPU: 19.000000
Array GPU: 20.000000
Array GPU: 21.000000
Array GPU: 22.000000
Array GPU: 23.000000
Array GPU: 24.000000
Array GPU: 25.000000
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 34.000000
Array GPU: 35.000000
Array GPU: 36.000000
Array GPU: 37.000000
Array GPU: 38.000000
Array GPU: 39.000000
Array GPU: 40.000000
Array GPU: 41.000000
Array GPU: 42.000000
Array GPU: 43.000000
Array GPU: 44.000000
Array GPU: 45.000000
Array GPU: 46.000000
Array GPU: 47.000000
Array GPU: 48.000000
Array GPU: 49.000000
Array GPU: 50.000000
Array GPU: 51.000000
Array GPU: 52.000000
Array GPU: 53.000000
Array GPU: 54.000000
Array GPU: 55.000000
Array GPU: 56.000000
Array GPU: 57.000000
Array GPU: 58.000000
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000     &lt-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 68.000000
Array GPU: 69.000000
...

As you can see, incorrect values are received by the device with no apparent pattern, and no error code is returned by clEnqueueWriteBuffer function.

To summarize: A memory block is sent to the kernel, but kernel receives zero'ed memory depending on the total block size sent.

The same code tested on different computers behaves differently (incorrect values in different iterations).

How can be memory corruption avoided? Am I missing something?

Thanks in advance.


Here's the complete working code:


Edit: After some tests, it needs to be clarify that the problem is not in the printf. The problem seems to be in the transfer of data to the device, previous to the execution of the kernel.

Here's the code without the execution of the kernel. The results are still wrong.

1
All of this looks like C code, you may want to untag C++ unless you want to receive numerous "dont use malloc, or new, use vector" comments/answers. - Borgleader
Are you checking the return values of the various OpenCL API calls? You are getting the return values (ret = ...) but then ignoring the value returned. It would be useful to know if one of those functions is failing. - dsharlet
The return values of every openCL function are printed in the complete working code which is linked at the end of the post. I removed those lines in the piece of code inside the post only to simplify it. However, I checked the return values of every function and in the cases where kernel returns zero (wrong value) none of them returns an error code. Thanks for the answer. - Backgroung
Usually 0 values on a GPU is out-of-bounds memory access. Run it on the CPU and see if you get a stack overflow? Check this answer:stackoverflow.com/questions/25536033/… - Austin
Let me guess, "AMD printf"... is quite known for printing the variable values wrong. Try setting the second address to the value of the first, and reading itfrom CPU. You will find that the operation was OK. See this question: stackoverflow.com/questions/24450831/… - DarkZeros

1 Answers

0
votes

Have you tried

   CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR

since your gpu shares same memory with CPU?

Device is also at the same place of host for your iGPU.

Create some buffers, do stress test on them, if all of them get invalid values then install another driver version probably a newer one, if this doesnt solve, RMA your card.

If only a single buffer is erroneous then it is simple vram error , tag that buffer as unusable and create new buffers as necesary and avoid that buffer but Im not sure if driver swaps buffers in background. If every single kernel is malfunctioning then cores may be damaged too.