我在C中有一个这样的函数(在伪代码中,删除了不重要的部分):
int func(int s, int x, int *a, int *r) {
int i;
// do some stuff
for (i = 0; i < a_really_big_int; ++i) {
if (s)
r[i] = x ^ i;
else
r[i] = x ^ a[i];
// and maybe a couple other ways of computing r
// that are equally fast individually
}
// do some other stuff
}
字符串
这段代码被调用得太多了,以至于这个循环实际上是代码中的一个速度瓶颈。我想知道几件事:
1.由于开关s
在函数中是一个常量,好的编译器会优化循环,使分支不会一直拖慢速度吗?
1.如果没有,那么优化这段代码的好方法是什么?
**编辑:**这里是一个更新,有一个更完整的例子:
int func(int s,
int start, int stop, int stride,
double *x, double *b,
int *a, int *flips, int *signs, int i_max,
double *c)
{
int i,k,st;
for (k=start; k<stop; k += stride) {
b[k] = 0;
for (i=0;i<i_max;++i) {
/* this is the code in question */
if (s) st = k^flips[i];
else st = a[k]^flips[i];
/* done with code in question */
b[k] += x[st] * (__builtin_popcount(st & signs[i])%2 ? -c[i] : c[i]);
}
}
}
型
编辑2:
如果有人好奇的话,我最终重构了代码,并将整个内部for循环(与i_max
一起)提升到外部,使really_big_int
循环变得更简单,希望更容易向量化!(同时也避免了无数次的额外逻辑)
5条答案
按热度按时间oymdgrw71#
优化代码的一个显而易见的方法是将条件拉到循环外:
字符串
一个精明的编译器可能能够将其改为一次对多个元素进行r[]赋值。
lstz6jyr2#
微优化
通常他们不值得花时间-审查更大的问题更有效。
然而,微观优化,尝试各种方法,然后分析它们以找到最好的方法可以做出适度的改进。
除了@wallyk和@kabanus很好的答案,一些简单的编译器还受益于以0结尾的循环。
字符串
[edit第二次优化]
OP增加了一个更复杂的例子。其中一个问题是编译器不能假设
b
和其他内存指向的内存不重叠。这阻止了某些优化。假设它们实际上不重叠,在
b
上使用restrict
来允许优化。const
也有助于较弱的编译器,如果引用数据不重叠,则无法推断其他编译器上的.restrict
也可能受益。型
lskq00tm3#
你所有的命令都是快速的O(1)循环命令。
if
绝对是优化的,如果你所有的命令都是r[i]=somethingquick
的话,你的for+if也是优化的。问题可能归结为你的大int能有多小?一个快速的
int main
,从INT_MIN
到INT_MAX
求和成一个长变量,对我来说在Windows上的Ubuntu子系统上需要大约10秒。你的命令可能会乘以几个,很快就到了一分钟。底线是,如果你真的迭代了一吨,这可能是不可避免的。如果
r[i]
是独立计算的,这将是线程/多处理的经典用法。编辑:
我认为
%
已经被编译器优化了,但如果没有,请注意x & 1
对于奇/偶检查来说要快得多。ifsvaxew4#
假设是x86_64,您可以确保指针对齐到16个字节并使用intrinsics。如果它仅在AVX2系统上运行,则可以使用__mm256变体(类似于avx512*)
字符串
ffx8fchx5#
尽管
if
语句在任何像样的编译器上都会被优化掉(除非你要求编译器不要优化),但我会考虑把优化写进去(以防你编译时没有优化)。此外,尽管编译器可能会优化“绝对”
if
语句,但我会考虑手动优化它,使用任何可用的内置或using bitwise操作。即
字符串
这将取
popcount
的最后一位(1 ==奇数,0 ==偶数),将其乘以const(如果是奇数,则所有位为1,如果为真,则所有位为0),然后对c[I]
值进行XOR(与0-c[I]
或~(c[I])
相同)。这将避免在第二个
absolute
if语句未优化的情况下出现指令跳转。P.S.
我使用了一个8字节长的值,并通过将其转换为
int
来截断它的长度。这是因为我不知道int
在您的系统上可能有多长(在我的系统上是4字节,即0xFFFFFFFF
)。