将openmp编译成pthreads C代码

时间:2013-02-14 16:03:22

标签: pthreads openmp

据我所知,OpenMP实际上只是一组编译成pthread的宏。有没有办法在编译的其余部分之前看到pthread代码?我正在使用GCC进行编译。

3 个答案:

答案 0 :(得分:10)

首先,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包含并行循环结构的实现。

答案 1 :(得分:5)

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

虽然可以将OpenMP实现为纯pthreads代码的转换,但很少这样做。 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];
}

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,它们用于引导,然后完成并行区域的执行({{1}稍后删除前缀)。在__builtin_内部有一个fun._omp_fn.0循环,在for中实现(请注意,循环本身也会展开)。此外,所有共享变量都被放入一个特殊的结构中,并传递给并行区域的实现。 <bb 4>包含用于计算当前线程将在其上运行的迭代范围的代码。

嗯,不是一个C代码,但这可能是最接近GCC的东西。

答案 2 :(得分:-1)

我还没有用openmp测试它。但编译器选项-E应该在预处理后为您提供代码。