将OpenMP编译为Pthreads C代码

7

我了解OpenMP实际上只是一组编译成pthread的宏。在编译的其余部分之前,有没有一种方法可以查看pthread代码?我正在使用GCC进行编译。

3个回答

13

首先,OpenMP并不是一组简单的宏。它可能被看作是一个简单的转换成类似于pthread的代码,但OpenMP需要更多的支持,包括运行时支持。

回到您的问题,至少在GCC中,您看不到pthreaded代码,因为GCC的OpenMP实现是在编译器后端(或中间层)完成的。转换是在IR(中间表示)级别进行的。因此,从程序员的角度来看,很难看出代码实际上是如何转换的。

然而,有一些参考资料。

(1)英特尔工程师提供了有关英特尔C / C ++编译器中实现OpenMP的概述:

http://www.drdobbs.com/parallel/how-do-openmp-compilers-work-part-1/226300148

http://www.drdobbs.com/parallel/how-do-openmp-compilers-work-part-2/226300277

(2)您可以查看GCC的OpenMP实现:

https://github.com/mirrors/gcc/tree/master/libgomp

请参见libgomp.h使用pthread,loop.c包含并行循环结构的实现。


6

OpenMP是一组编译器指令,而不是宏。在C/C++中,这些指令通过#pragma扩展机制实现,而在Fortran中,它们则以特殊格式的注释实现。这些指令指示编译器执行某些代码转换,以将串行代码转换为并行。

虽然可以将OpenMP实现为对纯pthread代码的转换,但这很少这样做。OpenMP机制的大部分通常内置于单独的运行时库中,该库作为编译器套件的一部分提供。对于GCC,这是libgomp。它提供了一组高级函数,用于轻松实现OpenMP结构。它也是编译器的内部组件,不适用于用户代码,即没有提供头文件。

使用GCC可以获取OpenMP转换后代码的伪代码表示。您必须提供-fdump-tree-all选项,这将导致编译器为每个编译单元产生大量的中间文件。最有趣的文件是filename.017t.ompexp(这来自于GCC 4.7.1,其他GCC版本可能有不同的编号,但扩展名仍然是.ompexp)。该文件包含了经过OpenMP结构降低和展开为其正确实现后的代码的中间表示。

考虑以下示例C代码,保存为fun.c:

void fun(double *data, int n)
{
   #pragma omp parallel for
   for (int i = 0; i < n; i++)
     data[i] += data[i]*data[i];
}
< p > fun.c.017t.ompexp 的内容是:

fun (double * data, int n)
{
  ...
  struct .omp_data_s.0 .omp_data_o.1;
  ...

<bb 2>:
  .omp_data_o.1.data = data;
  .omp_data_o.1.n = n;
  __builtin_GOMP_parallel_start (fun._omp_fn.0, &.omp_data_o.1, 0);
  fun._omp_fn.0 (&.omp_data_o.1);
  __builtin_GOMP_parallel_end ();
  data = .omp_data_o.1.data;
  n = .omp_data_o.1.n;
  return;
}

fun._omp_fn.0 (struct .omp_data_s.0 * .omp_data_i)
{
  int n [value-expr: .omp_data_i->n];
  double * data [value-expr: .omp_data_i->data];
  ...

<bb 3>:
  i = 0;
  D.1637 = .omp_data_i->n;
  D.1638 = __builtin_omp_get_num_threads ();
  D.1639 = __builtin_omp_get_thread_num ();
  ...

<bb 4>:
  ... this is the body of the loop ...
  i = i + 1;
  if (i < D.1644)
    goto <bb 4>;
  else
    goto <bb 5>;

<bb 5>:

<bb 6>:
  return;

  ...
}

我已经为了简洁省略了大部分输出。这不是精确的C代码,而是程序流程的类C表示形式。 <bb N>是所谓的基本块 - 语句的集合,在程序工作流中被视为单个块。首先可以看到的是并行区域被提取到一个单独的函数中。这是很常见的 - 大多数OpenMP实现都会做更多或更少相同的代码转换。还可以观察到编译器插入对libgomp函数的调用,例如GOMP_parallel_startGOMP_parallel_end,用于引导并完成并行区域的执行(稍后删除__builtin_前缀)。在fun._omp_fn.0内部有一个for循环,在<bb 4>中实现(请注意,循环本身也被展开)。此外,所有共享变量都被放入一个特殊的结构中,并传递给并行区域的实现。<bb 3>包含计算当前线程操作范围的代码。嗯,不完全是C代码,但这可能是从GCC获得的最接近的东西。

-1

我还没有使用openmp进行测试。但编译器选项-E应该可以在预处理后给你代码。


它不会。gcc -E只进行预处理,而不解释编译链中较晚出现的#pragma - Matthieu Moy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接