Pracuję w jakimś kodzie, który wysyła duże ilości danych z hosta do urządzenia, i zachowuje się nieregularnie.Uszkodzenie pamięci za pomocą clEnqueueWriteBuffer - OpenCL
W poniższym kodzie próbuję wysłać z hosta do urządzenia tablicę. Rozmiar macierzy zwiększa się w każdej iteracji, stopniowo zwiększając ilość pamięci wysyłanej do urządzenia. Pierwszy element w tablicy jest wypełniany niezerową wartością i jest odczytywany z wnętrza jądra i drukowany na konsoli. Wartość powinna być taka sama, gdy jest odczytywana z hosta i urządzenia, ale w niektórych iteracjach tak nie jest.
Oto kod:
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);
}
Urządzenie gdzie ten kod został przetestowany posiada następujące cechy:
-
- 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
jądra drukuje niepoprawne wartości lub nie, w zależności od wielkości bufora wysyłanych do urządzenia .
Oto wynik:
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 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- 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 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 0.000000 <-------- INCORRECT VALUE, kernel is receiving corrupted memory
Array GPU: 68.000000
Array GPU: 69.000000
...
Jak widać, nieprawidłowe wartości są odbierane przez urządzenie bez widocznego wzoru, a nie kod błędu zwrócony przez clEnqueueWriteBuffer funkcji.
Podsumowując: Blok pamięci jest wysyłany do jądra, ale jądro otrzymuje pamięć zerową w zależności od wysłanego całkowitego rozmiaru bloku.
Ten sam kod testowany na różnych komputerach zachowuje się inaczej (nieprawidłowe wartości w różnych iteracjach).
Jak można uniknąć uszkodzenia pamięci? Czy czegoś brakuje?
Z góry dziękuję.
Here jest kompletny kod roboczych:
Edit: Po kilku testach, należy wyjaśnić, że problem nie leży w printf. Problem wydaje się być związany z transferem danych do urządzenia, przed uruchomieniem jądra.
Here to kod bez wykonywania jądra. Wyniki są nadal błędne.
Wszystko to wygląda jak kod C, możesz odcyfrować C++, chyba że chcesz otrzymywać liczne komentarze i odpowiedzi "nie używaj malloc, new, use vector". – Borgleader
Czy sprawdzasz zwracane wartości różnych wywołań interfejsu API OpenCL? Otrzymujesz wartości zwracane (ret = ...), ale ignorujesz zwróconą wartość. Przydałoby się wiedzieć, czy jedna z tych funkcji nie działa. – dsharlet
Wartości zwracane każdej funkcji openCL są drukowane w pełnym kodzie roboczym, który jest połączony na końcu postu. Usunąłem te linie z fragmentu kodu wewnątrz postu tylko po to, aby go uprościć. Jednak sprawdziłem wartości zwracane każdej funkcji oraz w przypadkach, gdy jądro zwraca zero (zła wartość), żadne z nich nie zwraca kodu błędu. Dziękuję za odpowiedź. – Backgroung