如何在CUDA中多次执行内核时重用具有成员数据的函子,以提高内存使用率并减少复制时间?

如何在CUDA中多次执行内核时重用具有成员数据的函子,以提高内存使用率并减少复制时间?,cuda,Cuda,我正在将一个计算粒子对之间接触力的c++11程序翻译成cuda程序。所有粒子对彼此独立。我用函子来计算接触力。这个函子进行许多计算,并包含许多成员变量。因此,我尝试重用函子,而不是为每个粒子对创建一个新的函子 由于函子包含虚拟函数,因此函子克隆是在设备上而不是在主机上完成的 我正在考虑这样一个计划: 1) 克隆M函子 2) 开始计算M个粒子对 3) 粒子对M+1等待一个粒子对完成,然后重用其函子 然而,其他想法也非常受欢迎 我制作了一个非常简化的程序。在这个播放程序中,F变量不必是成员变量,但在

我正在将一个计算粒子对之间接触力的c++11程序翻译成cuda程序。所有粒子对彼此独立。我用函子来计算接触力。这个函子进行许多计算,并包含许多成员变量。因此,我尝试重用函子,而不是为每个粒子对创建一个新的函子

由于函子包含虚拟函数,因此函子克隆是在设备上而不是在主机上完成的

我正在考虑这样一个计划:

1) 克隆M函子

2) 开始计算M个粒子对

3) 粒子对M+1等待一个粒子对完成,然后重用其函子

然而,其他想法也非常受欢迎

我制作了一个非常简化的程序。在这个播放程序中,F变量不必是成员变量,但在实际程序中它必须是成员变量。在实际的程序中还有更多的成员数据和粒子对(N)。N通常是几百万

#包括
#定义TPB 4//实际值=128
#定义N 10//实际值=5000000
#定义M 5//复制时间和并行增益之间的权衡。
//实际价值大概在1000左右
#定义选项1
//选项1:使每个粒子对有一个函子=>工作,但会创建太多函子克隆
//选项2:只创建一个函子克隆=>不再有线程独立的成员变量
//选项3:制作M个可重用的克隆=>我的建议,但我不知道如何编程
结构FtorBase
{
__设备虚拟无效执行(长i)=0;
__设备\uuuuu虚拟无效显示()=0;
};
结构FtorA:公共FtorBase
{
__设备无效执行(长i)最终
{
F=a*i;
}
__设备\无效显示()最终版本
{
printf(“F=%F\n”,F);
}
双a;
双F;
};
模板
__全局无效克隆(FtorBase**d\U FtorBase,T ftor,长n\U FTORCENS)
{
const long i=threadIdx.x+blockIdx.x*blockDim.x;
如果(i>=n个力克隆){
返回;
}
d_ftorBase[i]=新的T(ftor);
}
结构类A
{
类型定义FtorA ftor\t;
FtorBase**getFtor()
{
FtorBase**d_cmFtorBase;
Cudamaloc(&d_cmFtorBase,N*sizeof(FtorBase*));
#如果选项==1
//选项1:为每个粒子对创建一个函子副本
printf(“使用选项1\n”);
克隆人(d_cmFtorBase,ftor,N);
#elif选项==2
//选项2:仅创建函子的一个副本
printf(“使用选项2\n”);
克隆因子(d_-cmFtorBase,ftor_1);
#elif选项==3
//选项3:创建M函子克隆
printf(“使用选项3\n”);
printf(“此选项未实现。我不知道如何执行。\n”);
克隆人(d_cmFtorBase,ftor_,M);
#恩迪夫
cudaDeviceSynchronize();
返回d_cmFtorBase;
}
ftor_t ftor_;
};
__全局无效CUDAExecutefor(FtorBase**FtorBase)
{
const long i=threadIdx.x+blockIdx.x*blockDim.x;
如果(i>=N){
返回;
}
#如果选项==1
//选项1:每个粒子创建一个函子
ftorBase[i]->执行(i);
ftorBase[i]->show();
#elif选项==2
//选项2:只创建了一个函子
ftorBase[0]->执行(i);
ftorBase[0]->show();
#elif选项==3
//选项3:重用功能器
//我不知道怎么做
#恩迪夫
}
int main()
{
ClassA*ClassA=新的ClassA();
classA->ftor.a=.1;
FtorBase**FtorBase=classA->getFtor();
cudaExecuteFtor(ftorBase);
cudaDeviceSynchronize();
返回0;
}
我正在检查F的输出,以查看成员变量在每次调用中是否独立。正如预期的那样,当为每个粒子对使用不同的函子(选项1)时,所有的F值都不同;当为整个程序仅使用一个函子时(选项2),所有的F值都相同

使用选项1
F=0.800000
F=0.900000
F=0.000000
F=0.100000
F=0.200000
F=0.300000
F=0.400000
F=0.500000
F=0.600000
F=0.700000
使用选项2
F=0.700000
F=0.700000
F=0.700000
F=0.700000
F=0.700000
F=0.700000
F=0.700000
F=0.700000
F=0.700000
F=0.700000
我想知道是否有一种方法可以在这个播放示例中获得所有不同的F值,而不需要N个副本(选项3)

注:我正在使用Ubuntu 18.04、nvcc 9.1和NVIDIA GeForce GTX 1060移动图形卡(cuda兼容6.1)

更新:

在我前面介绍的代码中,只有调试模式(与
-G
标志关联)存在问题,但在发布版本中没有。我猜编译器优化了
printf(“F=%F\n”,F)
printf(“F=%F\n”,a*i)这样,线程相关成员变量的问题,这个问题是关于什么的,就消失了


我更新了代码,因此编译器无法再在printf中进行替换。

我感到困惑。当我使用选项1或选项2运行您的代码时,我并没有像您使用
F=25.500000
所显示的那样获得统一的输出。您发布的代码是否实际生成了该输出?是我在CUDA 10.1上的测试用例,我看到在您的测试用例中,您将N定义为10。在本例中,您将获得
F=a*{0,1,…,N-1,N}
的所有结果
a=0.1
,因此
F={0.1,0.2,…,0.9,1.0}
。我将N定义为1000,因此在我的测试用例中
F={0.1,0.2,…,99.9100}
。使用选项1,我获得集合中的所有值。当使用选项2时,程序会随机打印其中一种可能性(
F=25.5
)。我只显示打印的1000个值中的10个。我将编辑我的问题以澄清这一点。您没有进行任何CUDA错误检查(我可以看到),我不知道您是否在windows或linux上运行。我建议任何时候你有困难与CUDA计划,也运行你的公关