【发布时间】:2018-12-04 21:26:22
【问题描述】:
在询问this question 之后,我很困惑,决定为 C 编译器程序构建类似的测试。这是我的代码:
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <stdlib.h>
#define SUMMATIONS 20000000
int main() {
static int speedups[2101] = { 0 };
srand((unsigned)time(NULL));
while (1) {
unsigned int t1, t2, t3, t4;
signed int tmp, i, n1, n2;
// Slow version
t1 = clock();
for (n1 = rand() % 50, i = 0; i < SUMMATIONS; i++) {
n1 += 3 * i * i;
}
t2 = clock();
// Optimized version
t3 = clock();
for (n2 = rand() % 50, i = 0; i < SUMMATIONS; i++) {
n2 += i * i;
}
n2 *= 3;
t4 = clock();
// gather speedup statistics
if ((int)(t2 - t1) != 0) {
tmp = (int)(100.0f * ((float)(t2 - t1) - (float)(t4 - t3)) / (float)(t2 - t1));
tmp = tmp < -100 ? -100 : tmp > 100 ? 100 : tmp;
tmp = (tmp >= 0 ? 1000 : 2000) + abs(tmp);
speedups[tmp]++;
}
// output statistics
for (i = 0; i < 2101; i++) {
if (speedups[i] != 0) {
char s = i / 1000 == 1 ? '+' : i / 1000 == 2 ? '-' : '?';
printf("%c%i : %i\n", s, i % 1000, speedups[i]);
}
}
printf("error %i ******************\n", abs(n2-n1));
}
return 0;
}
在 GCC 下编译,带有选项 -O3 -march=native
编辑
测试代码已更改,因此只能在运行时(而不是在编译时)知道错误值,因此 GCC 优化器无法删除 for 循环的代码。
结果
运行时 - 将 CPU 命中计数器重新计算为特定加速值并输出计数器表。如果我们绘制 CPU hits Vs Speedup 值,我们将 得到这样的图表:
所以 GCC 制作的程序平均产生了 ~ 20% 的加速。
问题
我们应该期望 CPU 加速吗? (根据GCC编译程序的预测)
【问题讨论】:
-
目前还不清楚所有这些代码的作用,以及它与您引用的输出的关系。你能补充一些解释吗?
-
有趣的事实:
gcc -O3愉快地生成了以下序列(由于此评论中缺少格式而进行了少量编辑)作为翻译的一部分:call clock; movq %rax, %r14; call clock; movq %rax, %rbx; call clock; movq %rax, %r13; call clock我邀请您思考时间的意义有多大有。 -
测量慢的和优化的代码块的执行速度。计算“快速”块的相对加速并增加数组中该加速值的计数器,以查看有多少处理器达到该加速值。以“百分比加速:命中量”格式打印数据
-
如果您使用godbolt.org 分析生成的汇编代码,您会发现带有给定命令参数的clang 能够优化掉完整的循环(即使它们为空)。修改您的代码以禁用优化器以丢弃计算结果。
-
@AgniusVasiliauskas 不,我的建议是对循环中聚合的变量做一些事情。在您的代码中,这些变量不再使用。因此,优化器很乐意将它们扔掉。因此,“禁用”我的意思是“阻止”而不是关闭。
标签: c optimization cpu