【发布时间】:2016-05-06 07:53:03
【问题描述】:
在尝试为我的代码(使用或不使用 128 位整数)对某些选项进行基准测试时,我观察到了一种我无法理解的行为。有人能解释一下吗?
#include <stdio.h>
#include <stdint.h>
#include <time.h>
int main(int a, char** b)
{
printf("Running tests\n");
clock_t start = clock();
unsigned __int128 t = 13;
for(unsigned long i = 0; i < (1UL<<30); i++)
t += 23442*t + 25;
if(t == 0) printf("0\n");
printf("u128, +25, took %fs\n", double(clock() - start)/CLOCKS_PER_SEC);
start = clock();
t = 13;
for(unsigned long i = 0; i < (1UL<<30); i++)
t += 23442*t;
if(t == 0) printf("0\n");
printf("u128, no+, took %fs\n", double(clock() - start)/CLOCKS_PER_SEC);
start = clock();
unsigned long u = 13;
for(unsigned long i = 0; i < (1UL<<30); i++)
u += 23442*u + 25;
if(u == 0) printf("0\n");
printf("u64 , +25, took %fs\n", double(clock() - start)/CLOCKS_PER_SEC);
start = clock();
u = 13;
for(unsigned long i = 0; i < (1UL<<30); i++)
u += 23442*u;
if(u == 0) printf("0\n");
printf("u64 , no+, took %fs\n", double(clock() - start)/CLOCKS_PER_SEC);
return 0;
}
(注意 printf 在这里,所以 gcc 不会优化 for 循环) 在我的系统上,这可靠地产生以下输出:
u128, +25, took 2.411922s
u128, no+, took 1.799805s
u64 , +25, took 1.797960s
u64 , no+, took 2.454104s
虽然 128 位整数行为是有道理的,但我看不到操作较少的 64 位循环如何执行显着 (30%) 慢。
这是一种已知的行为吗?在编写此类循环时尝试从这种优化中受益的一般规则是什么?
编辑:仅在使用 -O3 选项编译时才会观察到该行为。
gcc -lstdc++ -O3 -o a main.cpp
u128, +25, took 2.413949s
u128, no+, took 1.799469s
u64 , +25, took 1.798278s
u64 , no+, took 2.453414s
gcc -lstdc++ -O2 -o a main.cpp
u128, +25, took 2.415244s
u128, no+, took 1.800499s
u64 , +25, took 1.798699s
u64 , no+, took 1.348133s
【问题讨论】:
-
还提供您在编译示例时使用的编译器优化设置。
-
我得到的结果与@user6292850 与 GCC 5.3、默认、
-O和-O2相似。-O3虽然我确实看到了奇怪的行为。 -
常用答案——查看生成的汇编代码并尝试理解它。
-
对于“no+”,
clang在我的环境中快 10-20 倍。gcc尝试以疯狂的方式进行 SIMD 向量化,结果更糟。 -
使用 MWE 编辑了原始帖子。使用 O3 而不是 O2 编译时会观察到行为。显然,出于某种原因,O3 只是减慢了 64 位无加循环。
标签: c++ gcc optimization