0

我正在尝试使用 OpenACC(PGI 编译器)并行化我的顺序 C 代码并卸载到 NVIDIA GPU

我的代码是按顺序编写的。并且经常调用很长的函数,如下所示。

int main()
{
   // blah blah...
   for(i=0; i<10; i++)
   {
      for(j=0; j<20; j++)
      {
          big_function(a,b,c);
      }
   }
   // blah blah...
}

int big_function(a,b,c)
{
   small_function_1(a);
   small_function_2_with_data_dependencies(b);
}

那种情况下,big_function()可以并行化运行在GPU上吗?

我使用#pragma acc kernels将整个 for 循环声明为并行区域 。如下所示。

#pragma acc routine
int big_function(int a, int b, int c);
#pragma acc routine
int small_function_1(int a);
#pragma acc routine
int small_function_2_with_data_dependencies(int b);

int main()
{
   // blah blah...
   #pragma acc data ~~~~
   #pragma acc kernels
   for(i=0; i<10; i++)
   {
      for(j=0; j<20; j++)
      {
          big_function(a,b,c);
      }
   }
   // blah blah...
}

int big_function(a,b,c)
{
   small_function_1(a);
   small_function_2_with_data_dependencies(b);
}

但是编译后的文件需要很长时间才能完成。结果是不正确的。

我可以使用 OpenACC 来并行化使用许多函数调用的顺序代码吗?

或者我是否必须将big_function()分解为小部分?

4

2 回答 2

1

您需要使用acc routine指令在调用树中装饰每个函数,就像您在示例中所做的那样。如果您希望所有并行性都来自顶层的循环,那么您将希望将所有例程标记为顺序 ( seq)。只要你这样做了,编译器应该能够为 GPU 构建它。不过,您很可能会获得较差的性能,因为像这样的大型函数调用树往往包含大量状态,这会消耗 GPU 资源、共享内存和寄存器。您可能会发现,如果将并行性移到调用树下,它在 GPU 上的性能会好得多,但这可能会对 CPU 性能产生负面影响,并且可能会增加内存使用量,因为您必须保存以前的数据可用作线程状态。

如果您可以提供有关实际代码的更多信息,我可以尝试帮助您调试正确性问题。您应该检查编译器反馈 ( -Minfo) 并确保编译器正在执行您认为正在执行的操作。您可能会发现它被调用树绊倒了。您也可以尝试 PGI 论坛,因为它们通常对那里的帮助查询非常敏感。

于 2015-08-07T16:01:32.540 回答
0

这取决于你的调用树的深度。正如 jefflarkin 所说,acc routine可以帮助您,但仅此而已。通常,需要内联这些例程以创建一个大内核。GPU 并不是真正为处理具有数千行代码的复杂内核而构建的——即,即使它可以工作,也很难让它发挥作用。

在更复杂的情况下执行此操作的方法是在 i,j 域中私有化您的调用图(我假设这是某些模拟的物理参数化)。即,不是为一列或表面点计算所有内容,而是将更高维数据传递给子例程,因此您可以并行化 i,j 中的较小块。

旁注:对于 Fortran 90+,我为您构建了一个工具来进行并行化,但恐怕它不支持 C++。也许它会激发您的预处理解决方案。在我的情况下,我需要保持 CPU 性能,这可能会受到我上面提出的解决方案的影响,但这可能不适用于您的情况。

于 2015-08-08T18:28:50.727 回答