2010-09-30 9 views
13

Tôi đã thấy cả hai phiên bản trong hướng dẫn, nhưng tôi không thể tìm ra, những lợi thế và bất lợi của họ là gì. Cái nào là đúng?Sự khác nhau giữa việc tạo đối tượng đệm với clCreateBuffer + CL_MEM_COPY_HOST_PTR so với clCreateBuffer + clEnqueueWriteBuffer là gì?

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY,sizeof(float) * DATA_SIZE, NULL, NULL); 
clEnqueueWriteBuffer(command_queue, input, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputdata, 0, NULL, NULL); 

vs

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ,sizeof(float) * DATA_SIZE, inputdata, NULL); 

Cảm ơn.

[Cập nhật]

tôi thêm CL_MEM_COPY_HOST_PTR, để ví dụ thứ hai để làm cho nó đúng.

Trả lời

5

Tôi giả định rằng inputdata không phải là NULL.

Trong trường hợp đó, cách tiếp cận thứ hai không nên làm việc ở tất cả, kể từ khi thông số kỹ thuật nói, rằng clCreateBuffer trả về NULL và một lỗi, nếu:

CL_INVALID_HOST_PTR nếu host_ptr là NULL và CL_MEM_USE_HOST_PTR hoặc CL_MEM_COPY_HOST_PTR được thiết lập trong cờ hoặc nếu host_ptr không phải là NULL nhưng CL_MEM_COPY_HOST_PTR hoặc CL_MEM_USE_HOST_PTR không được đặt trong cờ.

vì vậy bạn có nghĩa là một trong hai

clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL); 

hoặc

clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL); 

Người đầu tiên nên được nhiều hơn hoặc ít hơn giống như các phương pháp tiếp cận đầu tiên bạn thấy, trong khi cái thứ hai sẽ không thực sự sao chép dữ liệu, nhưng thay vào đó hãy sử dụng vị trí bộ nhớ được cung cấp để lưu bộ nhớ đệm (các phần lưu trong bộ nhớ đệm hoặc toàn bộ bộ nhớ trong bộ nhớ thiết bị). Cái nào trong hai cái này tốt hơn phụ thuộc vào kịch bản sử dụng rõ ràng.

Cá nhân tôi thích sử dụng phương pháp tiếp cận hai bước để cấp phát bộ đệm và sau đó điền vào nó với một writeToBuffer, vì tôi thấy dễ dàng hơn để xem điều gì xảy ra (tất nhiên một bước có thể nhanh hơn (hoặc có thể không, đoán))

+1

Xin chào Grizzly, bạn đã đúng. Tôi đã quên CL_MEM_COPY_HOST_PTR. Vì vậy, không có sự thật khó khăn mà nói cho một hay khác? – Framester

+0

Ít nhất là từ các thông số kỹ thuật không nên có. Hiệu suất ofcourse có thể (hoặc có thể không) khác nhau, nhưng điều đó sẽ phụ thuộc vào việc thực hiện và có thể thay đổi, vì vậy tôi sẽ không dựa vào nó dù sao đi nữa (nếu hiệu suất là rất quan trọng đối với việc truyền tải bộ nhớ) (sử dụng CL_FALSE như là tham số chặn của clEnqueueWriteToBuffer) Một lần nữa có hay không nó nhanh hơn phụ thuộc vào ntation impleme, cho CPU nhanh nhất nên sử dụng CL_USE_HOST_PTR Nói chung tôi sẽ đảm bảo rằng memtransfertime không quan trọng nhiều và được donewith rằng – Grizzly

+0

Cảm ơn, hiệu suất không phải là sooo quan trọng, nó đã được nhiều hơn một câu hỏi học thuật. – Framester

1

Sự khác biệt chính giữa hai điều này là điểm đầu tiên phân bổ bộ nhớ trên thiết bị và sau đó sao chép dữ liệu vào bộ nhớ đó. Cái thứ hai chỉ phân bổ.

