Cuda “全局”函数如何返回值或像C/C++;做
最近我在CUDA上做字符串比较工作,我想知道当一个_全局_函数找到我要查找的确切字符串时,它怎么能返回一个值 我的意思是,我需要包含大量线程的_uglobal _u u u u u u u u u u u u u u u u u u u u u u u u u u u uCuda “全局”函数如何返回值或像C/C++;做,cuda,Cuda,最近我在CUDA上做字符串比较工作,我想知道当一个_全局_函数找到我要查找的确切字符串时,它怎么能返回一个值 我的意思是,我需要包含大量线程的_uglobal _u u u u u u u u u u u u u u u u u u u u u u u u u u u u 我正在使用CUDA C。我怎么可能做到这一点呢?全局函数并不像您想象的那样包含大量线程。它只是一个运行在设备上的内核函数,通过传递指定线程模型的参数来调用。CUDA采用的模型是二维网格模型,然后是网格上每个块内部的三维线程模型
我正在使用CUDA C。我怎么可能做到这一点呢?全局函数并不像您想象的那样包含大量线程。它只是一个运行在设备上的内核函数,通过传递指定线程模型的参数来调用。CUDA采用的模型是二维网格模型,然后是网格上每个块内部的三维线程模型 对于您遇到的问题类型,除了在每个块中使用1D线程的1D网格之外,实际上不需要使用任何东西,因为字符串池与其他问题(例如矩阵乘法)一样拆分为2D是没有意义的 我将介绍一个简单的示例,例如字符串池中的100个字符串,您希望以并行方式而不是顺序地检查它们
//main
//Should cudamalloc and cudacopy to device up before this code
dim3 dimGrid(10, 1); // 1D grid with 10 blocks
dim3 dimBlocks(10, 1); //1D Blocks with 10 threads
fun<<<dimGrid, dimBlocks>>>(, Height)
//cudaMemCpy answerIdx back to integer on host
//kernel (Not positive on these types as my CUDA is very rusty
__global__ void fun(char *strings[], char *stringToMatch, int *answerIdx)
{
int idx = blockIdx.x * 10 + threadIdx.x;
//Obviously use whatever function you've been using for string comparison
//I'm just using == for example's sake
if(strings[idx] == stringToMatch)
{
*answerIdx = idx
}
}
//main
//cudamalloc和cudacopy是否应该在该代码之前启动设备
dim3 dimGrid(10,1);//具有10个块的一维网格
dim3 DIM块(10,1)//带10个螺纹的1D块
乐趣(,身高)
//cudaMemCpy将主机上的IDX应答回整数
//内核(在这些类型上不是积极的,因为我的CUDA非常生锈
__全局无效乐趣(char*strings[],char*stringToMatch,int*answerIdx)
{
int idx=blockIdx.x*10+threadIdx.x;
//显然,可以使用任何用于字符串比较的函数
//我只是用==作为例子
if(strings[idx]==stringToMatch)
{
*answerIdx=idx
}
}
这显然不是最有效的方法,也很可能不是传递参数和使用CUDA处理内存的确切方法,但我希望它能够解决工作负载分割的问题,并且“全局”函数可以在许多不同的内核上执行,所以你不能真的告诉它们全部停止通过将工作负载分配到设备上(当然是以合理的方式),您将获得更快的速度将给您带来巨大的性能改进。为了了解线程模型,我强烈建议您阅读Nvidia网站上有关CUDA的文档。这些文档将极大地帮助您,并教您设置网格和块以获得最佳性能的最佳方法。在CUDA(或Nvidia GPU)中没有任何方法一个线程中断所有正在运行的线程的执行。一旦发现结果,就不能立即退出内核,这在今天是不可能的
但是,在一个线程找到结果后,您可以让所有线程尽快退出
__global___ void kernel(volatile bool *found, ...)
{
while (!(*found) && workLeftToDo()) {
bool iFoundIt = do_some_work(...); // see notes below
if (iFoundIt) *found = true;
}
}
关于这一点的一些注释
volatile
。这很重要found
——它必须是指向false
的设备指针时,线程不会立即退出。它们只会在下次返回while循环顶部时退出
做一些工作
很重要。如果工作量太大(或变量太大),那么在找到结果后退出的延迟将很长(或变量太大)。如果工作量太小,那么线程将花费大部分时间检查找到的
,而不是做有用的工作dou_some_work
还负责分配任务(即计算/递增索引),具体操作方式取决于具体问题found==true
之后运行,这意味着它们将启动,然后立即退出。解决方案是只启动可以同时驻留的尽可能多的块(也称为“最大启动”),并相应地更新任务分配If
替换while
,并运行足够多的线程来覆盖任务数量。这样就不会出现死锁(但前一点的第一部分适用)workleftodo()
是特定于问题的,但是当没有剩余的工作要做时,它将返回false,以便在没有找到匹配项的情况下不会死锁__global___ void kernel(volatile bool *found, ...)
{
volatile __shared__ bool someoneFoundIt;
// initialize shared status
if (threadIdx.x == 0) someoneFoundIt = *found;
__syncthreads();
while(!someoneFoundIt && workLeftToDo()) {
bool iFoundIt = do_some_work(...);
// if I found it, tell everyone they can exit
if (iFoundIt) { someoneFoundIt = true; *found = true; }
// if someone in another block found it, tell
// everyone in my block they can exit
if (threadIdx.x == 0 && *found) someoneFoundIt = true;
__syncthreads();
}
}
这样,每个块一个线程轮询全局变量,只有找到匹配项的线程才会写入全局变量,因此全局内存流量最小化
旁白:_全局__函数是无效的,因为很难定义如何将1000个线程中的值返回到单个CPU线程中。用户在设备或零拷贝内存中设计一个适合其用途的返回数组很简单,但很难创建通用机制
免责声明:在浏览器中编写的代码,未经测试,未经验证。如果您感到冒险,停止内核执行的另一种方法是只执行
// (write result to memory here)
__threadfence();
asm("trap;");
如果找到答案
这不需要轮询内存,但不如Mark Harris建议的解决方案