我正在編寫一個程序,它會嘗試每個32位數字的組合,查看它是否符合某些條件並返回這些條件。從示例程序中我已經看到數組的大小始終是(元素的數量* sizeof())。使用CUDA進行暴力攻擊。關於內存分配
這個數字看起來太大了,而且大多數數字也會被拒絕,所以我不需要2^32數組。我知道結果的數量將大大少於2^32,但我不知道究竟會有多少。
此外,每個線程都會在嘗試數字時循環,因此線程可能有多個積極結果。
那麼如何做內存分配,以及如何存儲接受的值?
我正在編寫一個程序,它會嘗試每個32位數字的組合,查看它是否符合某些條件並返回這些條件。從示例程序中我已經看到數組的大小始終是(元素的數量* sizeof())。使用CUDA進行暴力攻擊。關於內存分配
這個數字看起來太大了,而且大多數數字也會被拒絕,所以我不需要2^32數組。我知道結果的數量將大大少於2^32,但我不知道究竟會有多少。
此外,每個線程都會在嘗試數字時循環,因此線程可能有多個積極結果。
那麼如何做內存分配,以及如何存儲接受的值?
一種方法是嘗試儘可能多地分配內存,或者認爲您需要存儲內核輸出,然後使用原子增量計數器來跟蹤輸出緩衝區中的下一個空閒位置,其中任何給定的線程都可以存儲結果。
例如,如果你定義一個輔助結構是這樣的:在主機代碼
struct counter
{
unsigned int * _val;
__host__ __device__
counter(unsigned int * value) : _val(value) {};
__device__
unsigned int next() {
return atomicAdd(_val, 1);
};
}
,然後像做
unsigned int * array_index;
const unsigned int zero = 0;
cudaMalloc((void **)&array_index, sizeof(unsigned int*));
cudaMemcpy(array_index, &zero, sizeof(unsigned int), cudaMemcpyHostToDevice);
counter mycounter(array_index);
你可以是零初始化設備內存計數器通過反覆調用next()
方法,安全地讀取並增加設備代碼。
在內核這個樣子:
__global__ void kernel(Type * buffer, counter mycounter)
{
// Calculate and find a match...
buffer[mycounter.next()] = match;
}
[強烈警告:寫在瀏覽器的所有代碼,沒有編譯或測試,可能會設置你的GPU着火,在風險自負]
你然後內核可以爲每個線程發出儘可能多的輸出,以適應您的算法設計。將上面闡述的設計模式擴展到包含數組邊界檢查是明智的。還應注意的其中發出的內核可以這樣被檢索輸出總數:
unsigned int N;
cudaMemcpy(&N, array_index, sizeof(unsigned int), cudaMemcpyDeviceToHost);
該解決方案將可能是最有用的,當內核的輸出是相當「疏」,即數量相對於線程數量或輸入數量的輸出相當小。如果你的問題更加「密集」,即內核相對於線程或輸入數量將發出大量輸出,那麼原子內存事務可能會造成顯着的性能損失。在這種情況下,將線程存儲到「稀疏」輸出緩衝區並使用流壓縮傳遞消除內核輸出緩衝區中的少量空條目可能會更好。
我不認爲會有一些全局變量會在所有衍生線程中共享,我可以增加它呢? – watisit
@watisit:這正是我給的代碼所做的。如果你有一個全局變量,無論是靜態還是動態聲明,你都必須使用原子增量操作來使其工作。該類只是糖,使生活更輕鬆(它可以與支持原子內存交易的任何類型的內存一起工作,如共享內存) – talonmies
如何在主機代碼中打印結果? – watisit