我知道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包含并行循环构造的实现.
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实现或多或少都进行相同的代码转换.还可以观察到编译器插入对libgomp像GOMP_parallel_start和等函数的调用,这些函数GOMP_parallel_end用于引导,然后完成并行区域的执行(__builtin_稍后将删除前缀).里面fun._omp_fn.0有一个for循环,实现在<bb 4>(注意循环本身也扩展).此外,所有共享变量都被放入一个特殊的结构中,并传递给并行区域的实现.<bb 3>包含计算当前线程将在其上运行的迭代范围的代码.
好吧,不是一个C代码,但这可能是最接近GCC的东西.