将openmp编译成pthreads C代码

sup*_*ggs 6 pthreads openmp

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

min*_*ang 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包含并行循环构造的实现.


Hri*_*iev 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];
}
Run Code Online (Sandbox Code Playgroud)

内容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;

  ...
}
Run Code Online (Sandbox Code Playgroud)

为简洁起见,我省略了大部分输出.这不完全是C代码.它是程序流程的类似C的表示.<bb N>是所谓的基本块 - 语句集合,在程序的工作流程中被视为单个块.人们看到的第一件事是并行区域被提取到一个单独的函数中.这种情况并不少见 - 大多数OpenMP实现或多或少都进行相同的代码转换.还可以观察到编译器插入对libgompGOMP_parallel_start和等函数的调用,这些函数GOMP_parallel_end用于引导,然后完成并行区域的执行(__builtin_稍后将删除前缀).里面fun._omp_fn.0有一个for循环,实现在<bb 4>(注意循环本身也扩展).此外,所有共享变量都被放入一个特殊的结构中,并传递给并行区域的实现.<bb 3>包含计算当前线程将在其上运行的迭代范围的代码.

好吧,不是一个C代码,但这可能是最接近GCC的东西.