Tak więc bawię się teraz z OpenCL i testuję prędkości transferu pamięci między hostem a urządzeniem. Użyłem Intel OpenCL SDK i działa na Intel i5 Processor ze zintegrowaną grafiką. Następnie odkryto clEnqueueMapBuffer
zamiast clEnqueueWriteBuffer
który okazał się szybciej, prawie 10 razy przy użyciu przypięte pamięci tak:CL_MEM_ALLOC_HOST_PTR wolniej niż CL_MEM_USE_HOST_PTR
int amt = 16*1024*1024;
...
k_a = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(int)*amt, a, NULL);
k_b = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(int)*amt, b, NULL);
k_c = clCreateBuffer(context,CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, sizeof(int)*amt, ret, NULL);
int* map_a = (int*) clEnqueueMapBuffer(c_q, k_a, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
int* map_b = (int*) clEnqueueMapBuffer(c_q, k_b, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
int* map_c = (int*) clEnqueueMapBuffer(c_q, k_c, CL_TRUE, CL_MAP_WRITE, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
clFinish(c_q);
przypadku a
b
i ret
są dopasowane 128 bit int tablice. Czas wyszedł do około 22,026186 ms, w porównaniu do 198,604528 ms korzystających clEnqueueWriteBuffer
Jednak, gdy zmieniłem kod do
k_a = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, NULL);
k_b = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, NULL);
k_c = clCreateBuffer(context,CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, NULL);
int* map_a = (int*)clEnqueueMapBuffer(c_q, k_a, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
int* map_b = (int*)clEnqueueMapBuffer(c_q, k_b, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
int* map_c = (int*)clEnqueueMapBuffer(c_q, k_c, CL_TRUE, CL_MAP_WRITE, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
/** initiate map_a and map_b **/
czas zwiększa się 91,350065 ms
Co może być problemem? Czy to w ogóle problem?
EDIT: ten sposób zainicjować tablice w drugiej Kod:
for (int i = 0; i < amt; i++)
{
map_a[i] = i;
map_b[i] = i;
}
a teraz, że mogę sprawdzić, map_a i map_b zrobić zawierać odpowiednie elementy na końcu programu, ale map_c zawiera wszystkie 0. Zrobiłem to:
clEnqueueUnmapMemObject(c_q, k_a, map_a, 0, NULL, NULL);
clEnqueueUnmapMemObject(c_q, k_b, map_b, 0, NULL, NULL);
clEnqueueUnmapMemObject(c_q, k_c, map_c, 0, NULL, NULL);
i moje jądro jest tylko
__kernel void test(__global int* a, __global int* b, __global int* c)
{
int i = get_global_id(0);
c[i] = a[i] + b[i];
}
w drugim kodzie możesz pokazać, jak zainicjować k_a, k_b i k_c z danymi a, b i ret i gdzie jest clFinish. Jeśli 2 kody robią różne rzeczy, trudno będzie ci pomóc. –
Niestety, kod jest taki sam, po prostu nie skopiowałem wszystkiego przypadkowo.W drugim kodzie nie inicjalizuję k_c z ret, ponieważ pomyślałem, że mogłem po prostu odczytać dane z map_c. – selena731
Po mapowaniu i używaniu, musisz albo usunąć mapę, albo wykonać clWrite/Read z odwzorowanego obiektu w celu zapewnienia spójności pamięci. – DarkZeros