拳头,让我解释一下我正在实施的内容。我的程序的目标是在启用cuda的GPU上生成给定字符集的所有可能的,非独特的组合。为了并行化工作,我将每个线程初始化为一个起始字符。
例如,考虑字符集abcdefghijklmnopqrstuvwxyz
。在这种情况下,理想情况下会有26个线程:例如characterSet[threadIdx.x] = a
(实际上,显然会有一个偏移量来跨越整个网格,以便每个线程都有一个唯一的标识符)。
到目前为止,这是我的代码:
//Used to calculate grid dimensions
int* threads;
int* blocks;
int* tpb;
int charSetSize;
void calculate_grid_parameters(int length, int size, int* threads, int* blocks, int* tpb){
//Validate input
if(!threads || !blocks || ! tpb){
cout <<"An error has occured: Null pointer passed to function...\nPress enter to exit...";
getchar();
exit(1);
}
//Declarations
const int maxBlocks = 65535; //Does not change
int maxThreads = 512; //Limit in order to provide more portability
int dev = 0;
int maxCombinations;
cudaDeviceProp deviceProp;
//Query device
//cudaGetDeviceProperties(&deviceProp, dev);
//maxThreads = deviceProp.maxThreadsPerBlock;
//Determine total threads to spawn
//Length of password * size of character set
//Each thread will handle part of the total number of the combinations
if(length > 3) length = 3; //Max length is 3
maxCombinations = length * size;
assert(maxCombinations < (maxThreads * maxBlocks));
}
这是相当基本的。
由于特定原因,我将长度限制为3。我相信完整的字符集abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !\"#$&'()*+-.:;<>=?@[]^_{}~|
是92个字符。这意味着长度为3,有778,688种可能的非独特组合。如果长度为4,则大约为7100万,而GPU的最大线程数约为6900万(在一个维度上)。此外,这些组合已经在一个文件中生成,该文件将被读入一个数组,然后委托一个特定的初始化线程。
这引出了我的问题。
cuda GPU上的最大块数(1-d)为65,535。每个块(在我的gpu上)都可以在一个维度上运行1024个线程。为了便携性,我在代码中将其限制为512(这可能是不必要的)。理想情况下,每个块应运行32个线程或32个线程的倍数,以便提高效率。我遇到的问题是我需要多少线程。就像我上面说的那样,如果我使用长度为3的完整字符集作为起始值,则需要778,688个线程。这恰好可以被32整除,假设每个块运行32个线程,产生24,334个块。但是,如果我运行长度为2的相同字符集,我将留下264.5个块,每个块运行32个线程。
基本上,我的字符集是可变的,初始化组合的长度可以从1-3变化。
如果我向上舍入到最接近的整数,我的偏移索引tid = threadIdx.x + ....
将访问不存在的数组部分。
如何以这样的方式处理此问题仍然可以高效运行并且不会产生可能导致内存问题的不必要线程?
赞赏任何有建设性的意见。
答案 0 :(得分:2)
您发布的代码似乎没有做任何重要的事情,并且不包含cuda代码。
您的问题似乎是:
如何以这样的方式处理此问题仍然可以高效运行并且不会产生可能导致内存问题的不必要线程?
通常的做法是启动内核以“舍入”到最近的线程增量,可能是32,也许是32的某个倍数,这样就可以启动整数个块。在这种情况下,通常的做法是在内核代码中包含一个线程检查,例如:
__global__ void mykernel(.... int size){
int idx=threadIdx.x + blockDim.x*blockIdx.x;
if (idx < size){
//main body of kernel code here
}
}
在这种情况下,size
是您的整体问题大小(您实际需要的线程数)。无效的其他线程的开销通常不是一个重要的性能问题。