Hoặc bạn có nghĩa là clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);?

+0

Xin chào stevenhb, bạn đã đúng. Tôi đã quên CL_MEM_COPY_HOST_PTR. Vậy bây giờ chúng khác nhau như thế nào? – Framester

+0

Tôi không nghĩ rằng họ làm, ngoại trừ khả năng chuyển giao không đồng bộ, như Grizzly đã đề cập. –

2

một khác biệt lớn mà tôi đã chạy vào:

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY,sizeof(float) * DATA_SIZE, NULL, NULL); clEnqueueWriteBuffer(command_queue, input, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputdata, 0, NULL, NULL);

này tập đầu tiên của lệnh sẽ tạo ra một bộ đệm rỗng và enqueue một lệnh trong hàng đợi lệnh của bạn để điền vào bộ đệm.

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ,sizeof(float) * DATA_SIZE, inputdata, NULL) 

Lệnh thứ hai này sẽ tạo bộ đệm và điền ngay vào bộ đệm. Lưu ý rằng không có hàng đợi lệnh trong danh sách đối số này, vì vậy nó sử dụng nội dung của dữ liệu đầu vào như hiện tại.

Nếu bạn đã chạy mã CL và con trỏ nguồn của bạn phụ thuộc vào lệnh trước đó trong hàng đợi lệnh hoàn thành (ví dụ:một đọc enqueued của một bộ đệm đầu ra trước), bạn chắc chắn muốn sử dụng phương pháp 1. Nếu bạn cố gắng tạo và điền vào bộ đệm trong một lệnh duy nhất, bạn sẽ kết thúc với một điều kiện chủng tộc trong đó các nội dung bộ đệm sẽ không chờ đợi đúng khi hoàn thành bộ đệm đệm trước của bạn.

2

Mặt đẹp của phương pháp thứ nhất, là "clEnqueueWriteBuffer" cho phép bạn chỉ định một sự kiện cho bản sao của bộ đệm. Vì vậy, giả sử bạn muốn đo thời gian cần để sao chép dữ liệu vào GPU bằng cách sử dụng tùy chọn GPU_Profiling, bạn sẽ có thể làm như vậy với phương pháp tiếp cận đầu tiên, nhưng không thể thực hiện với phương pháp thứ hai.

Cách tiếp cận thứ hai nhỏ gọn hơn, dễ đọc hơn và yêu cầu ít dòng mã hơn.

7

Trong làm việc của tôi với OpenCL Tôi tìm thấy một sự khác biệt rất quan trọng giữa

cl_mem CT = clCreateImage3DContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , Volume_format, X, Y, Z, rowPitch, slicePitch, sourceData, &error); 

cl_mem CT = clCreateImage3D(Context, CL_MEM_READ_ONLY , Volume_format, X, Y, Z, 0, 0, 0, &error); 
error = clEnqueueWriteImage(CommandQue, CT, CL_TRUE, origin, region, rowPitch, slicePitch, sourceData, 0, 0, 0); 

Đối với phương pháp tiếp cận đầu tiên OpenCL sẽ sao chép các con trỏ máy chủ không chỉ đạo cho GPU. Đầu tiên nó sẽ cấp phát một bộ đệm tạm thời thứ hai trên máy chủ có thể gây ra vấn đề nếu bạn tải những thứ lớn như CT vào GPU. Trong một thời gian ngắn, bộ nhớ cần thiết gấp đôi kích thước CT. Ngoài ra, dữ liệu không được sao chép trong khi thực hiện chức năng này. Nó được sao chép trong cài đặt đối số cho hàm hạt nhân sử dụng đối tượng hình ảnh 3D.

Cách tiếp cận thứ hai sẽ trực tiếp sao chép dữ liệu vào GPU. Không có phân bổ bổ sung được thực hiện bởi OpenCL. Tôi nghĩ rằng điều này có lẽ là giống nhau cho các đối tượng đệm bình thường.