2013-07-21 25 views
5

Vì vậy, tôi đã chơi xung quanh với OpenCL một chút ngay bây giờ và kiểm tra tốc độ truyền bộ nhớ giữa máy chủ và thiết bị. Tôi đang sử dụng SDK Intel OpenCL và chạy trên Intel i5 Processor với đồ họa tích hợp. Sau đó tôi phát hiện ra clEnqueueMapBuffer thay vì clEnqueueWriteBuffer mà hóa ra là nhanh hơn gần 10 lần khi sử dụng bộ nhớ gắn như vậy:CL_MEM_ALLOC_HOST_PTR chậm hơn 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); 

đâu abret là 128 bit liên kết int mảng. Hiện ra khoảng 22,026186 ms, so với 198,604528 ms sử dụng clEnqueueWriteBuffer Tuy nhiên, khi tôi đã thay đổi mã của tôi để

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 **/ 

thời gian tăng lên 91,350065 ms

Điều gì có thể là vấn đề? Hay nó là một vấn đề?

EDIT: Đây là cách tôi khởi tạo các mảng trong mã thứ hai:

for (int i = 0; i < amt; i++) 
{ 
    map_a[i] = i; 
    map_b[i] = i; 
} 

Và bây giờ mà tôi kiểm tra, map_a và map_b làm chứa các yếu tố ngay ở phần cuối của chương trình, nhưng map_c chứa tất cả 0. Tôi đã làm điều này:

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); 

và hạt nhân của tôi chỉ là

__kernel void test(__global int* a, __global int* b, __global int* c) 
{ 
    int i = get_global_id(0); 
    c[i] = a[i] + b[i]; 
} 
+0

trong mã thứ hai, bạn có thể cho biết cách bạn khởi tạo k_a, k_b và k_c với dữ liệu a, b và ret và vị trí clFinish. Nếu 2 mã làm những việc khác nhau sẽ rất khó để giúp bạn –

+0

Xin lỗi, mã giống nhau tôi không sao chép mọi thứ một cách vô tình.Trong mã thứ hai, tôi không khởi tạo k_c với ret vì tôi nghĩ rằng tôi có thể đọc dữ liệu từ map_c. – selena731

+0

Sau khi ánh xạ và sử dụng, bạn có thể để unmap, hoặc để thực hiện một clWrite/Read từ đối tượng được ánh xạ để đảm bảo tính nhất quán của bộ nhớ. – DarkZeros

Trả lời

1

sự hiểu biết của tôi là giao đất CL_MEM_ALLOC_HOST_PTR nhưng không sao chép. Liệu khối thứ 2 của mã thực sự nhận được bất kỳ dữ liệu nào trên thiết bị?

Ngoài ra, clCreateBuffer khi được sử dụng với CL_MEM_USE_HOST_PTR và CL_MEM_COPY_HOST_PTR không nên yêu cầu clEnqueueWrite, vì bộ đệm được tạo bằng bộ nhớ được trỏ tới bởi void * host_ptr.

Sử dụng "gắn" bộ nhớ trong OpenCL phải là một quá trình như:

int amt = 16*1024*1024; 
    int Array[] = new int[amt]; 
    int Error = 0; 

    //Note, since we are using NULL for the data pointer, we HAVE to use CL_MEM_ALLOC_HOST_PTR 
    //This allocates memory on the devices 
    cl_mem B1 = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, &Error); 

    //Map the Device memory to host memory, aka pinning it 
    int *host_ptr = clEnqueueMapBuffer(queue, B1, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, sizeof(int)*amt, 0, NULL, NULL, &Error); 

    //Copy from host memory to pinned host memory which copies to the card automatically` 
    memcpy(host_ptr, Array, sizeof(int)*amt); 

    //Call your kernel and everything else and memcpy back the pinned back to host when 
    //you are done 

Edit: Một điều cuối cùng bạn có thể làm để tăng tốc độ chương trình là không làm cho bộ nhớ đọc/ghi chặn bằng cách sử dụng CL_FALSE thay vì CL_TRUE. Chỉ cần đảm bảo gọi clFinish() trước khi dữ liệu được sao chép trở lại máy chủ để hàng đợi lệnh bị làm trống và tất cả các lệnh được xử lý.

Nguồn: OpenCL In Action

+0

Sry nhưng tôi không thể đồng ý với câu trả lời này. Kể từ khi ánh xạ bộ nhớ và thực hiện một memcpy() thực sự sao chép dữ liệu song song bằng DMA và nó sẽ nhanh hơn. Tuy nhiên, bạn không thể sử dụng nó trong kernel mà không có unmap(). Vì hạt nhân có thể sử dụng một bản sao không hoàn chỉnh của bộ đệm. Thông thường điều này có thể dẫn đến tốc độ nhân tạo lên, đó là không thực sự spped lên ở tất cả, nhưng sao chép bộ nhớ không đầy đủ. – DarkZeros

+0

Câu trả lời này có gây nhầm lẫn ánh xạ (tức là các giao dịch PCIe ghi vào một bên) với ghim (tức là khóa trang, để bạn không bao giờ phải giải quyết trang vật lý hoặc hoán đổi)? – einpoklum

0

Với sự kết hợp của lá cờ, bạn sẽ có thể để đạt được "không sao" (tức là rất nhanh) bản đồ/unmap trên Intel Graphics Tích hợp vì không có nhu cầu về một "CPU để GPU "sao chép vì cả hai đều sử dụng cùng một bộ nhớ (đó là những gì" tích hợp "có nghĩa là). Đọc phần Intel OpenCL Optimization Guide trên bộ nhớ.

Các vấn đề liên quan