2016-03-13 50 views
0

我正在编写一个程序,它会尝试每个32位数字的组合,查看它是否符合某些条件并返回这些条件。从示例程序中我已经看到数组的大小始终是(元素的数量* sizeof())。使用CUDA进行暴力攻击。关于内存分配

这个数字看起来太大了,而且大多数数字也会被拒绝,所以我不需要2^32数组。我知道结果的数量将大大少于2^32,但我不知道究竟会有多少。

此外,每个线程都会在尝试数字时循环,因此线程可能有多个积极结果。

那么如何做内存分配,以及如何存储接受的值?

回答

4

一种方法是尝试尽可能多地分配内存,或者认为您需要存储内核输出,然后使用原子增量计数器来跟踪输出缓冲区中的下一个空闲位置,其中任何给定的线程都可以存储结果。

例如,如果你定义一个辅助结构是这样的:在主机代码

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

该解决方案将可能是最有用的,当内核的输出是相当“疏”,即数量相对于线程数量或输入数量的输出相当小。如果你的问题更加“密集”,即内核相对于线程或输入数量将发出大量输出,那么原子内存事务可能会造成显着的性能损失。在这种情况下,将线程存储到“稀疏”输出缓冲区并使用流压缩传递消除内核输出缓冲区中的少量空条目可能会更好。

+1

我不认为会有一些全局变量会在所有衍生线程中共享,我可以增加它呢? – watisit

+0

@watisit:这正是我给的代码所做的。如果你有一个全局变量,无论是静态还是动态声明,你都必须使用原子增量操作来使其工作。该类只是糖,使生活更轻松(它可以与支持原子内存交易的任何类型的内存一起工作,如共享内存) – talonmies

+0

如何在主机代码中打印结果? – watisit