确定如何实现OpenMP原子指令

时间:2012-12-07 11:06:38

标签: c++ gcc openmp atomic

实现OpenMP标准的编译器可能(但没有义务)利用特殊的硬件指令在#pragma omp atomic指令原子之后进行某些内存更新,从而避免昂贵的锁定。根据{{​​3}},GCC实现了如下原子更新:

  

尽可能使用内置的原子更新。如果失败,则尝试进行比较和交换循环。如果这也失败了,则使用表达式周围的常规关键部分。

  1. 如何确定给定计算机和GCC版本中实际使用的三个中的哪一个?是否有一些GCC的详细选项,我可以设置找出,而不必分析我的程序或查看生成的字节码?

  2. 是否有一些文档列出了提供原子添加/增量/等指令的CPU /架构,允许我预测给定机器的结果?

  3. 我在各种不同的机器上使用GCC版本4.2到4.6。

2 个答案:

答案 0 :(得分:1)

您可以使用-fdump-tree-all选项查看中间树表示。给定该选项,GCC在几个中间步骤中写入一组文件,并且可以观察应用于树的连续变换。 .ompexp文件在这里特别有用,因为它在OpenMP表达式扩展到具体实现之后就包含了树。

例如,以下简单代码中parallel区域内的块:

int main (void)
{
    int i = 0;

    #pragma omp parallel
    {
       #pragma omp atomic
       i++;
    }

    return i;
}

由GCC 4.7.2在64位Linux上转换为:

;; Function main._omp_fn.0 (main._omp_fn.0, funcdef_no=1, decl_uid=1712, cgraph_uid=1)

main._omp_fn.0 (struct .omp_data_s.0 * .omp_data_i)
{
  int D.1726;
  int D.1725;
  int i [value-expr: *.omp_data_i->i];
  int * D.1723;
  int * D.1722;

<bb 2>:
  D.1722_2 = .omp_data_i_1(D)->i;
  D.1723_3 = &*D.1722_2;
  __atomic_fetch_add_4 (D.1723_3, 1, 0);
  return;

}

最终以:

结束
00000000004006af <main._omp_fn.0>:
  4006af:       55                      push   %rbp
  4006b0:       48 89 e5                mov    %rsp,%rbp
  4006b3:       48 89 7d f8             mov    %rdi,-0x8(%rbp)
  4006b7:       48 8b 45 f8             mov    -0x8(%rbp),%rax
  4006bb:       48 8b 00                mov    (%rax),%rax
  4006be:       f0 83 00 01             lock addl $0x1,(%rax)
  4006c2:       5d                      pop    %rbp
  4006c3:       c3                      retq

至于第二个问题,它可能还取决于GCC是如何建立的。

答案 1 :(得分:0)

GCC将定义宏

#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 1

如果相应的操作可用。

通常,人们总是希望在任何支持多处理器的架构上进行比较和交换(以CAS或LL / SC的形式)。

另外,在x86上有原子增量和减量。