c - 在 C 中的内联函数中循环展开

标签 c optimization inline icc

我有一个关于 C 编译器优化以及何时/如何展开内联函数中的循环的问题。

我正在开发一个数字代码,它的功能类似于下面的示例。基本上,my_for()会计算某种模板并调用 op()my_type *arg 中的数据做些什么对于每个 i .在这里,my_func()包裹 my_for() , 创建参数并将函数指针发送到 my_op() ...谁的工作是修改 i每个 ( arg->n ) double 组 arg->dest[j] 的第 double .

typedef struct my_type {
  int const n;
  double *dest[16];
  double const *src[16];
} my_type;

static inline void my_for( void (*op)(my_type *,int), my_type *arg, int N ) {
  int i;

  for( i=0; i<N; ++i )
    op( arg, i );
}

static inline void my_op( my_type *arg, int i ) {
  int j;
  int const n = arg->n;

  for( j=0; j<n; ++j )
    arg->dest[j][i] += arg->src[j][i];
}

void my_func( double *dest0, double *dest1, double const *src0, double const *src1, int N ) {
  my_type Arg = {
    .n = 2,
    .dest = { dest0, dest1 },
    .src = { src0, src1 }
  };

  my_for( &my_op, &Arg, N );
}

这很好用。这些函数按照它们应该的方式进行内联,并且代码(几乎)与在单个函数中内联编写所有内容并展开 j 一样高效。循环,没有任何 my_type Arg .

这里是困惑:如果我设置 int const n = 2;而不是 int const n = arg->n;my_op() ,然后代码变得与展开的单功能版本一样快。所以,问题是:为什么?如果所有内容都被内联到 my_func() ,为什么编译器看不到我在字面上定义 Arg.n = 2 ?此外,当我明确地对 j 进行限制时,没有任何改进。循环 arg->n ,它应该看起来像更快的 int const n = 2;内联后。我也尝试使用 my_type const到处都向编译器发出这种常量性信号,但它只是不想展开循环。

在我的数字代码中,这相当于大约 15% 的性能损失。如果重要的话,n=4还有这些j循环出现在 op() 中的几个条件分支中.

我正在使用 icc (ICC) 12.1.5 20120612 进行编译。我尝试了 #pragma unroll .这是我的编译器选项(我错过了任何好的选项吗?):

-O3 -ipo -static -unroll-aggressive -fp-model precise -fp-model source -openmp -std=gnu99 -Wall -Wextra -Wno-unused -Winline -pedantic

谢谢!

最佳答案

很明显,编译器不够“聪明”,无法传播 n 常量并展开 for 循环。实际上它是安全的,因为 arg->n 可以在实例化和使用之间改变。

为了在各代编译器中获得一致的性能并最​​大限度地利用您的代码,请手动展开。

像我这样的人在这些情况下所做的(性能为王)依赖于宏。

宏将在调试版本中“内联”(有用)并且可以使用宏参数进行模板化(到一定程度)。作为编译时常量的宏参数保证保持这种方式。

关于c - 在 C 中的内联函数中循环展开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30802037/

相关文章:

c - 异步线程的问题(使用 pthread)。抱歉,但更具体的是 body

algorithm - 在战列舰游戏中确定船只是否被击中的最有效方法是什么?

c - 从循环中删除开关

c++ - 为什么 header 中有 C++ 内联函数?

css - 无法使用内联 CSS 和电子邮件签名删除超链接下划线

c - 带成员的整个结构的大小

c - 输出到另一个文件中

c - 带重定向输入和输出的 MadLib C 程序

c++ - 为什么在 XCode 中默认情况下循环展开?

html - Gmail 的时事通讯布局崩溃