我有一个大内核,其中使用不同的技术演变初始状态。也就是说,我在内核中有一个循环,在这个循环中,某个谓词是在当前状态和该谓词的结果上进行评估的,会采取某种行动。
内核需要一些临时数据和共享内存,但由于它很大,它使用63个寄存器,占用率非常低。
我想在许多小内核中拆分内核,但是每个块都完全独立于其他内核,我(我想)我不能在主机代码上使用单个线程来启动多个小内核。
我不确定流是否适合这种工作,我从未使用它们,但由于我可以选择使用动态并行,我想如果这是实现这种工作的一个很好的选择。 从内核启动内核是否快速? 我是否需要在全局内存中复制数据以使其可用于子内核?
如果我将我的大内核拆分成许多小内核,并在第一个内核中放置一个主循环,在必要时调用所需的内核(这允许我在每个子内核中移动临时变量),将帮助我增加占用?
我知道这是一个通用的问题,但我不知道这项技术,我想它是否符合我的情况,或者流是否更好。
编辑: 为了提供其他一些细节,你可以想象我的内核有这种结构:
__global__ void kernel(int *sampleData, int *initialData) {
__shared__ int systemState[N];
__shared__ int someTemp[N * 3];
__shared__ int time;
int tid = ...;
systemState[tid] = initialData[tid];
while (time < TIME_END) {
bool c = calc_something(systemState);
if (c)
break;
someTemp[tid] = do_something(systemState);
c = do_check(someTemp);
if (__syncthreads_or(c))
break;
sample(sampleData, systemState);
if (__syncthreads_and(...)) {
do_something(systemState);
sync();
time += some_increment(systemState);
}
else {
calcNewTemp(someTemp, systemState);
sync();
do_something_else(someTemp, systemState);
time += some_other_increment(someTemp, systemState);
}
}
do_some_stats();
}
这是为了告诉你有一个主循环,有一些临时数据用于某个地方,而不是在其他地方,有共享数据,同步点等。
线程用于计算矢量数据,而理想情况下,每个块中有一个单个循环(当然,这不是真的,但逻辑上是这样)......每个块有一个“大流量”。
现在,我不确定如何在这种情况下使用流......“大循环”在哪里?在主机上我猜...但是如何从单个循环中协调所有块?这让我最可疑。我可以使用来自不同主机线程的流(每个块一个线程)吗?
我对动态并行性不太怀疑,因为我可以很容易地保持大循环运行,但我不确定我是否可以在这里获得优势。
答案 0 :(得分:2)
我受益于动态并行性来解决形式的插值问题:
int i = threadIdx.x + blockDim.x * blockIdx.x;
for(int m=0; m<(2*K+1); m++) {
PP1 = calculate_PP1(i,m);
phi_cap1 = calculate_phi_cap1(i,m);
for(int n=0; n<(2*K+1); n++) {
PP2 = calculate_PP2(i,m);
phi_cap2 = calculate_phi_cap2(i,n);
atomicAdd(&result[PP1][PP2],data[i]*phi_cap1*phi_cap2); } } }
其中K=6
。在这个插值问题中,每个加数的计算独立于其他加数,因此我将它们拆分为(2K+1)x(2K+1)
内核。
从我的(可能不完整的)经验来看,如果你有一些独立的迭代,动态并行将会有所帮助。对于大量的迭代,也许你最终可能会多次调用子内核,所以你应该检查内核启动的开销是否是限制因素。