2013-10-30 49 views
2

我有一個需要使用全局內存的CUDA(v5.5)應用程序。理想情況下,我寧願使用常量內存,但我已經耗盡了常量內存,並且溢出將不得不放置在全局內存中。我還有一些需要偶爾寫入的變量(在對GPU進行一些簡化操作之後),我將它放在全局內存中。全局內存與CUDA中的動態全局內存分配

對於閱讀,我將以簡單的方式訪問全局內存。我的內核在for循環中被調用,並且在每次內核調用時,每個線程都將訪問完全相同的全局內存地址,且無偏移量。對於編寫而言,在每次調用內核之後,都會在GPU上執行縮減操作,並且必須在循環的下一次迭代之前將結果寫入全局內存。然而,在我的應用程序中寫入全局內存的讀取次數要多得多。

我的問題是使用全局(變量)作用域中聲明的全局內存使用動態分配的全局內存是否有任何優勢?我需要的全局內存量將根據應用程序而改變,因此動態分配會更好。我知道我的全局內存使用的上限,但我更關心性能,所以我也可以使用大的固定分配靜態地聲明內存,我肯定不會溢出。考慮到性能,是否有理由更喜歡一種形式的全局內存分配?它們是否存在於GPU上相同的物理位置,並且是以相同方式緩存的,還是兩種形式的讀取代價不同?

回答

9

Global memory可以分配statically和經由CUDA runtime(例如,使用cudaMalloc的)。

所有上述方法在物理上分配相同類型的存儲器,即從板上(但不是片上)DRAM子系統中劃出的存儲器。該內存具有相同的訪問,合併和緩存規則,無論它如何分配(因此具有相同的一般性能注意事項)。

由於動態分配需要一些非零時間,因此可以通過在程序開始時執行一次分配(使用靜態方法(即__device__)方法或通過運行時API (即cudaMalloc等)這可以避免在代碼的性能敏感區域花時間動態分配內存。

另請注意,我概述的3種方法雖然具有與設備代碼類似的類似C/C++的訪問方法,但與主機有不同的訪問方法。靜態分配的存儲器被使用像cudaMemcpyToSymbolcudaMemcpyFromSymbol運行時API函數訪問,運行時API分配的內存經由普通cudaMalloc/cudaMemcpy型功能訪問,並且動態分配的全局存儲器(裝置newmalloc)不從主機直接訪問。

+0

謝謝,這完全回答了我有問題,還有一些我甚至沒有問過。 –

1

首先你需要考慮合併內存訪問。你沒有提到你正在使用的GPU。在最新的GPU中,煤礦帶內存讀取將具有與恆定內存相同的性能。所以,儘可能地儘可能地讓你的記憶以煤礦的方式讀寫。

另一個你可以使用紋理內存(如果數據大小適合它)。這個紋理內存有一些緩存機制。這是以前用於全局內存讀取未合併的情況。但最新的GPU給紋理和全局內存提供了幾乎相同的性能。

我不認爲全局聲明的內存比動態分配的全局內存提供更多的性能,因爲合併問題依然存在。在全局(變量)作用域中聲明的全局內存在CUDA全局內存情況下也是不可能的。可以全局聲明(在程序中)的變量是常量內存變量和紋理,我們不需要將它們作爲參數傳遞給內核。

以進行內存優化請參閱(使用__device__dynamically(使用設備mallocnew)在CUDA C最佳實踐指南的存儲器最優化部http://docs.nvidia.com/cuda/cuda-c-best-practices-guide/#memory-optimizations

+0

感謝您的指針。我在亞馬遜AWS上使用Tesla M2050s。我理解合併問題。但是,從靜態與動態分配的全局內存的合併讀取之間是否有任何區別是我猜想的問題的關鍵。另外,我不確定最後一行是「唯一全局聲明的變量是常量內存變量和紋理」。根據這個(https://developer.nvidia.com/content/how-access-global-memory-efficiently-cuda-cc-kernels),CUDA全局內存中有全局(可變)範圍。儘管這個鏈接沒有解決我的原始問題。內存優化 –

+0

請參閱cuda c最佳實踐指南中的內存優化部分http://docs.nvidia.com/cuda/cuda-c-best-practices-guide/#memory-optimizations – Sijo