我可以使用OpenACC来并行调用某些函数的大代码吗?

时间:2015-08-07 05:43:38

标签: c++ function parallel-processing nvidia openacc

我正在尝试将我的顺序C代码并行化并使用OpenACC(PGI编译器)卸载到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循环到parallized区域。如下。

#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()分解为小部分?

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

这取决于您的calltree的深度。正如杰夫拉金所说,acc routine可以帮到你,但它只能走到这一步。通常,需要内联这些例程来创建一个大内核。 GPU并不是真正构建来处理具有数千行代码的复杂内核 - 即使它工作也很难获得高性能。

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

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