我想调查我的并行GPU代码(使用OpenACC编写)的强大扩展。使用GPU进行强扩展的概念 - 至少据我所知 - 比使用CPU更加模糊。 The only resource I found regarding strong scaling on GPUs建议修复问题规模并增加GPU数量。但是,我相信在 GPU中有一些强大的扩展,例如扩展流式多处理器(在Nvidia Kepler架构中)。
OpenACC和CUDA的目的是明确地将硬件抽象给并行程序员,将其限制为他们的三级编程模型,包括帮派(线程块),工人(warps)和向量(SIMT线程组)。据我所知,CUDA模型旨在提供与其线程块相关的可伸缩性,这些线程块是独立的并映射到SMX。因此,我看到了两种方法来研究GPU的强缩放:
我的问题是:关于GPU上的强缩放正确/相关的思路是什么?如果是这样,有没有办法在OpenACC中执行上面的#2?
答案 0 :(得分:5)
GPU的规模很大,但不一定与您的思维方式相符,这就是为什么您只能找到有关强扩展到多个GPU的信息的原因。使用多核CPU,您可以轻松确定要运行多少CPU核心,这样您就可以修复工作并调整核心的线程程度。使用GPU,SM之间的分配将自动处理,完全不受您的控制。这是设计上的,因为这意味着编写良好的GPU代码可以强大地扩展以填充您抛出的任何GPU(或GPU)而无需任何程序员或用户干预。
你可以运行一些少数的OpenACC团伙/ CUDA线程块,并假设14个团伙将在14个不同的SM上运行,但是这有几个问题。首先,1个gang / threadblock不会使单个Kepler SMX饱和。无论有多少线程,无论占用多少,每个SM都需要更多的块才能充分利用硬件。其次,您并没有真正保证硬件会选择以这种方式安排块。最后,即使您在设备上找到每个SM的最佳块数或帮派数,它也不会扩展到其他设备。 GPU的技巧是尽可能多地暴露并行性,以便您可以从具有1 SM的设备扩展到具有100的设备(如果它们存在)或多个设备。
如果你想试验一下固定工作量的OpenACC帮派数量如何影响性能,你可以使用num_gangs
条款,如果你正在使用如果您正在使用parallel
,则gang
区域或kernels
子句。由于您试图强制执行循环的特定映射,因此您使用parallel
会更好,因为这是更具说明性的指令。你想做的事情如下:
#pragma acc parallel loop gang vector num_gangs(vary this number) vector_length(fix this number)
for(i=0; i<N; i++)
do something
这告诉编译器使用一些提供的向量长度对循环进行向量化,然后在OpenACC帮派之间对循环进行分区。我期待的是,当你添加帮派时,你会看到更好的表现直到SM数量的多倍,此时性能将变得大致平坦(当然有异常值)。正如我上面所说的那样,在你看到最佳性能的时刻修复帮派数量并不一定是最好的想法,除非这是你唯一感兴趣的设备。相反,要么让编译器决定如何分解循环,它允许编译器根据您建立的体系结构做出明智的决策,或者通过尽可能多地暴露团队,这为您提供了更大的并行性,可以扩展到更大的GPU或多个GPU,您可以; d有更多的可移植代码。
答案 1 :(得分:0)
对于占用完整的SMX,我建议使用共享内存作为限制占用资源。编写一个消耗所有32kB共享内存的内核,该块将占用整个SMX,因为SMX超出了另一个块的资源。您可以将块从1扩展到13(对于K20c),并且调度程序(希望)将每个块安排到不同的SMX。你可以先将每个块的therads首先扩展到192以使每个CUDA核心忙,然后你可以进一步让warp调度程序满意。 GPU通过延迟隐藏提供性能。因此,您必须从1个块继续占用SMX到N个块。您可以通过使用较少的共享内存来实现。再次扩展你的warp以涵盖延迟隐藏。
我从未接触过OpenACC,如果您真的希望完全控制您的实验代码,请使用CUDA而不是OpenACC。您无法在OpenACC编译器内部看到它与代码中使用的编译指示的作用。