2010-09-30 47 views
13

我在教程中看到了這兩個版本,但我找不到它們的優點和缺點。哪一個是正確的?使用clCreateBuffer + CL_MEM_COPY_HOST_PTR創建緩衝區對象與clCreateBuffer + clEnqueueWriteBuffer之間有什麼區別?

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

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

感謝。

[更新]

我添加CL_MEM_COPY_HOST_PTR,第二示例以使其正確。

回答

5

我假設inputdata不是NULL。

在這種情況下,第二種方法不應該在所有的工作,因爲規範說,這clCreateBuffer返回NULL和一個錯誤,如果:

CL_INVALID_HOST_PTR如果host_ptr爲NULL和CL_MEM_USE_HOST_PTR或CL_MEM_COPY_HOST_PTR在標誌設置或者如果host_ptr不爲NULL,但CL_MEM_COPY_HOST_PTR或CL_MEM_USE_HOST_PTR未在標誌中設置。

所以你的意思是要麼

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

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

第一個應該是或多或少一樣的,你表現出第一種方法,而第二個實際上不會複製數據,而是使用提供的內存位置進行緩衝存儲(緩存部分或全部在設備內存中)。哪兩個更好取決於使用場景。

Personaly我更喜歡使用第一步分配緩衝區的兩步法,然後用writeToBuffer填充它,因爲我發現更容易看到會發生什麼(當然,一步可能會更快(或者它可能不會,那只是猜測))

+1

嗨灰熊,你是對的。我忘記了CL_MEM_COPY_HOST_PTR。因此,沒有任何事實可以說明一個或另一個? – Framester 2010-10-01 09:58:06

+0

至少從規格來看不應該有。當然,性能可能會(或可能不會)變化,但這會依賴於實現並且可能會發生變化,所以我不會指望它(如果性能對於內存傳輸至關重要,那麼可能會考慮將異步內存傳輸(使用CL_FALSE作爲clEnqueueWriteToBuffer的阻塞參數)再次判斷它的更快取決於實現,對於CPU,最快的應該是使用CL_USE_HOST_PTR。一般來說,我會確保memtransfertime沒有那麼重要,並且可以用這個來完成 – Grizzly 2010-10-01 13:33:11

+0

謝謝,表演並不重要,它更像是一個學術問題。 – Framester 2010-10-01 15:04:17

1

那麼這兩者之間的主要區別在於第一個在設備上分配內存,然後將數據複製到該內存。第二個只分配。

還是你的意思是clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);

+0

嗨史蒂文,你說得對。我忘記了CL_MEM_COPY_HOST_PTR。那麼他們現在有什麼不同呢? – Framester 2010-10-01 09:56:18

+0

我不認爲他們這樣做,除非像灰熊提到的那樣進行異步傳輸。 – 2010-10-01 15:20:31

2

一個主要區別是我碰到的:

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

這第一組命令將創建一個空的緩衝區,並在你的命令隊列排隊的命令來填充緩衝區。

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

第二個命令將創建緩衝區並立即填充。請注意,此參數列表中沒有命令隊列,因此它現在使用輸入數據的內容。

如果您已經運行CL代碼,並且您的源指針依賴於命令隊列完成中的先前命令(例如,一個先前的輸出緩衝區的入隊讀取),你一定要使用第一種方法。如果嘗試在單個命令中創建並填充緩衝區,則最終會出現競爭條件,在該競爭條件下,緩衝區內容將無法正確等待前一個緩衝區讀取的完成。

2

第一種方法的好處在於「clEnqueueWriteBuffer」允許您將事件分配給緩衝區副本。因此,假設您要測量使用GPU_Profiling選項將數據複製到GPU所用的時間,您將可以使用第一種方法執行此操作,但不能使用第二種方法。

第二種方法更緊湊,更易於閱讀,並且需要更少的代碼行。

7

在我和OpenCL的工作,我發現

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

之間一個非常重要的區別對於第一種方法的OpenCL將複製主機指針不是直接到GPU。首先,它會在主機上分配第二個臨時緩衝區,如果您將諸如CT之類的大型內容加載到GPU上,會導致問題。短時間內,所需的內存是CT尺寸的兩倍。此外,該功能期間不會複製數據。它在參數設置期間被複制到使用3D圖像對象的內核函數。

第二種方法直接將數據複製到GPU。 OpenCL沒有額外的分配。我認爲這對普通緩衝區對象可能是相同的。

相關問題