【发布时间】:2012-11-13 09:34:33
【问题描述】:
对于一门名为“高性能计算”的课程,我需要优化以下代码片段:
int foobar(int a, int b, int N)
{
int i, j, k, x, y;
x = 0;
y = 0;
k = 256;
for (i = 0; i <= N; i++) {
for (j = i + 1; j <= N; j++) {
x = x + 4*(2*i+j)*(i+2*k);
if (i > j){
y = y + 8*(i-j);
}else{
y = y + 8*(j-i);
}
}
}
return x;
}
使用一些建议,我设法优化了代码(或者至少我是这么认为的),例如:
- 不断传播
- 代数化简
- 复制传播
- 通用子表达式消除
- 死代码消除
- 循环不变量去除
- 按位移位而不是乘法,因为它们更便宜。
这是我的代码:
int foobar(int a, int b, int N) {
int i, j, x, y, t;
x = 0;
y = 0;
for (i = 0; i <= N; i++) {
t = i + 512;
for (j = i + 1; j <= N; j++) {
x = x + ((i<<3) + (j<<2))*t;
}
}
return x;
}
根据我的导师的说法,一个优化良好的代码指令在汇编语言级别应该有更少或更低成本的指令。因此必须在比原始代码更短的时间内运行指令,即计算是用::
执行时间 = 指令数 * 每条指令的周期数
当我使用命令生成汇编代码时:gcc -o code_opt.s -S foobar.c,
虽然做了一些优化,但生成的代码行数比原代码多,运行时间也较短,但没有原代码多。我做错了什么?
不要粘贴汇编代码,因为两者都非常广泛。所以我在 main 中调用函数“foobar”,我正在使用 linux 中的 time 命令测量执行时间
int main () {
int a,b,N;
scanf ("%d %d %d",&a,&b,&N);
printf ("%d\n",foobar (a,b,N));
return 0;
}
【问题讨论】:
-
常数传播、代数简化、复制传播、公共子表达式消除、死代码消除、循环不变删除,以及使用按位移位而不是乘法,因为它们更便宜 - 有趣事实:这些正是现代优化编译器可以自己完成的“简单”优化,而且通常比程序员更好;出于这个原因,通常程序员关心更“高级”(例如算法)优化(或更微妙的东西 - 例如与缓存相关 - 通常需要分析)。
-
告诉编译器你想要所有优化的花里胡哨,因为it is smarter than you about this stuff?
-
运行
gcc和-O3应该有一些效果。虽然我不确定优化编译器在多大程度上违背了本练习的目的。 -
不幸的是,许多“HPC 编程”课程看起来像是直接从 1970 年代传来的。去过也做过。不幸的是,对于 OP,基于这个任务,包括这个任务。 :(
-
另外:只有我一个人,还是整个函数看起来可以被扁平化为一个单一的、无循环的表达式?
标签: c performance optimization compiler-optimization bit-shift